diff options
Diffstat (limited to 'src/script')
| -rw-r--r-- | src/script/sign.cpp | 16 | ||||
| -rw-r--r-- | src/script/sign.h | 18 |
2 files changed, 29 insertions, 5 deletions
diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 1e4102c20..1ab5051ff 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -244,17 +244,33 @@ bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& t input.FillSignatureData(sigdata); // Get UTXO + bool require_witness_sig = false; CTxOut utxo; if (input.non_witness_utxo) { + // If we're taking our information from a non-witness UTXO, verify that it matches the prevout. + if (input.non_witness_utxo->GetHash() != tx.vin[index].prevout.hash) return false; + // If both witness and non-witness UTXO are provided, verify that they match. This check shouldn't + // matter, as the PSBT deserializer enforces only one of both is provided, and the only way both + // can be present is when they're added simultaneously by FillPSBT (in which case they always match). + // Still, check in order to not rely on callers to enforce this. + if (!input.witness_utxo.IsNull() && input.non_witness_utxo->vout[tx.vin[index].prevout.n] != input.witness_utxo) return false; utxo = input.non_witness_utxo->vout[tx.vin[index].prevout.n]; } else if (!input.witness_utxo.IsNull()) { utxo = input.witness_utxo; + // When we're taking our information from a witness UTXO, we can't verify it is actually data from + // the output being spent. This is safe in case a witness signature is produced (which includes this + // information directly in the hash), but not for non-witness signatures. Remember that we require + // a witness signature in this situation. + require_witness_sig = true; } else { return false; } MutableTransactionSignatureCreator creator(&tx, index, utxo.nValue, sighash); + sigdata.witness = false; bool sig_complete = ProduceSignature(provider, creator, utxo.scriptPubKey, sigdata); + // Verify that a witness signature was produced in case one was required. + if (require_witness_sig && !sigdata.witness) return false; input.FromSignatureData(sigdata); return sig_complete; } diff --git a/src/script/sign.h b/src/script/sign.h index 24cddda51..7ade715ee 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -223,7 +223,8 @@ struct PSBTInput // If there is a non-witness utxo, then don't add the witness one. if (non_witness_utxo) { SerializeToVector(s, PSBT_IN_NON_WITNESS_UTXO); - SerializeToVector(s, non_witness_utxo); + OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion() | SERIALIZE_TRANSACTION_NO_WITNESS); + SerializeToVector(os, non_witness_utxo); } else if (!witness_utxo.IsNull()) { SerializeToVector(s, PSBT_IN_WITNESS_UTXO); SerializeToVector(s, witness_utxo); @@ -297,13 +298,17 @@ struct PSBTInput // Do stuff based on type switch(type) { case PSBT_IN_NON_WITNESS_UTXO: + { if (non_witness_utxo) { throw std::ios_base::failure("Duplicate Key, input non-witness utxo already provided"); } else if (key.size() != 1) { throw std::ios_base::failure("Non-witness utxo key is more than one byte type"); } - UnserializeFromVector(s, non_witness_utxo); + // Set the stream to unserialize with witness since this is always a valid network transaction + OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion() & ~SERIALIZE_TRANSACTION_NO_WITNESS); + UnserializeFromVector(os, non_witness_utxo); break; + } case PSBT_IN_WITNESS_UTXO: if (!witness_utxo.IsNull()) { throw std::ios_base::failure("Duplicate Key, input witness utxo already provided"); @@ -547,7 +552,8 @@ struct PartiallySignedTransaction SerializeToVector(s, PSBT_GLOBAL_UNSIGNED_TX); // Write serialized tx to a stream - SerializeToVector(s, *tx); + OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion() | SERIALIZE_TRANSACTION_NO_WITNESS); + SerializeToVector(os, *tx); // Write the unknown things for (auto& entry : unknown) { @@ -601,7 +607,9 @@ struct PartiallySignedTransaction throw std::ios_base::failure("Global unsigned tx key is more than one byte type"); } CMutableTransaction mtx; - UnserializeFromVector(s, mtx); + // Set the stream to serialize with non-witness since this should always be non-witness + OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion() | SERIALIZE_TRANSACTION_NO_WITNESS); + UnserializeFromVector(os, mtx); tx = std::move(mtx); // Make sure that all scriptSigs and scriptWitnesses are empty for (const CTxIn& txin : tx->vin) { @@ -678,7 +686,7 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType); bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType); -/** Signs a PSBTInput */ +/** Signs a PSBTInput, verifying that all provided data matches what is being signed. */ bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, SignatureData& sigdata, int index, int sighash = 1); /** Extract signature data from a transaction input, and insert it. */ |