From fb9faffae3a26b8aed8b671864ba679747163019 Mon Sep 17 00:00:00 2001 From: Antoine Poinsot Date: Tue, 19 Jul 2022 11:58:16 +0200 Subject: extended keys: fail to derive too large depth instead of wrapping around This issue was reported to me by Marco Falke, and found with the descriptor_parse fuzz target. --- src/key.cpp | 1 + src/pubkey.cpp | 1 + src/test/bip32_tests.cpp | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/src/key.cpp b/src/key.cpp index 9b0971a2dd..199808505d 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -333,6 +333,7 @@ bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const } bool CExtKey::Derive(CExtKey &out, unsigned int _nChild) const { + if (nDepth == std::numeric_limits::max()) return false; out.nDepth = nDepth + 1; CKeyID id = key.GetPubKey().GetID(); memcpy(out.vchFingerprint, &id, 4); diff --git a/src/pubkey.cpp b/src/pubkey.cpp index 324f681a0a..0b94868d1f 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -365,6 +365,7 @@ void CExtPubKey::DecodeWithVersion(const unsigned char code[BIP32_EXTKEY_WITH_VE } bool CExtPubKey::Derive(CExtPubKey &out, unsigned int _nChild) const { + if (nDepth == std::numeric_limits::max()) return false; out.nDepth = nDepth + 1; CKeyID id = pubkey.GetID(); memcpy(out.vchFingerprint, &id, 4); diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp index 64cc924239..75b29ae0aa 100644 --- a/src/test/bip32_tests.cpp +++ b/src/test/bip32_tests.cpp @@ -184,4 +184,22 @@ BOOST_AUTO_TEST_CASE(bip32_test5) { } } +BOOST_AUTO_TEST_CASE(bip32_max_depth) { + CExtKey key_parent{DecodeExtKey(test1.vDerive[0].prv)}, key_child; + CExtPubKey pubkey_parent{DecodeExtPubKey(test1.vDerive[0].pub)}, pubkey_child; + + // We can derive up to the 255th depth.. + for (auto i = 0; i++ < 255;) { + BOOST_CHECK(key_parent.Derive(key_child, 0)); + std::swap(key_parent, key_child); + BOOST_CHECK(pubkey_parent.Derive(pubkey_child, 0)); + std::swap(pubkey_parent, pubkey_child); + } + + // But trying to derive a non-existent 256th depth will fail! + BOOST_CHECK(key_parent.nDepth == 255 && pubkey_parent.nDepth == 255); + BOOST_CHECK(!key_parent.Derive(key_child, 0)); + BOOST_CHECK(!pubkey_parent.Derive(pubkey_child, 0)); +} + BOOST_AUTO_TEST_SUITE_END() -- cgit v1.2.3