Skip to content

validate pubkey from extended public key when parsed; validate extended key version #38

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion ngu/hdnode.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,18 +261,29 @@ STATIC mp_obj_t s_hdnode_deserialize(mp_obj_t self_in, mp_obj_t encoded) {
p += 32;

if(p[0] == 0x00) {
/* mainnet/testnet private */
assert((version == 0x0488ADE4) || (version == 0x04358394));
p++;
memcpy(self->privkey, p, 32);
p += 32;
self->have_private = true;
_calc_pubkey(self);
} else if(p[0] == 0x02 || p[0] == 0x3) {
/* mainnet/testnet public */
assert((version == 0x0488B21E) || (version == 0x043587CF));
// 33 bytes of pubkey
self->have_private = false;
memcpy(self->pubkey, p, 33);
p += 33;

/* verify that parsed pubkey is valid */
secp256k1_pubkey pub;
int ok;
ok = secp256k1_ec_pubkey_parse(lib_ctx, &pub, self->pubkey, 33);
if(!ok) goto fail;

} else {
mp_raise_ValueError(MP_ERROR_TEXT("bad pubkey"));
goto fail;
}

_calc_hash160(self);
Expand All @@ -291,6 +302,11 @@ STATIC mp_obj_t s_hdnode_deserialize(mp_obj_t self_in, mp_obj_t encoded) {
assert(p == &tmp[78]);

return mp_obj_new_int(version);

fail:
self->depth = -1;
mp_raise_ValueError(MP_ERROR_TEXT("bad pubkey"));
return 0; // not reached
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(s_hdnode_deserialize_obj, s_hdnode_deserialize);

Expand Down
1 change: 1 addition & 0 deletions ngu/ngu_tests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ test tests:
$(MPY) test_ec_gen.py
$(PY) test_bip39.py
$(MPY) test_bip39.py
$(MPY) test_bip32.py

# runs the test compiled in, not here
# or, on target
Expand Down
1 change: 1 addition & 0 deletions ngu/ngu_tests/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@
import ngu_tests.test_ec
import ngu_tests.test_ec_gen
import ngu_tests.test_bip39
import ngu_tests.test_bip32
35 changes: 35 additions & 0 deletions ngu/ngu_tests/test_bip32.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Invalid Extended Keys test
# https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-5
import ngu

TO_DO = [
"xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6LBpB85b3D2yc8sfvZU521AAwdZafEz7mnzBBsz4wKY5fTtTQBm", #(pubkey version / prvkey mismatch)
"xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6Txnt3siSujt9RCVYsx4qHZGc62TG4McvMGcAUjeuwZdduYEvFn", #(invalid pubkey prefix 04)
"xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6N8ZMMXctdiCjxTNq964yKkwrkBJJwpzZS4HS2fxvyYUA4q2Xe4", #(invalid pubkey prefix 01)
# allowed
# "xpub661no6RGEX3uJkY4bNnPcw4URcQTrSibUZ4NqJEw5eBkv7ovTwgiT91XX27VbEXGENhYRCf7hyEbWrR3FewATdCEebj6znwMfQkhRYHRLpJ", # (zero depth with non - zero parent fingerprint)
# "xpub661MyMwAuDcm6CRQ5N4qiHKrJ39Xe1R1NyfouMKTTWcguwVcfrZJaNvhpebzGerh7gucBvzEQWRugZDuDXjNDRmXzSZe4c7mnTK97pTvGS8", # (zero depth with non - zero index)
"xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6Q5JXayek4PRsn35jii4veMimro1xefsM58PgBMrvdYre8QyULY", # (invalid pubkey 020000000000000000000000000000000000000000000000000000000000000007)
"DMwo58pR1QLEFihHiXPVykYB6fJmsTeHvyTp7hRThAtCX8CvYzgPcn8XnmdfHPmHJiEDXkTiJTVV9rHEBUem2mwVbbNfvT2MTcAqj3nesx8uBf9", # unknown version
# private below
"xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFGTQQD3dC4H2D5GBj7vWvSQaaBv5cxi9gafk7NF3pnBju6dwKvH", # (prvkey version / pubkey mismatch)
"xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFGpWnsj83BHtEy5Zt8CcDr1UiRXuWCmTQLxEK9vbz5gPstX92JQ", # (invalid prvkey prefix 04)
"xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFAzHGBP2UuGCqWLTAPLcMtD9y5gkZ6Eq3Rjuahrv17fEQ3Qen6J", # (invalid prvkey prefix 01)
# allowed
# "xprv9s2SPatNQ9Vc6GTbVMFPFo7jsaZySyzk7L8n2uqKXJen3KUmvQNTuLh3fhZMBoG3G4ZW1N2kZuHEPY53qmbZzCHshoQnNf4GvELZfqTUrcv", # (zero depth with non - zero parent fingerprint)
# "xprv9s21ZrQH4r4TsiLvyLXqM9P7k1K3EYhA1kkD6xuquB5i39AU8KF42acDyL3qsDbU9NmZn6MsGSUYZEsuoePmjzsB3eFKSUEh3Gu1N3cqVUN", # (zero depth with non - zero index)
"xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzF93Y5wvzdUayhgkkFoicQZcP3y52uPPxFnfoLZB21Teqt1VvEHx", # (private key 0 not in 1..n - 1)
"xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFAzHGBP2UuGCqWLTAPLcMtD5SDKr24z3aiUvKr9bJpdrcLg1y3G", # (private key n not in 1..n - 1)
"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHL", # (invalid checksum)
"DMwo58pR1QLEFihHiXPVykYB6fJmsTeHvyTp7hRThAtCX8CvYzgPcn8XnmdfHGMQzT7ayAmfo4z3gY5KfbrZWZ6St24UVf2Qgo6oujFktLHdHY4", # (unknown version)
]

HDNode = ngu.hdnode.HDNode
for ek in TO_DO:
n = HDNode()
try:
n.deserialize(ek)
raise AttributeError
except (AssertionError, ValueError, RuntimeError): pass

print('PASS - test_bip32')
2 changes: 1 addition & 1 deletion ngu/ngu_tests/test_hdnode.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def test_derive():
p1 = a.derive(43, False).pubkey()

b = HDNode()
assert b.deserialize(a.serialize(0x123, 0)) == 0x123
assert b.deserialize(a.serialize(0x0488B21E, 0)) == 0x0488B21E
p2 = b.pubkey()
assert b.depth() == 1
assert b.parent_fp() == m_fp
Expand Down