Skip to content

Commit 2c0a4ab

Browse files
authored
Merge pull request ipfs/go-ipns#41 from ipfs/chore/require-v2-signatures
fix: require V2 signatures This commit was moved from ipfs/go-ipns@1af8e5c
2 parents fe8211a + f748bd4 commit 2c0a4ab

File tree

4 files changed

+61
-33
lines changed

4 files changed

+61
-33
lines changed

ipns/README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
# go-ipns
22

3-
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://protocol.ai)
4-
[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/)
5-
[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs)
3+
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](https://protocol.ai)
4+
[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](https://ipfs.tech/)
65
[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
76
[![GoDoc](https://godoc.org/github.com/ipfs/go-datastore?status.svg)](https://godoc.org/github.com/ipfs/go-ipns)
87

98
> ipns record definitions
109
11-
This package contains all of the components necessary to create, understand, and validate IPNS records. It does *not* publish or resolve those records. [`go-ipfs`](https://github.com/ipfs/go-ipfs) uses this package internally to manipulate records.
10+
This package contains all of the components necessary to create, understand, and validate IPNS records. It does *not* publish or resolve those records. [Kubo](https://github.com/ipfs/kubo) uses this package internally to manipulate records.
1211

1312
## Lead Maintainer
1413

ipns/errors.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,10 @@ var ErrPublicKeyMismatch = errors.New("public key in record did not match expect
3535

3636
// ErrBadRecord should be returned when an ipns record cannot be unmarshalled
3737
var ErrBadRecord = errors.New("record could not be unmarshalled")
38+
39+
// 10 KiB limit defined in https://github.com/ipfs/specs/pull/319
40+
const MaxRecordSize int = 10 << (10 * 1)
41+
42+
// ErrRecordSize should be returned when an ipns record is
43+
// invalid due to being too big
44+
var ErrRecordSize = errors.New("record exceeds allowed size limit")

ipns/ipns.go

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ func Create(sk ic.PrivKey, val []byte, seq uint64, eol time.Time, ttl time.Durat
5353
}
5454
entry.Data = cborData
5555

56+
// For now we still create V1 signatures. These are deprecated, and not
57+
// used during verification anymore (Validate func requires SignatureV2),
58+
// but setting it here allows legacy nodes (e.g., go-ipfs < v0.9.0) to
59+
// still resolve IPNS published by modern nodes.
5660
sig1, err := sk.Sign(ipnsEntryDataForSigV1(entry))
5761
if err != nil {
5862
return nil, errors.Wrap(err, "could not compute signature data")
@@ -128,28 +132,31 @@ func createCborDataForIpnsEntry(e *pb.IpnsEntry) ([]byte, error) {
128132

129133
// Validates validates the given IPNS entry against the given public key.
130134
func Validate(pk ic.PubKey, entry *pb.IpnsEntry) error {
135+
// Make sure max size is respected
136+
if entry.Size() > MaxRecordSize {
137+
return ErrRecordSize
138+
}
139+
131140
// Check the ipns record signature with the public key
141+
if entry.GetSignatureV2() == nil {
142+
// always error if no valid signature could be found
143+
return ErrSignature
144+
}
132145

133-
// Check v2 signature if it's available, otherwise use the v1 signature
134-
if entry.GetSignatureV2() != nil {
135-
sig2Data, err := ipnsEntryDataForSigV2(entry)
136-
if err != nil {
137-
return fmt.Errorf("could not compute signature data: %w", err)
138-
}
139-
if ok, err := pk.Verify(sig2Data, entry.GetSignatureV2()); err != nil || !ok {
140-
return ErrSignature
141-
}
146+
sig2Data, err := ipnsEntryDataForSigV2(entry)
147+
if err != nil {
148+
return fmt.Errorf("could not compute signature data: %w", err)
149+
}
150+
if ok, err := pk.Verify(sig2Data, entry.GetSignatureV2()); err != nil || !ok {
151+
return ErrSignature
152+
}
142153

143-
// TODO: If we switch from pb.IpnsEntry to a more generic IpnsRecord type then perhaps we should only check
144-
// this if there is no v1 signature. In the meanwhile this helps avoid some potential rough edges around people
145-
// checking the entry fields instead of doing CBOR decoding everywhere.
146-
if err := validateCborDataMatchesPbData(entry); err != nil {
147-
return err
148-
}
149-
} else {
150-
if ok, err := pk.Verify(ipnsEntryDataForSigV1(entry), entry.GetSignatureV1()); err != nil || !ok {
151-
return ErrSignature
152-
}
154+
// TODO: If we switch from pb.IpnsEntry to a more generic IpnsRecord type then perhaps we should only check
155+
// this if there is no v1 signature. In the meanwhile this helps avoid some potential rough edges around people
156+
// checking the entry fields instead of doing CBOR decoding everywhere.
157+
// See https://github.com/ipfs/go-ipns/pull/42 for next steps here
158+
if err := validateCborDataMatchesPbData(entry); err != nil {
159+
return err
153160
}
154161

155162
eol, err := GetEOL(entry)

ipns/validate_test.go

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ func TestPeerIDPubKeyValidate(t *testing.T) {
178178
testValidatorCase(t, sk, kbook, ipnsk, dataNoKey, goodeol, nil)
179179
}
180180

181-
func TestBothSignatureVersionsValidate(t *testing.T) {
181+
func TestOnlySignatureV2Validate(t *testing.T) {
182182
goodeol := time.Now().Add(time.Hour)
183183

184184
sk, pk, err := crypto.GenerateEd25519Key(rand.New(rand.NewSource(42)))
@@ -197,17 +197,12 @@ func TestBothSignatureVersionsValidate(t *testing.T) {
197197
}
198198

199199
entry.SignatureV2 = nil
200-
if err := Validate(pk, entry); err != nil {
201-
t.Fatal(err)
202-
}
203-
204-
entry.SignatureV1 = nil
205200
if err := Validate(pk, entry); !errors.Is(err, ErrSignature) {
206201
t.Fatal(err)
207202
}
208203
}
209204

210-
func TestNewSignatureVersionPreferred(t *testing.T) {
205+
func TestSignatureV1Ignored(t *testing.T) {
211206
goodeol := time.Now().Add(time.Hour)
212207

213208
sk, pk, err := crypto.GenerateEd25519Key(rand.New(rand.NewSource(42)))
@@ -251,13 +246,13 @@ func TestNewSignatureVersionPreferred(t *testing.T) {
251246
t.Fatal("entry2 should be better than entry1")
252247
}
253248

254-
// Having only the v1 signature should be valid
249+
// Having only the v1 signature should be invalid
255250
entry2.SignatureV2 = nil
256-
if err := Validate(pk, entry2); err != nil {
251+
if err := Validate(pk, entry2); !errors.Is(err, ErrSignature) {
257252
t.Fatal(err)
258253
}
259254

260-
// However the v2 signature should be preferred
255+
// Record with v2 signature should always be preferred
261256
best, err = v.Select(ipnsk, [][]byte{mustMarshal(t, entry1), mustMarshal(t, entry2)})
262257
if err != nil {
263258
t.Fatal(err)
@@ -279,6 +274,26 @@ func TestNewSignatureVersionPreferred(t *testing.T) {
279274
}
280275
}
281276

277+
func TestMaxSizeValidate(t *testing.T) {
278+
goodeol := time.Now().Add(time.Hour)
279+
280+
sk, pk, err := crypto.GenerateEd25519Key(rand.New(rand.NewSource(42)))
281+
if err != nil {
282+
t.Fatal(err)
283+
}
284+
285+
// Create record over the max size (value+other fields)
286+
value := make([]byte, MaxRecordSize)
287+
entry, err := Create(sk, value, 1, goodeol, 0)
288+
if err != nil {
289+
t.Fatal(err)
290+
}
291+
// Must fail with ErrRecordSize
292+
if err := Validate(pk, entry); !errors.Is(err, ErrRecordSize) {
293+
t.Fatal(err)
294+
}
295+
}
296+
282297
func TestCborDataCanonicalization(t *testing.T) {
283298
goodeol := time.Now().Add(time.Hour)
284299

0 commit comments

Comments
 (0)