Stop searching for public keys before doing an IPNS Get (#7549)
* feat: stop checking the DHT for public keys before doing an IPNS get. It has been many releases since we started adding the public keys into the IPNS records by default.
Adin Schmahmann committed
Aug 14, 2020 at 18:08 UTC
8e730218525253b2f45d31c122083d98ec2ba0ac
2 files changed
+50
-54
namesys/ipns_resolver_validation_test.go
+50
-40
@@ -10,6 +10,7 @@ import (
10
mockrouting "github.com/ipfs/go-ipfs-routing/mock"
11
offline "github.com/ipfs/go-ipfs-routing/offline"
12
ipns "github.com/ipfs/go-ipns"
13
+ ipns_pb "github.com/ipfs/go-ipns/pb"
14
path "github.com/ipfs/go-path"
15
opts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
16
ci "github.com/libp2p/go-libp2p-core/crypto"
@@ -23,6 +24,25 @@ import (
24
)
25
26
func TestResolverValidation(t *testing.T) {
27
+ t.Run("RSA",
28
+ func(t *testing.T) {
29
+ testResolverValidation(t, ci.RSA)
30
+ })
31
+ t.Run("Ed25519",
32
+ func(t *testing.T) {
33
+ testResolverValidation(t, ci.Ed25519)
34
+ })
35
+ t.Run("ECDSA",
36
+ func(t *testing.T) {
37
+ testResolverValidation(t, ci.ECDSA)
38
+ })
39
+ t.Run("Secp256k1",
40
+ func(t *testing.T) {
41
+ testResolverValidation(t, ci.Secp256k1)
42
+ })
43
+}
44
+
45
+func testResolverValidation(t *testing.T, keyType int) {
46
ctx := context.Background()
47
rid := testutil.RandIdentityOrFatal(t)
48
dstore := dssync.MutexWrap(ds.NewMapDatastore())
@@ -34,16 +54,10 @@ func TestResolverValidation(t *testing.T) {
54
nvVstore := offline.NewOfflineRouter(dstore, mockrouting.MockValidator{})
55
56
// Create entry with expiry in one hour
37
- priv, id, _, ipnsDHTPath := genKeys(t)
57
+ priv, id, _, ipnsDHTPath := genKeys(t, keyType)
58
ts := time.Now()
59
p := []byte("/ipfs/QmfM2r8seH2GiRaC4esTjeraXEachRt8ZsSeGaWTPLyMoG")
40
- entry, err := ipns.Create(priv, p, 1, ts.Add(time.Hour))
41
- if err != nil {
42
- t.Fatal(err)
43
- }
44
-
45
- // Make peer's public key available in peer store
46
- err = peerstore.AddPubKey(id, priv.GetPublic())
60
+ entry, err := createIPNSRecordWithEmbeddedPublicKey(priv, p, 1, ts.Add(time.Hour))
61
if err != nil {
62
t.Fatal(err)
63
}
@@ -63,7 +77,7 @@ func TestResolverValidation(t *testing.T) {
77
t.Fatalf("Mismatch between published path %s and resolved path %s", p, resp)
78
}
79
// Create expired entry
66
- expiredEntry, err := ipns.Create(priv, p, 1, ts.Add(-1*time.Hour))
80
+ expiredEntry, err := createIPNSRecordWithEmbeddedPublicKey(priv, p, 1, ts.Add(-1*time.Hour))
81
if err != nil {
82
t.Fatal(err)
83
}
@@ -81,13 +95,7 @@ func TestResolverValidation(t *testing.T) {
95
}
96
97
// Create IPNS record path with a different private key
84
- priv2, id2, _, ipnsDHTPath2 := genKeys(t)
85
-
86
- // Make peer's public key available in peer store
87
- err = peerstore.AddPubKey(id2, priv2.GetPublic())
88
- if err != nil {
89
- t.Fatal(err)
90
- }
98
+ priv2, id2, _, ipnsDHTPath2 := genKeys(t, keyType)
99
100
// Publish entry
101
err = PublishEntry(ctx, nvVstore, ipnsDHTPath2, entry)
@@ -102,50 +110,52 @@ func TestResolverValidation(t *testing.T) {
110
t.Fatal("ValidateIpnsRecord should have failed signature verification")
111
}
112
105
- // Publish entry without making public key available in peer store
106
- priv3, id3, pubkDHTPath3, ipnsDHTPath3 := genKeys(t)
107
- entry3, err := ipns.Create(priv3, p, 1, ts.Add(time.Hour))
108
- if err != nil {
113
+ // Try embedding the incorrect private key inside the entry
114
+ if err := ipns.EmbedPublicKey(priv2.GetPublic(), entry); err != nil {
115
t.Fatal(err)
116
}
111
- err = PublishEntry(ctx, nvVstore, ipnsDHTPath3, entry3)
117
+
118
+ // Publish entry
119
+ err = PublishEntry(ctx, nvVstore, ipnsDHTPath2, entry)
120
if err != nil {
121
t.Fatal(err)
122
}
123
116
- // Record should fail validation because public key is not available
117
- // in peer store or on network
118
- _, err = resolve(ctx, resolver, id3.Pretty(), opts.DefaultResolveOpts())
124
+ // Record should fail validation because public key defined by
125
+ // ipns path doesn't match record signature
126
+ _, err = resolve(ctx, resolver, id2.Pretty(), opts.DefaultResolveOpts())
127
if err == nil {
120
- t.Fatal("ValidateIpnsRecord should have failed because public key was not found")
128
+ t.Fatal("ValidateIpnsRecord should have failed signature verification")
129
+ }
130
+}
131
+
132
+func genKeys(t *testing.T, keyType int) (ci.PrivKey, peer.ID, string, string) {
133
+ bits := 0
134
+ if keyType == ci.RSA {
135
+ bits = 2048
136
}
137
123
- // Publish public key to the network
124
- err = PublishPublicKey(ctx, vstore, pubkDHTPath3, priv3.GetPublic())
138
+ sk, pk, err := test.RandTestKeyPair(keyType, bits)
139
if err != nil {
140
t.Fatal(err)
141
}
128
-
129
- // Record should now pass validation because resolver will ensure
130
- // public key is available in the peer store by looking it up in
131
- // the DHT, which causes the DHT to fetch it and cache it in the
132
- // peer store
133
- _, err = resolve(ctx, resolver, id3.Pretty(), opts.DefaultResolveOpts())
142
+ id, err := peer.IDFromPublicKey(pk)
143
if err != nil {
144
t.Fatal(err)
145
}
146
+ return sk, id, PkKeyForID(id), ipns.RecordKey(id)
147
}
148
139
-func genKeys(t *testing.T) (ci.PrivKey, peer.ID, string, string) {
140
- sk, pk, err := test.RandTestKeyPair(ci.RSA, 2048)
149
+func createIPNSRecordWithEmbeddedPublicKey(sk ci.PrivKey, val []byte, seq uint64, eol time.Time) (*ipns_pb.IpnsEntry, error){
150
+ entry, err := ipns.Create(sk, val, seq, eol)
151
if err != nil {
142
- t.Fatal(err)
152
+ return nil, err
153
}
144
- id, err := peer.IDFromPublicKey(pk)
145
- if err != nil {
146
- t.Fatal(err)
154
+ if err := ipns.EmbedPublicKey(sk.GetPublic(), entry); err != nil {
155
+ return nil, err
156
}
148
- return sk, id, PkKeyForID(id), ipns.RecordKey(id)
157
+
158
+ return entry, nil
159
}
160
161
type mockValueStore struct {
namesys/routing.go
-14
@@ -69,20 +69,6 @@ func (r *IpnsResolver) resolveOnceAsync(ctx context.Context, name string, option
69
return out
70
}
71
72
- // Name should be the hash of a public key retrievable from ipfs.
73
- // We retrieve the public key here to make certain that it's in the peer
74
- // store before calling GetValue() on the DHT - the DHT will call the
75
- // ipns validator, which in turn will get the public key from the peer
76
- // store to verify the record signature
77
- _, err = routing.GetPublicKey(r.routing, ctx, pid)
78
- if err != nil {
79
- log.Debugf("RoutingResolver: could not retrieve public key %s: %s\n", name, err)
80
- out <- onceResult{err: err}
81
- close(out)
82
- cancel()
83
- return out
84
- }
85
-
72
// Use the routing system to get the name.
73
// Note that the DHT will call the ipns validator when retrieving
74
// the value, which in turn verifies the ipns record signature