aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGreg Sanders <gsanders87@gmail.com>2022-07-12 10:37:27 -0400
committerGreg Sanders <gsanders87@gmail.com>2022-10-17 11:13:02 -0400
commitd25699280af1ea45bebc884f63a10da7ea275ef9 (patch)
tree153247e252e3d768f941bf3b5af9b06ec36febaa /src
parenta52ff619a45c760f657413cbd40e1e2226068541 (diff)
Verify PSBT inputs rather than check for fields being empty
Diffstat (limited to 'src')
-rw-r--r--src/node/psbt.cpp2
-rw-r--r--src/psbt.cpp33
-rw-r--r--src/psbt.h5
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