Skip to content

Commit 63f8b01

Browse files
committed
Merge #13917: Additional safety checks in PSBT signer
5df6f08 More tests of signer checks (Andrew Chow) 7c8bffd Test that a non-witness script as witness utxo is not signed (Andrew Chow) 8254e99 Additional sanity checks in SignPSBTInput (Pieter Wuille) c05712c Only wipe wrong UTXO type data if overwritten by wallet (Pieter Wuille) Pull request description: The current PSBT signing code can end up producing a non-segwit signature, while only the UTXO being spent is provided in the PSBT (as opposed to the entire transaction being spent). This may be used to trick a user to incorrectly decide a transaction has the semantics he intends to sign. Fix this by refusing to sign if there is any mismatch between the provided data and what is being signed. Tree-SHA512: b55790d79d8166e05513fc4c603a982a33710e79dc3c045060cddac6b48a1be3a28ebf8db63f988b6567b15dd27fd09bbaf48846e323c8635376ac20178956f4
2 parents 3e5424f + 5df6f08 commit 63f8b01

File tree

5 files changed

+79
-11
lines changed

5 files changed

+79
-11
lines changed

src/script/sign.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,17 +244,33 @@ bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& t
244244
input.FillSignatureData(sigdata);
245245

246246
// Get UTXO
247+
bool require_witness_sig = false;
247248
CTxOut utxo;
248249
if (input.non_witness_utxo) {
250+
// If we're taking our information from a non-witness UTXO, verify that it matches the prevout.
251+
if (input.non_witness_utxo->GetHash() != tx.vin[index].prevout.hash) return false;
252+
// If both witness and non-witness UTXO are provided, verify that they match. This check shouldn't
253+
// matter, as the PSBT deserializer enforces only one of both is provided, and the only way both
254+
// can be present is when they're added simultaneously by FillPSBT (in which case they always match).
255+
// Still, check in order to not rely on callers to enforce this.
256+
if (!input.witness_utxo.IsNull() && input.non_witness_utxo->vout[tx.vin[index].prevout.n] != input.witness_utxo) return false;
249257
utxo = input.non_witness_utxo->vout[tx.vin[index].prevout.n];
250258
} else if (!input.witness_utxo.IsNull()) {
251259
utxo = input.witness_utxo;
260+
// When we're taking our information from a witness UTXO, we can't verify it is actually data from
261+
// the output being spent. This is safe in case a witness signature is produced (which includes this
262+
// information directly in the hash), but not for non-witness signatures. Remember that we require
263+
// a witness signature in this situation.
264+
require_witness_sig = true;
252265
} else {
253266
return false;
254267
}
255268

256269
MutableTransactionSignatureCreator creator(&tx, index, utxo.nValue, sighash);
270+
sigdata.witness = false;
257271
bool sig_complete = ProduceSignature(provider, creator, utxo.scriptPubKey, sigdata);
272+
// Verify that a witness signature was produced in case one was required.
273+
if (require_witness_sig && !sigdata.witness) return false;
258274
input.FromSignatureData(sigdata);
259275
return sig_complete;
260276
}

src/script/sign.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,7 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
686686
bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType);
687687
bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType);
688688

689-
/** Signs a PSBTInput */
689+
/** Signs a PSBTInput, verifying that all provided data matches what is being signed. */
690690
bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, SignatureData& sigdata, int index, int sighash = 1);
691691

692692
/** Extract signature data from a transaction input, and insert it. */

src/wallet/rpcwallet.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4504,10 +4504,11 @@ bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const C
45044504

45054505
// If we don't know about this input, skip it and let someone else deal with it
45064506
const uint256& txhash = txin.prevout.hash;
4507-
const auto& it = pwallet->mapWallet.find(txhash);
4507+
const auto it = pwallet->mapWallet.find(txhash);
45084508
if (it != pwallet->mapWallet.end()) {
45094509
const CWalletTx& wtx = it->second;
45104510
CTxOut utxo = wtx.tx->vout[txin.prevout.n];
4511+
// Update both UTXOs from the wallet.
45114512
input.non_witness_utxo = wtx.tx;
45124513
input.witness_utxo = utxo;
45134514
}
@@ -4524,11 +4525,13 @@ bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const C
45244525
complete &= SignPSBTInput(PublicOnlySigningProvider(pwallet), *psbtx.tx, input, sigdata, i, sighash_type);
45254526
}
45264527

4527-
// Drop the unnecessary UTXO
4528-
if (sigdata.witness) {
4529-
input.non_witness_utxo = nullptr;
4530-
} else {
4531-
input.witness_utxo.SetNull();
4528+
if (it != pwallet->mapWallet.end()) {
4529+
// Drop the unnecessary UTXO if we added both from the wallet.
4530+
if (sigdata.witness) {
4531+
input.non_witness_utxo = nullptr;
4532+
} else {
4533+
input.witness_utxo.SetNull();
4534+
}
45324535
}
45334536

45344537
// Get public key paths

0 commit comments

Comments
 (0)