diff options
author | Greg Sanders <gsanders87@gmail.com> | 2022-07-12 10:37:27 -0400 |
---|---|---|
committer | Greg Sanders <gsanders87@gmail.com> | 2022-10-17 11:13:02 -0400 |
commit | d25699280af1ea45bebc884f63a10da7ea275ef9 (patch) | |
tree | 153247e252e3d768f941bf3b5af9b06ec36febaa /src | |
parent | a52ff619a45c760f657413cbd40e1e2226068541 (diff) |
Verify PSBT inputs rather than check for fields being empty
Diffstat (limited to 'src')
-rw-r--r-- | src/node/psbt.cpp | 2 | ||||
-rw-r--r-- | src/psbt.cpp | 33 | ||||
-rw-r--r-- | src/psbt.h | 5 |
3 files changed, 37 insertions, 3 deletions
diff --git a/src/node/psbt.cpp b/src/node/psbt.cpp index 57162cd679..ca3fc0955d 100644 --- a/src/node/psbt.cpp +++ b/src/node/psbt.cpp @@ -59,7 +59,7 @@ PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx) } // Check if it is final - if (!utxo.IsNull() && !PSBTInputSigned(input)) { + if (!PSBTInputSignedAndVerified(psbtx, i, &txdata)) { input_analysis.is_final = false; // Figure out what is missing diff --git a/src/psbt.cpp b/src/psbt.cpp index cbf2f88788..461987c503 100644 --- a/src/psbt.cpp +++ b/src/psbt.cpp @@ -4,6 +4,7 @@ #include <psbt.h> +#include <policy/policy.h> #include <util/check.h> #include <util/strencodings.h> @@ -273,11 +274,41 @@ void PSBTOutput::Merge(const PSBTOutput& output) if (m_tap_internal_key.IsNull() && !output.m_tap_internal_key.IsNull()) m_tap_internal_key = output.m_tap_internal_key; if (m_tap_tree.empty() && !output.m_tap_tree.empty()) m_tap_tree = output.m_tap_tree; } + bool PSBTInputSigned(const PSBTInput& input) { return !input.final_script_sig.empty() || !input.final_script_witness.IsNull(); } +bool PSBTInputSignedAndVerified(const PartiallySignedTransaction psbt, unsigned int input_index, const PrecomputedTransactionData* txdata) +{ + CTxOut utxo; + assert(psbt.inputs.size() >= input_index); + const PSBTInput& input = psbt.inputs[input_index]; + + if (input.non_witness_utxo) { + // If we're taking our information from a non-witness UTXO, verify that it matches the prevout. + COutPoint prevout = psbt.tx->vin[input_index].prevout; + if (prevout.n >= input.non_witness_utxo->vout.size()) { + return false; + } + if (input.non_witness_utxo->GetHash() != prevout.hash) { + return false; + } + utxo = input.non_witness_utxo->vout[prevout.n]; + } else if (!input.witness_utxo.IsNull()) { + utxo = input.witness_utxo; + } else { + return false; + } + + if (txdata) { + return VerifyScript(input.final_script_sig, utxo.scriptPubKey, &input.final_script_witness, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker{&(*psbt.tx), input_index, utxo.nValue, *txdata, MissingDataBehavior::FAIL}); + } else { + return VerifyScript(input.final_script_sig, utxo.scriptPubKey, &input.final_script_witness, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker{&(*psbt.tx), input_index, utxo.nValue, MissingDataBehavior::FAIL}); + } +} + size_t CountPSBTUnsignedInputs(const PartiallySignedTransaction& psbt) { size_t count = 0; for (const auto& input : psbt.inputs) { @@ -331,7 +362,7 @@ bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& PSBTInput& input = psbt.inputs.at(index); const CMutableTransaction& tx = *psbt.tx; - if (PSBTInputSigned(input)) { + if (PSBTInputSignedAndVerified(psbt, index, txdata)) { return true; } diff --git a/src/psbt.h b/src/psbt.h index ddcdb8c68d..37bf142366 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -1218,9 +1218,12 @@ std::string PSBTRoleName(PSBTRole role); /** Compute a PrecomputedTransactionData object from a psbt. */ PrecomputedTransactionData PrecomputePSBTData(const PartiallySignedTransaction& psbt); -/** Checks whether a PSBTInput is already signed. */ +/** Checks whether a PSBTInput is already signed by checking for non-null finalized fields. */ bool PSBTInputSigned(const PSBTInput& input); +/** Checks whether a PSBTInput is already signed by doing script verification using final fields. */ +bool PSBTInputSignedAndVerified(const PartiallySignedTransaction psbt, unsigned int input_index, const PrecomputedTransactionData* txdata); + /** Signs a PSBTInput, verifying that all provided data matches what is being signed. * * txdata should be the output of PrecomputePSBTData (which can be shared across |