Skip to content

Commit c1b7400

Browse files
committed
fix: enforce minimal encoding
Note: this removes two errors that don't appear to be used by anyone.
1 parent 3da5bbb commit c1b7400

File tree

5 files changed

+64
-59
lines changed

5 files changed

+64
-59
lines changed

cid.go

Lines changed: 30 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -22,29 +22,20 @@ package cid
2222
import (
2323
"bytes"
2424
"encoding"
25-
"encoding/binary"
2625
"encoding/json"
2726
"errors"
2827
"fmt"
2928
"strings"
3029

3130
mbase "github.com/multiformats/go-multibase"
3231
mh "github.com/multiformats/go-multihash"
32+
varint "github.com/multiformats/go-varint"
3333
)
3434

3535
// UnsupportedVersionString just holds an error message
3636
const UnsupportedVersionString = "<unsupported cid version>"
3737

3838
var (
39-
// ErrVarintBuffSmall means that a buffer passed to the cid parser was not
40-
// long enough, or did not contain an invalid cid
41-
ErrVarintBuffSmall = errors.New("reading varint: buffer too small")
42-
43-
// ErrVarintTooBig means that the varint in the given cid was above the
44-
// limit of 2^64
45-
ErrVarintTooBig = errors.New("reading varint: varint bigger than 64bits" +
46-
" and not supported")
47-
4839
// ErrCidTooShort means that the cid passed to decode was not long
4940
// enough to be a valid Cid
5041
ErrCidTooShort = errors.New("cid too short")
@@ -173,9 +164,9 @@ func NewCidV0(mhash mh.Multihash) Cid {
173164
func NewCidV1(codecType uint64, mhash mh.Multihash) Cid {
174165
hashlen := len(mhash)
175166
// two 8 bytes (max) numbers plus hash
176-
buf := make([]byte, 2*binary.MaxVarintLen64+hashlen)
177-
n := binary.PutUvarint(buf, 1)
178-
n += binary.PutUvarint(buf[n:], codecType)
167+
buf := make([]byte, 1+varint.UvarintSize(codecType)+hashlen)
168+
n := varint.PutUvarint(buf, 1)
169+
n += varint.PutUvarint(buf[n:], codecType)
179170
cn := copy(buf[n:], mhash)
180171
if cn != hashlen {
181172
panic("copy hash length is inconsistent")
@@ -281,17 +272,6 @@ func ExtractEncoding(v string) (mbase.Encoding, error) {
281272
return encoding, nil
282273
}
283274

284-
func uvError(read int) error {
285-
switch {
286-
case read == 0:
287-
return ErrVarintBuffSmall
288-
case read < 0:
289-
return ErrVarintTooBig
290-
default:
291-
return nil
292-
}
293-
}
294-
295275
// Cast takes a Cid data slice, parses it and returns a Cid.
296276
// For CidV1, the data buffer is in the form:
297277
//
@@ -351,8 +331,8 @@ func (c Cid) Type() uint64 {
351331
if c.Version() == 0 {
352332
return DagProtobuf
353333
}
354-
_, n := uvarint(c.str)
355-
codec, _ := uvarint(c.str[n:])
334+
_, n, _ := uvarint(c.str)
335+
codec, _, _ := uvarint(c.str[n:])
356336
return codec
357337
}
358338

@@ -414,9 +394,9 @@ func (c Cid) Hash() mh.Multihash {
414394
}
415395

416396
// skip version length
417-
_, n1 := binary.Uvarint(bytes)
397+
_, n1, _ := varint.FromUvarint(bytes)
418398
// skip codec length
419-
_, n2 := binary.Uvarint(bytes[n1:])
399+
_, n2, _ := varint.FromUvarint(bytes[n1:])
420400

421401
return mh.Multihash(bytes[n1+n2:])
422402
}
@@ -562,34 +542,42 @@ func (p Prefix) Sum(data []byte) (Cid, error) {
562542
//
563543
// <version><codec><mh-type><mh-length>
564544
func (p Prefix) Bytes() []byte {
565-
buf := make([]byte, 4*binary.MaxVarintLen64)
566-
n := binary.PutUvarint(buf, p.Version)
567-
n += binary.PutUvarint(buf[n:], p.Codec)
568-
n += binary.PutUvarint(buf[n:], uint64(p.MhType))
569-
n += binary.PutUvarint(buf[n:], uint64(p.MhLength))
570-
return buf[:n]
545+
size := varint.UvarintSize(p.Version)
546+
size += varint.UvarintSize(p.Codec)
547+
size += varint.UvarintSize(p.MhType)
548+
size += varint.UvarintSize(uint64(p.MhLength))
549+
550+
buf := make([]byte, size)
551+
n := varint.PutUvarint(buf, p.Version)
552+
n += varint.PutUvarint(buf[n:], p.Codec)
553+
n += varint.PutUvarint(buf[n:], p.MhType)
554+
n += varint.PutUvarint(buf[n:], uint64(p.MhLength))
555+
if n != size {
556+
panic("size mismatch")
557+
}
558+
return buf
571559
}
572560

573561
// PrefixFromBytes parses a Prefix-byte representation onto a
574562
// Prefix.
575563
func PrefixFromBytes(buf []byte) (Prefix, error) {
576564
r := bytes.NewReader(buf)
577-
vers, err := binary.ReadUvarint(r)
565+
vers, err := varint.ReadUvarint(r)
578566
if err != nil {
579567
return Prefix{}, err
580568
}
581569

582-
codec, err := binary.ReadUvarint(r)
570+
codec, err := varint.ReadUvarint(r)
583571
if err != nil {
584572
return Prefix{}, err
585573
}
586574

587-
mhtype, err := binary.ReadUvarint(r)
575+
mhtype, err := varint.ReadUvarint(r)
588576
if err != nil {
589577
return Prefix{}, err
590578
}
591579

592-
mhlen, err := binary.ReadUvarint(r)
580+
mhlen, err := varint.ReadUvarint(r)
593581
if err != nil {
594582
return Prefix{}, err
595583
}
@@ -616,17 +604,17 @@ func CidFromBytes(data []byte) (int, Cid, error) {
616604
return 34, Cid{string(h)}, nil
617605
}
618606

619-
vers, n := binary.Uvarint(data)
620-
if err := uvError(n); err != nil {
607+
vers, n, err := varint.FromUvarint(data)
608+
if err != nil {
621609
return 0, Undef, err
622610
}
623611

624612
if vers != 1 {
625613
return 0, Undef, fmt.Errorf("expected 1 as the cid version number, got: %d", vers)
626614
}
627615

628-
_, cn := binary.Uvarint(data[n:])
629-
if err := uvError(cn); err != nil {
616+
_, cn, err := varint.FromUvarint(data[n:])
617+
if err != nil {
630618
return 0, Undef, err
631619
}
632620

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ module github.com/ipfs/go-cid
22

33
require (
44
github.com/multiformats/go-multibase v0.0.1
5-
github.com/multiformats/go-multihash v0.0.10
5+
github.com/multiformats/go-multihash v0.0.13
6+
github.com/multiformats/go-varint v0.0.5
67
)
78

89
go 1.13

go.sum

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,20 @@ github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771 h1:MHkK1uRtFbV
44
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
55
github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ=
66
github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
7-
github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78=
8-
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
7+
github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc=
8+
github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
99
github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI=
1010
github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=
1111
github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA=
1212
github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs=
13-
github.com/multiformats/go-multihash v0.0.8 h1:wrYcW5yxSi3dU07n5jnuS5PrNwyHy0zRHGVoUugWvXg=
14-
github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
15-
github.com/multiformats/go-multihash v0.0.9 h1:aoijQXYYl7Xtb2pUUP68R+ys1TlnlR3eX6wmozr0Hp4=
16-
github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
17-
github.com/multiformats/go-multihash v0.0.10 h1:lMoNbh2Ssd9PUF74Nz008KGzGPlfeV6wH3rit5IIGCM=
18-
github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
13+
github.com/multiformats/go-multihash v0.0.12 h1:i2PQZWlsq8asUZwPS5w7VMCoUKEz/k/XG6WH30gsTU8=
14+
github.com/multiformats/go-multihash v0.0.12/go.mod h1:2+oRiLVLqXx+yxM/RIdhLstp1q2WMJAlQ4kdLkS3un0=
15+
github.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc=
16+
github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
17+
github.com/multiformats/go-varint v0.0.4 h1:CplQWhUouUgTZ53vNFE8VoWr2VjaKXci+xyrKyyFuSw=
18+
github.com/multiformats/go-varint v0.0.4/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
19+
github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg=
20+
github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
1921
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
2022
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
2123
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=

varint.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package cid
22

3+
import (
4+
"github.com/multiformats/go-varint"
5+
)
6+
37
// Version of varint function that work with a string rather than
48
// []byte to avoid unnecessary allocation
59

@@ -15,20 +19,22 @@ package cid
1519
// n < 0: value larger than 64 bits (overflow)
1620
// and -n is the number of bytes read
1721
//
18-
func uvarint(buf string) (uint64, int) {
22+
func uvarint(buf string) (uint64, int, error) {
1923
var x uint64
2024
var s uint
2125
// we have a binary string so we can't use a range loope
2226
for i := 0; i < len(buf); i++ {
2327
b := buf[i]
2428
if b < 0x80 {
2529
if i > 9 || i == 9 && b > 1 {
26-
return 0, -(i + 1) // overflow
30+
return 0, 0, varint.ErrOverflow
31+
} else if b == 0 && i > 0 {
32+
return 0, 0, varint.ErrNotMinimal
2733
}
28-
return x | uint64(b)<<s, i + 1
34+
return x | uint64(b)<<s, i + 1, nil
2935
}
3036
x |= uint64(b&0x7f) << s
3137
s += 7
3238
}
33-
return 0, 0
39+
return 0, 0, varint.ErrUnderflow
3440
}

varint_test.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
11
package cid
22

33
import (
4-
"encoding/binary"
54
"testing"
5+
6+
"github.com/multiformats/go-varint"
67
)
78

89
func TestUvarintRoundTrip(t *testing.T) {
910
testCases := []uint64{0, 1, 2, 127, 128, 129, 255, 256, 257, 1<<63 - 1}
1011
for _, tc := range testCases {
12+
t.Log("testing", tc)
1113
buf := make([]byte, 16)
12-
binary.PutUvarint(buf, tc)
13-
v, l1 := uvarint(string(buf))
14-
_, l2 := binary.Uvarint(buf)
14+
varint.PutUvarint(buf, tc)
15+
v, l1, err := uvarint(string(buf))
16+
if err != nil {
17+
t.Fatalf("%v: %s", buf, err)
18+
}
19+
_, l2, err := varint.FromUvarint(buf)
20+
if err != nil {
21+
t.Fatal(err)
22+
}
1523
if tc != v {
1624
t.Errorf("roundtrip failed expected %d but got %d", tc, v)
1725
}

0 commit comments

Comments
 (0)