@cryptotaxi247 / kubo / commits / bc129ac5c

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) {