Skip to content

Commit f970056

Browse files
authored
crypto/hd: make DerivePrivateKeyForPath error and not panic on trailing slashes (#8607)
Detected during my audit, right before fuzzing, the code that checked for presence of hyphens per path segment assumed that the part would always be non-empty. However, with paths such as: * m/4/ * /44/ * m/4/// it'd panic with a runtime slice out of bounds. With this new change, we now: * firstly strip the right trailing slash * on finding any empty segments of a path return an error Fixes #8557
1 parent 56fc3fc commit f970056

File tree

2 files changed

+31
-1
lines changed

2 files changed

+31
-1
lines changed

crypto/hd/hdpath.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"encoding/binary"
77
"fmt"
88
"math/big"
9+
"path/filepath"
910
"strconv"
1011
"strings"
1112

@@ -177,6 +178,9 @@ func ComputeMastersFromSeed(seed []byte) (secret [32]byte, chainCode [32]byte) {
177178
// DerivePrivateKeyForPath derives the private key by following the BIP 32/44 path from privKeyBytes,
178179
// using the given chainCode.
179180
func DerivePrivateKeyForPath(privKeyBytes, chainCode [32]byte, path string) ([]byte, error) {
181+
// First step is to trim the right end path separator lest we panic.
182+
// See issue https://github.com/cosmos/cosmos-sdk/issues/8557
183+
path = strings.TrimRightFunc(path, func(r rune) bool { return r == filepath.Separator })
180184
data := privKeyBytes
181185
parts := strings.Split(path, "/")
182186

@@ -187,7 +191,10 @@ func DerivePrivateKeyForPath(privKeyBytes, chainCode [32]byte, path string) ([]b
187191
parts = parts[1:]
188192
}
189193

190-
for _, part := range parts {
194+
for i, part := range parts {
195+
if part == "" {
196+
return nil, fmt.Errorf("path %q with split element #%d is an empty string", part, i)
197+
}
191198
// do we have an apostrophe?
192199
harden := part[len(part)-1:] == "'"
193200
// harden == private derivation, else public derivation:

crypto/hd/hdpath_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,3 +281,26 @@ func ExampleSomeBIP32TestVecs() {
281281
//
282282
// c4c11d8c03625515905d7e89d25dfc66126fbc629ecca6db489a1a72fc4bda78
283283
}
284+
285+
// Ensuring that we don't crash if values have trailing slashes
286+
// See issue https://github.com/cosmos/cosmos-sdk/issues/8557.
287+
func TestDerivePrivateKeyForPathDoNotCrash(t *testing.T) {
288+
paths := []string{
289+
"m/5/",
290+
"m/5",
291+
"/44",
292+
"m//5",
293+
"m/0/7",
294+
"/",
295+
" m  /0/7", // Test case from fuzzer
296+
"  /  ", // Test case from fuzzer
297+
"m///7//////",
298+
}
299+
300+
for _, path := range paths {
301+
path := path
302+
t.Run(path, func(t *testing.T) {
303+
hd.DerivePrivateKeyForPath([32]byte{}, [32]byte{}, path)
304+
})
305+
}
306+
}

0 commit comments

Comments
 (0)