change handshake to use pub/priv keys for verification
Jeromy committed
Sep 1, 2014 at 19:04 UTC
48865db1eae429ea939a40523e979157c2163644
4 files changed
+134
-2
identify/identify.go
+79
-2
@@ -3,6 +3,7 @@
3
package identify
4
5
import (
6
+ "bytes"
7
"crypto"
8
"crypto/rand"
9
"crypto/rsa"
@@ -10,6 +11,7 @@ import (
11
"errors"
12
"io/ioutil"
13
14
+ proto "code.google.com/p/goprotobuf/proto"
15
peer "github.com/jbenet/go-ipfs/peer"
16
u "github.com/jbenet/go-ipfs/util"
17
)
@@ -17,15 +19,90 @@ import (
19
// Perform initial communication with this peer to share node ID's and
20
// initiate communication
21
func Handshake(self, remote *peer.Peer, in, out chan []byte) error {
20
- // TODO: make this more... secure.
21
- out <- self.ID
22
+ encoded, err := buildHandshake(self)
23
+ if err != nil {
24
+ return err
25
+ }
26
+ out <- encoded
27
resp := <-in
28
+
29
+ pbresp := new(Identify)
30
+ err = proto.Unmarshal(resp, pbresp)
31
+ if err != nil {
32
+ return err
33
+ }
34
+
35
+ // Verify that the given ID matches their given public key
36
+ if verifyErr := verifyID(peer.ID(pbresp.GetId()), pbresp.GetPubkey()); verifyErr != nil {
37
+ return verifyErr
38
+ }
39
+
40
+ pubkey, err := x509.ParsePKIXPublicKey(pbresp.GetPubkey())
41
+ if err != nil {
42
+ return err
43
+ }
44
+
45
+ // Challenge peer to ensure they own the given pubkey
46
+ secret := make([]byte, 32)
47
+ rand.Read(secret)
48
+ encrypted, err := rsa.EncryptPKCS1v15(rand.Reader, pubkey.(*rsa.PublicKey), secret)
49
+ if err != nil {
50
+ //... this is odd
51
+ return err
52
+ }
53
+
54
+ out <- encrypted
55
+ challenge := <-in
56
+
57
+ plain, err := rsa.DecryptPKCS1v15(rand.Reader, self.PrivKey.(*rsa.PrivateKey), challenge)
58
+ if err != nil {
59
+ return err
60
+ }
61
+
62
+ out <- plain
63
+ chalResp := <-in
64
+ if !bytes.Equal(chalResp, secret) {
65
+ return errors.New("Recieved incorrect challenge response!")
66
+ }
67
+
68
remote.ID = peer.ID(resp)
69
+ remote.PubKey = pubkey
70
u.DOut("[%s] identify: Got node id: %s\n", self.ID.Pretty(), remote.ID.Pretty())
71
72
return nil
73
}
74
75
+func buildHandshake(self *peer.Peer) ([]byte, error) {
76
+ pkb, err := x509.MarshalPKIXPublicKey(self.PubKey)
77
+ if err != nil {
78
+ return nil, err
79
+ }
80
+
81
+ pmes := new(Identify)
82
+ pmes.Id = []byte(self.ID)
83
+ pmes.Pubkey = pkb
84
+
85
+ encoded, err := proto.Marshal(pmes)
86
+ if err != nil {
87
+ return nil, err
88
+ }
89
+
90
+ return encoded, nil
91
+}
92
+
93
+func verifyID(id peer.ID, pubkey []byte) error {
94
+ hash, err := u.Hash(pubkey)
95
+ if err != nil {
96
+ return err
97
+ }
98
+
99
+ if id.Equal(peer.ID(hash)) {
100
+ return nil
101
+ }
102
+
103
+ return errors.New("ID did not match public key!")
104
+}
105
+
106
type KeyPair struct {
107
Pub crypto.PublicKey
108
Priv crypto.PrivateKey
identify/message.pb.go
new
+48
@@ -0,0 +1,48 @@
1
+// Code generated by protoc-gen-go.
2
+// source: message.proto
3
+// DO NOT EDIT!
4
+
5
+/*
6
+Package identify is a generated protocol buffer package.
7
+
8
+It is generated from these files:
9
+ message.proto
10
+
11
+It has these top-level messages:
12
+ Identify
13
+*/
14
+package identify
15
+
16
+import proto "code.google.com/p/goprotobuf/proto"
17
+import math "math"
18
+
19
+// Reference imports to suppress errors if they are not otherwise used.
20
+var _ = proto.Marshal
21
+var _ = math.Inf
22
+
23
+type Identify struct {
24
+ Id []byte `protobuf:"bytes,1,req,name=id" json:"id,omitempty"`
25
+ Pubkey []byte `protobuf:"bytes,2,req,name=pubkey" json:"pubkey,omitempty"`
26
+ XXX_unrecognized []byte `json:"-"`
27
+}
28
+
29
+func (m *Identify) Reset() { *m = Identify{} }
30
+func (m *Identify) String() string { return proto.CompactTextString(m) }
31
+func (*Identify) ProtoMessage() {}
32
+
33
+func (m *Identify) GetId() []byte {
34
+ if m != nil {
35
+ return m.Id
36
+ }
37
+ return nil
38
+}
39
+
40
+func (m *Identify) GetPubkey() []byte {
41
+ if m != nil {
42
+ return m.Pubkey
43
+ }
44
+ return nil
45
+}
46
+
47
+func init() {
48
+}
identify/message.proto
+3
@@ -1,3 +1,6 @@
1
+package identify;
2
+
3
message Identify {
4
required bytes id = 1;
5
+ required bytes pubkey = 2;
6
}
peer/peer.go
+4
@@ -1,6 +1,7 @@
1
package peer
2
3
import (
4
+ "crypto"
5
"sync"
6
"time"
7
@@ -33,6 +34,9 @@ type Peer struct {
34
ID ID
35
Addresses []*ma.Multiaddr
36
37
+ PubKey crypto.PublicKey
38
+ PrivKey crypto.PrivateKey
39
+
40
latency time.Duration
41
latenLock sync.RWMutex
42
}