make signing dht put records optional
Jeromy committed
Feb 23, 2015 at 00:25 UTC
049b5ad94510f735a4cf0a73d0582c37e668f190
15 files changed
+95
-65
core/commands/dht.go
+1
-1
@@ -508,7 +508,7 @@ PutValue will store the given key value pair in the dht.
508
509
go func() {
510
defer close(events)
511
- err := dht.PutValue(ctx, key, []byte(data))
511
+ err := dht.PutValue(ctx, key, []byte(data), true)
512
if err != nil {
513
notif.PublishQueryEvent(ctx, ¬if.QueryEvent{
514
Type: notif.QueryError,
namesys/publisher.go
+2
-2
@@ -62,7 +62,7 @@ func (p *ipnsPublisher) Publish(ctx context.Context, k ci.PrivKey, value u.Key)
62
log.Debugf("Storing pubkey at: %s", namekey)
63
// Store associated public key
64
timectx, _ := context.WithDeadline(ctx, time.Now().Add(time.Second*10))
65
- err = p.routing.PutValue(timectx, namekey, pkbytes)
65
+ err = p.routing.PutValue(timectx, namekey, pkbytes, false)
66
if err != nil {
67
return err
68
}
@@ -72,7 +72,7 @@ func (p *ipnsPublisher) Publish(ctx context.Context, k ci.PrivKey, value u.Key)
72
log.Debugf("Storing ipns entry at: %s", ipnskey)
73
// Store ipns entry at "/ipns/"+b58(h(pubkey))
74
timectx, _ = context.WithDeadline(ctx, time.Now().Add(time.Second*10))
75
- err = p.routing.PutValue(timectx, ipnskey, data)
75
+ err = p.routing.PutValue(timectx, ipnskey, data, true)
76
if err != nil {
77
return err
78
}
routing/dht/dht.go
+1
-10
@@ -254,16 +254,7 @@ func (dht *IpfsDHT) getOwnPrivateKey() (ci.PrivKey, error) {
254
}
255
256
// putLocal stores the key value pair in the datastore
257
-func (dht *IpfsDHT) putLocal(key u.Key, value []byte) error {
258
- sk, err := dht.getOwnPrivateKey()
259
- if err != nil {
260
- return err
261
- }
262
-
263
- rec, err := record.MakePutRecord(sk, key, value)
264
- if err != nil {
265
- return err
266
- }
257
+func (dht *IpfsDHT) putLocal(key u.Key, rec *pb.Record) error {
258
data, err := proto.Marshal(rec)
259
if err != nil {
260
return err
routing/dht/dht_test.go
+26
-6
@@ -17,6 +17,7 @@ import (
17
peer "github.com/jbenet/go-ipfs/p2p/peer"
18
netutil "github.com/jbenet/go-ipfs/p2p/test/util"
19
routing "github.com/jbenet/go-ipfs/routing"
20
+ record "github.com/jbenet/go-ipfs/routing/record"
21
u "github.com/jbenet/go-ipfs/util"
22
23
ci "github.com/jbenet/go-ipfs/util/testutil/ci"
@@ -147,7 +148,7 @@ func TestValueGetSet(t *testing.T) {
148
connect(t, ctx, dhtA, dhtB)
149
150
ctxT, _ := context.WithTimeout(ctx, time.Second)
150
- dhtA.PutValue(ctxT, "/v/hello", []byte("world"))
151
+ dhtA.PutValue(ctxT, "/v/hello", []byte("world"), false)
152
153
ctxT, _ = context.WithTimeout(ctx, time.Second*2)
154
val, err := dhtA.GetValue(ctxT, "/v/hello")
@@ -188,7 +189,13 @@ func TestProvides(t *testing.T) {
189
190
for k, v := range testCaseValues {
191
log.Debugf("adding local values for %s = %s", k, v)
191
- err := dhts[3].putLocal(k, v)
192
+ sk := dhts[3].peerstore.PrivKey(dhts[3].self)
193
+ rec, err := record.MakePutRecord(sk, k, v, false)
194
+ if err != nil {
195
+ t.Fatal(err)
196
+ }
197
+
198
+ err = dhts[3].putLocal(k, rec)
199
if err != nil {
200
t.Fatal(err)
201
}
@@ -456,7 +463,12 @@ func TestProvidesMany(t *testing.T) {
463
providers[k] = dht.self
464
465
t.Logf("adding local values for %s = %s (on %s)", k, v, dht.self)
459
- err := dht.putLocal(k, v)
466
+ rec, err := record.MakePutRecord(nil, k, v, false)
467
+ if err != nil {
468
+ t.Fatal(err)
469
+ }
470
+
471
+ err = dht.putLocal(k, rec)
472
if err != nil {
473
t.Fatal(err)
474
}
@@ -543,13 +555,21 @@ func TestProvidesAsync(t *testing.T) {
555
connect(t, ctx, dhts[1], dhts[2])
556
connect(t, ctx, dhts[1], dhts[3])
557
546
- err := dhts[3].putLocal(u.Key("hello"), []byte("world"))
558
+ k := u.Key("hello")
559
+ val := []byte("world")
560
+ sk := dhts[3].peerstore.PrivKey(dhts[3].self)
561
+ rec, err := record.MakePutRecord(sk, k, val, false)
562
+ if err != nil {
563
+ t.Fatal(err)
564
+ }
565
+
566
+ err = dhts[3].putLocal(k, rec)
567
if err != nil {
568
t.Fatal(err)
569
}
570
551
- bits, err := dhts[3].getLocal(u.Key("hello"))
552
- if err != nil && bytes.Equal(bits, []byte("world")) {
571
+ bits, err := dhts[3].getLocal(k)
572
+ if err != nil && bytes.Equal(bits, val) {
573
t.Fatal(err)
574
}
575
routing/dht/ext_test.go
+1
-1
@@ -111,7 +111,7 @@ func TestGetFailures(t *testing.T) {
111
t.Fatal(err)
112
}
113
114
- rec, err := record.MakePutRecord(sk, u.Key(str), []byte("blah"))
114
+ rec, err := record.MakePutRecord(sk, u.Key(str), []byte("blah"), true)
115
if err != nil {
116
t.Fatal(err)
117
}
routing/dht/records.go
+26
-12
@@ -7,6 +7,7 @@ import (
7
ci "github.com/jbenet/go-ipfs/p2p/crypto"
8
peer "github.com/jbenet/go-ipfs/p2p/peer"
9
pb "github.com/jbenet/go-ipfs/routing/dht/pb"
10
+ record "github.com/jbenet/go-ipfs/routing/record"
11
u "github.com/jbenet/go-ipfs/util"
12
ctxutil "github.com/jbenet/go-ipfs/util/ctx"
13
)
@@ -99,14 +100,20 @@ func (dht *IpfsDHT) getPublicKeyFromNode(ctx context.Context, p peer.ID) (ci.Pub
100
// key, we fail. we do not search the dht.
101
func (dht *IpfsDHT) verifyRecordLocally(r *pb.Record) error {
102
102
- // First, validate the signature
103
- p := peer.ID(r.GetAuthor())
104
- pk := dht.peerstore.PubKey(p)
105
- if pk == nil {
106
- return fmt.Errorf("do not have public key for %s", p)
103
+ if len(r.Signature) > 0 {
104
+ // First, validate the signature
105
+ p := peer.ID(r.GetAuthor())
106
+ pk := dht.peerstore.PubKey(p)
107
+ if pk == nil {
108
+ return fmt.Errorf("do not have public key for %s", p)
109
+ }
110
+
111
+ if err := record.CheckRecordSig(r, pk); err != nil {
112
+ return err
113
+ }
114
}
115
109
- return dht.Validator.VerifyRecord(r, pk)
116
+ return dht.Validator.VerifyRecord(r)
117
}
118
119
// verifyRecordOnline verifies a record, searching the DHT for the public key
@@ -116,12 +123,19 @@ func (dht *IpfsDHT) verifyRecordLocally(r *pb.Record) error {
123
// massive amplification attack on the dht. Use with care.
124
func (dht *IpfsDHT) verifyRecordOnline(ctx context.Context, r *pb.Record) error {
125
119
- // get the public key, search for it if necessary.
120
- p := peer.ID(r.GetAuthor())
121
- pk, err := dht.getPublicKeyOnline(ctx, p)
122
- if err != nil {
123
- return err
126
+ if len(r.Signature) > 0 {
127
+ // get the public key, search for it if necessary.
128
+ p := peer.ID(r.GetAuthor())
129
+ pk, err := dht.getPublicKeyOnline(ctx, p)
130
+ if err != nil {
131
+ return err
132
+ }
133
+
134
+ err = record.CheckRecordSig(r, pk)
135
+ if err != nil {
136
+ return err
137
+ }
138
}
139
126
- return dht.Validator.VerifyRecord(r, pk)
140
+ return dht.Validator.VerifyRecord(r)
141
}
routing/dht/routing.go
+5
-5
@@ -29,21 +29,21 @@ var asyncQueryBuffer = 10
29
30
// PutValue adds value corresponding to given Key.
31
// This is the top level "Store" operation of the DHT
32
-func (dht *IpfsDHT) PutValue(ctx context.Context, key u.Key, value []byte) error {
32
+func (dht *IpfsDHT) PutValue(ctx context.Context, key u.Key, value []byte, sign bool) error {
33
log.Debugf("PutValue %s", key)
34
- err := dht.putLocal(key, value)
34
+ sk, err := dht.getOwnPrivateKey()
35
if err != nil {
36
return err
37
}
38
39
- sk, err := dht.getOwnPrivateKey()
39
+ rec, err := record.MakePutRecord(sk, key, value, sign)
40
if err != nil {
41
+ log.Debug("Creation of record failed!")
42
return err
43
}
44
44
- rec, err := record.MakePutRecord(sk, key, value)
45
+ err = dht.putLocal(key, rec)
46
if err != nil {
46
- log.Debug("Creation of record failed!")
47
return err
48
}
49
routing/mock/centralized_client.go
+1
-1
@@ -22,7 +22,7 @@ type client struct {
22
}
23
24
// FIXME(brian): is this method meant to simulate putting a value into the network?
25
-func (c *client) PutValue(ctx context.Context, key u.Key, val []byte) error {
25
+func (c *client) PutValue(ctx context.Context, key u.Key, val []byte, sign bool) error {
26
log.Debugf("PutValue: %s", key)
27
return c.datastore.Put(key.DsKey(), val)
28
}
routing/offline/offline.go
+3
-3
@@ -35,8 +35,8 @@ type offlineRouting struct {
35
sk ci.PrivKey
36
}
37
38
-func (c *offlineRouting) PutValue(ctx context.Context, key u.Key, val []byte) error {
39
- rec, err := record.MakePutRecord(c.sk, key, val)
38
+func (c *offlineRouting) PutValue(ctx context.Context, key u.Key, val []byte, sign bool) error {
39
+ rec, err := record.MakePutRecord(c.sk, key, val, sign)
40
if err != nil {
41
return err
42
}
@@ -89,7 +89,7 @@ func (c *offlineRouting) Ping(ctx context.Context, p peer.ID) (time.Duration, er
89
return 0, ErrOffline
90
}
91
92
-func (c *offlineRouting) Bootstrap(context.Context) (error) {
92
+func (c *offlineRouting) Bootstrap(context.Context) error {
93
return nil
94
}
95
routing/record/record.go
+9
-7
@@ -14,7 +14,7 @@ import (
14
var log = eventlog.Logger("routing/record")
15
16
// MakePutRecord creates and signs a dht record for the given key/value pair
17
-func MakePutRecord(sk ci.PrivKey, key u.Key, value []byte) (*pb.Record, error) {
17
+func MakePutRecord(sk ci.PrivKey, key u.Key, value []byte, sign bool) (*pb.Record, error) {
18
record := new(pb.Record)
19
20
record.Key = proto.String(string(key))
@@ -26,14 +26,16 @@ func MakePutRecord(sk ci.PrivKey, key u.Key, value []byte) (*pb.Record, error) {
26
}
27
28
record.Author = proto.String(string(pkh))
29
- blob := RecordBlobForSig(record)
29
+ if sign {
30
+ blob := RecordBlobForSig(record)
31
31
- sig, err := sk.Sign(blob)
32
- if err != nil {
33
- return nil, err
34
- }
32
+ sig, err := sk.Sign(blob)
33
+ if err != nil {
34
+ return nil, err
35
+ }
36
36
- record.Signature = sig
37
+ record.Signature = sig
38
+ }
39
return record, nil
40
}
41
routing/record/validation.go
+13
-13
@@ -29,19 +29,7 @@ type Validator map[string]ValidatorFunc
29
30
// VerifyRecord checks a record and ensures it is still valid.
31
// It runs needed validators
32
-func (v Validator) VerifyRecord(r *pb.Record, pk ci.PubKey) error {
33
- // First, validate the signature
34
- blob := RecordBlobForSig(r)
35
- ok, err := pk.Verify(blob, r.GetSignature())
36
- if err != nil {
37
- log.Info("Signature verify failed. (ignored)")
38
- return err
39
- }
40
- if !ok {
41
- log.Info("dht found a forged record! (ignored)")
42
- return ErrBadRecord
43
- }
44
-
32
+func (v Validator) VerifyRecord(r *pb.Record) error {
33
// Now, check validity func
34
parts := strings.Split(r.GetKey(), "/")
35
if len(parts) < 3 {
@@ -73,3 +61,15 @@ func ValidatePublicKeyRecord(k u.Key, val []byte) error {
61
}
62
return nil
63
}
64
+
65
+func CheckRecordSig(r *pb.Record, pk ci.PubKey) error {
66
+ blob := RecordBlobForSig(r)
67
+ good, err := pk.Verify(blob, r.Signature)
68
+ if err != nil {
69
+ return nil
70
+ }
71
+ if !good {
72
+ return errors.New("invalid record signature")
73
+ }
74
+ return nil
75
+}
routing/routing.go
+1
-1
@@ -21,7 +21,7 @@ type IpfsRouting interface {
21
// Basic Put/Get
22
23
// PutValue adds value corresponding to given Key.
24
- PutValue(context.Context, u.Key, []byte) error
24
+ PutValue(context.Context, u.Key, []byte, bool) error
25
26
// GetValue searches for the value corresponding to given Key.
27
GetValue(context.Context, u.Key) ([]byte, error)
routing/supernode/client.go
+1
-1
@@ -59,7 +59,7 @@ func (c *Client) FindProvidersAsync(ctx context.Context, k u.Key, max int) <-cha
59
return ch
60
}
61
62
-func (c *Client) PutValue(ctx context.Context, k u.Key, v []byte) error {
62
+func (c *Client) PutValue(ctx context.Context, k u.Key, v []byte, sign bool) error {
63
defer log.EventBegin(ctx, "putValue", &k).Done()
64
r, err := makeRecord(c.peerstore, c.local, k, v)
65
if err != nil {
routing/supernode/server.go
+4
-1
@@ -210,7 +210,10 @@ func verify(ps peer.Peerstore, r *dhtpb.Record) error {
210
if pk == nil {
211
return fmt.Errorf("do not have public key for %s", p)
212
}
213
- if err := v.VerifyRecord(r, pk); err != nil {
213
+ if err := record.CheckRecordSig(r, pk); err != nil {
214
+ return err
215
+ }
216
+ if err := v.VerifyRecord(r); err != nil {
217
return err
218
}
219
return nil
test/integration/grandcentral_test.go
+1
-1
@@ -168,7 +168,7 @@ func RunSupernodePutRecordGetRecord(conf testutil.LatencyConfig) error {
168
k := util.Key("key")
169
note := []byte("a note from putter")
170
171
- if err := putter.Routing.PutValue(ctx, k, note); err != nil {
171
+ if err := putter.Routing.PutValue(ctx, k, note, false); err != nil {
172
return fmt.Errorf("failed to put value: %s", err)
173
}
174