embed public keys inside ipns records, use for validation
License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com>
Jeromy committed
Jun 5, 2018 at 02:01 UTC
bc129ac5c786d55c2e1725c2195dd50cbfdfe87a
4 files changed
+77
-13
namesys/pb/namesys.pb.go
+24
-9
@@ -1,12 +1,12 @@
1
// Code generated by protoc-gen-gogo.
2
-// source: namesys.proto
2
+// source: namesys/pb/namesys.proto
3
// DO NOT EDIT!
4
5
/*
6
Package namesys_pb is a generated protocol buffer package.
7
8
It is generated from these files:
9
- namesys.proto
9
+ namesys/pb/namesys.proto
10
11
It has these top-level messages:
12
IpnsEntry
@@ -14,10 +14,12 @@ It has these top-level messages:
14
package namesys_pb
15
16
import proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
17
+import fmt "fmt"
18
import math "math"
19
20
// Reference imports to suppress errors if they are not otherwise used.
21
var _ = proto.Marshal
22
+var _ = fmt.Errorf
23
var _ = math.Inf
24
25
type IpnsEntry_ValidityType int32
@@ -52,13 +54,18 @@ func (x *IpnsEntry_ValidityType) UnmarshalJSON(data []byte) error {
54
}
55
56
type IpnsEntry struct {
55
- Value []byte `protobuf:"bytes,1,req,name=value" json:"value,omitempty"`
56
- Signature []byte `protobuf:"bytes,2,req,name=signature" json:"signature,omitempty"`
57
- ValidityType *IpnsEntry_ValidityType `protobuf:"varint,3,opt,name=validityType,enum=namesys.pb.IpnsEntry_ValidityType" json:"validityType,omitempty"`
58
- Validity []byte `protobuf:"bytes,4,opt,name=validity" json:"validity,omitempty"`
59
- Sequence *uint64 `protobuf:"varint,5,opt,name=sequence" json:"sequence,omitempty"`
60
- Ttl *uint64 `protobuf:"varint,6,opt,name=ttl" json:"ttl,omitempty"`
61
- XXX_unrecognized []byte `json:"-"`
57
+ Value []byte `protobuf:"bytes,1,req,name=value" json:"value,omitempty"`
58
+ Signature []byte `protobuf:"bytes,2,req,name=signature" json:"signature,omitempty"`
59
+ ValidityType *IpnsEntry_ValidityType `protobuf:"varint,3,opt,name=validityType,enum=namesys.pb.IpnsEntry_ValidityType" json:"validityType,omitempty"`
60
+ Validity []byte `protobuf:"bytes,4,opt,name=validity" json:"validity,omitempty"`
61
+ Sequence *uint64 `protobuf:"varint,5,opt,name=sequence" json:"sequence,omitempty"`
62
+ Ttl *uint64 `protobuf:"varint,6,opt,name=ttl" json:"ttl,omitempty"`
63
+ // in order for nodes to properly validate a record upon receipt, they need the public
64
+ // key associated with it. For old RSA keys, its easiest if we just send this as part of
65
+ // the record itself. For newer ed25519 keys, the public key can be embedded in the
66
+ // peerID, making this field unnecessary.
67
+ PubKey []byte `protobuf:"bytes,7,opt,name=pubKey" json:"pubKey,omitempty"`
68
+ XXX_unrecognized []byte `json:"-"`
69
}
70
71
func (m *IpnsEntry) Reset() { *m = IpnsEntry{} }
@@ -107,6 +114,14 @@ func (m *IpnsEntry) GetTtl() uint64 {
114
return 0
115
}
116
117
+func (m *IpnsEntry) GetPubKey() []byte {
118
+ if m != nil {
119
+ return m.PubKey
120
+ }
121
+ return nil
122
+}
123
+
124
func init() {
125
+ proto.RegisterType((*IpnsEntry)(nil), "namesys.pb.IpnsEntry")
126
proto.RegisterEnum("namesys.pb.IpnsEntry_ValidityType", IpnsEntry_ValidityType_name, IpnsEntry_ValidityType_value)
127
}
namesys/pb/namesys.proto
+6
@@ -14,4 +14,10 @@ message IpnsEntry {
14
optional uint64 sequence = 5;
15
16
optional uint64 ttl = 6;
17
+
18
+ // in order for nodes to properly validate a record upon receipt, they need the public
19
+ // key associated with it. For old RSA keys, its easiest if we just send this as part of
20
+ // the record itself. For newer ed25519 keys, the public key can be embedded in the
21
+ // peerID, making this field unnecessary.
22
+ optional bytes pubKey = 7;
23
}
namesys/publisher.go
+13
@@ -240,6 +240,17 @@ func PutRecordToRouting(ctx context.Context, r routing.ValueStore, k ci.PubKey,
240
return err
241
}
242
243
+ // if we can't derive the public key from the peerID, embed the entire pubkey in
244
+ // the record to make the verifiers job easier
245
+ if extractedPublicKey == nil {
246
+ pubkeyBytes, err := k.Bytes()
247
+ if err != nil {
248
+ return err
249
+ }
250
+
251
+ entry.PubKey = pubkeyBytes
252
+ }
253
+
254
namekey, ipnskey := IpnsKeysForID(id)
255
256
go func() {
@@ -247,6 +258,8 @@ func PutRecordToRouting(ctx context.Context, r routing.ValueStore, k ci.PubKey,
258
}()
259
260
// Publish the public key if a public key cannot be extracted from the ID
261
+ // TODO: once v0.4.16 is widespread enough, we can stop doing this
262
+ // and at that point we can even deprecate the /pk/ namespace in the dht
263
if extractedPublicKey == nil {
264
go func() {
265
errs <- PublishPublicKey(ctx, r, namekey, k)
namesys/validator.go
+34
-4
@@ -3,11 +3,13 @@ package namesys
3
import (
4
"bytes"
5
"errors"
6
+ "fmt"
7
"time"
8
9
pb "github.com/ipfs/go-ipfs/namesys/pb"
10
peer "gx/ipfs/QmcJukH2sAFjY3HdBKq35WDzWoL3UUu2gt9wdfqZTUyM74/go-libp2p-peer"
11
pstore "gx/ipfs/QmdeiKhUy1TVGBaKxt7y1QmBDLBdisSrLJ1x58Eoj4PXUh/go-libp2p-peerstore"
12
+ ic "gx/ipfs/Qme1knMqwt1hKZbc1BmQFmnm9f36nyQGwXxPGVpVJ9rMK5/go-libp2p-crypto"
13
14
u "gx/ipfs/QmNiJuT8Ja3hMVpBHXv3Q6dwmperaQ6JjLtpMQgMCD7xvx/go-ipfs-util"
15
record "gx/ipfs/QmTUyK82BVPA6LmSzEJpfEunk9uBaQzWtMsNP917tVj4sT/go-libp2p-record"
@@ -65,10 +67,10 @@ func (v IpnsValidator) Validate(key string, value []byte) error {
67
log.Debugf("failed to parse ipns record key %s into peer ID", pidString)
68
return ErrKeyFormat
69
}
68
- pubk := v.KeyBook.PubKey(pid)
69
- if pubk == nil {
70
- log.Debugf("public key with hash %s not found in peer store", pid)
71
- return ErrPublicKeyNotFound
70
+
71
+ pubk, err := v.getPublicKey(pid, entry)
72
+ if err != nil {
73
+ return fmt.Errorf("getting public key failed: %s", err)
74
}
75
76
// Check the ipns record signature with the public key
@@ -94,6 +96,34 @@ func (v IpnsValidator) Validate(key string, value []byte) error {
96
return nil
97
}
98
99
+func (v IpnsValidator) getPublicKey(pid peer.ID, entry *pb.IpnsEntry) (ic.PubKey, error) {
100
+ if entry.PubKey != nil {
101
+ pk, err := ic.UnmarshalPublicKey(entry.PubKey)
102
+ if err != nil {
103
+ // TODO: i think this counts as a 'malformed record' and should be discarded
104
+ log.Debugf("public key in ipns record failed to parse: ", err)
105
+ return nil, err
106
+ }
107
+ expPid, err := peer.IDFromPublicKey(pk)
108
+ if err != nil {
109
+ return nil, fmt.Errorf("could not regenerate peerID from pubkey: %s", err)
110
+ }
111
+
112
+ if pid != expPid {
113
+ return nil, fmt.Errorf("pubkey in record did not match expected pubkey")
114
+ }
115
+
116
+ return pk, nil
117
+ }
118
+
119
+ pubk := v.KeyBook.PubKey(pid)
120
+ if pubk == nil {
121
+ log.Debugf("public key with hash %s not found in peer store", pid)
122
+ return nil, ErrPublicKeyNotFound
123
+ }
124
+ return pubk, nil
125
+}
126
+
127
// IpnsSelectorFunc selects the best record by checking which has the highest
128
// sequence number and latest EOL
129
func (v IpnsValidator) Select(k string, vals [][]byte) (int, error) {