diff options
author | Antoine Poinsot <darosior@protonmail.com> | 2024-04-11 16:08:01 +0200 |
---|---|---|
committer | glozow <gloriajzhao@gmail.com> | 2024-05-23 17:05:57 +0100 |
commit | d9ef6cf934cbd8e9b2f8256de001ca44f74ad6e9 (patch) | |
tree | ee460a6cdc2f21a2d2607b9aa91809fd6d81e558 | |
parent | e4859c82c7b848554b4e9d27c2f8b8615422528e (diff) |
sign: don't assume we are parsing a sane Miniscript
The script provided for signature might be externally provided, for
instance by way of 'finalizepsbt'. Therefore the script might be
ill-crafted, so don't assume pubkeys are always 32 bytes.
Thanks to Niklas for finding this.
Github-Pull: #29853
Rebased-From: 4d8d21320eba54571ff63931509cd515c3e20339
-rw-r--r-- | src/script/sign.cpp | 2 | ||||
-rw-r--r-- | src/test/script_tests.cpp | 24 |
2 files changed, 25 insertions, 1 deletions
diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 251a8420f7..d91a246d03 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -295,7 +295,7 @@ struct TapSatisfier: Satisfier<XOnlyPubKey> { //! Conversion from a raw xonly public key. template <typename I> std::optional<XOnlyPubKey> FromPKBytes(I first, I last) const { - CHECK_NONFATAL(last - first == 32); + if (last - first != 32) return {}; XOnlyPubKey pubkey; std::copy(first, last, pubkey.begin()); return pubkey; diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 624d0b2c12..50715e9a04 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -1276,6 +1276,30 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) BOOST_CHECK(combined.scriptSig == partial3c); } +/** + * Reproduction of an exception incorrectly raised when parsing a public key inside a TapMiniscript. + */ +BOOST_AUTO_TEST_CASE(sign_invalid_miniscript) +{ + FillableSigningProvider keystore; + SignatureData sig_data; + CMutableTransaction prev, curr; + + // Create a Taproot output which contains a leaf in which a non-32 bytes push is used where a public key is expected + // by the Miniscript parser. This offending Script was found by the RPC fuzzer. + const auto invalid_pubkey{ParseHex("173d36c8c9c9c9ffffffffffff0200000000021e1e37373721361818181818181e1e1e1e19000000000000000000b19292929292926b006c9b9b9292")}; + TaprootBuilder builder; + builder.Add(0, {invalid_pubkey}, 0xc0); + XOnlyPubKey nums{ParseHex("50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0")}; + builder.Finalize(nums); + prev.vout.emplace_back(0, GetScriptForDestination(builder.GetOutput())); + curr.vin.emplace_back(COutPoint{prev.GetHash(), 0}); + sig_data.tr_spenddata = builder.GetSpendData(); + + // SignSignature can fail but it shouldn't raise an exception (nor crash). + BOOST_CHECK(!SignSignature(keystore, CTransaction(prev), curr, 0, SIGHASH_ALL, sig_data)); +} + BOOST_AUTO_TEST_CASE(script_standard_push) { ScriptError err; |