Skip to content

Commit 2262f33

Browse files
committed
wip: Check that holder witnesses sighash types are SIGHASH_(ALL/DEFAULT)
1 parent 60fb2f4 commit 2262f33

File tree

1 file changed

+49
-6
lines changed

1 file changed

+49
-6
lines changed

lightning/src/ln/channel.rs

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use bitcoin::constants::ChainHash;
1414
use bitcoin::script::{Builder, Script, ScriptBuf, WScriptHash};
1515
use bitcoin::sighash::EcdsaSighashType;
1616
use bitcoin::transaction::{Transaction, TxIn, TxOut};
17-
use bitcoin::{Weight, Witness};
17+
use bitcoin::{TapSighashType, Weight, Witness};
1818

1919
use bitcoin::hash_types::{BlockHash, Txid};
2020
use bitcoin::hashes::sha256::Hash as Sha256;
@@ -7586,11 +7586,54 @@ where
75867586
}
75877587
}
75887588

7589-
fn verify_interactive_tx_signatures(&mut self, _witnesses: &Vec<Witness>) {
7590-
if let Some(ref mut _signing_session) = self.interactive_tx_signing_session {
7591-
// Check that sighash_all was used:
7592-
// TODO(dual_funding): Check sig for sighash
7589+
// A very basic check that anything resembling a signature in provided witnesses uses the
7590+
// SIGHASH_ALL sighash type.
7591+
//
7592+
// May have false positives for elements that have the same length as Schnorr signatures.
7593+
// If the length is 64 bytes, this doesn't matter as it's implicitly treated as SIGHASH_DEFAULT
7594+
// (= SIGHASH_ALL). If it is instead 65 bytes and the last byte could be interpreted as a real
7595+
// sighash type, then this function would return an error if it is not equal to SIGHASH_ALL.
7596+
fn verify_interactive_tx_signatures(
7597+
&mut self, witnesses: &Vec<Witness>,
7598+
) -> Result<(), APIError> {
7599+
for witness in witnesses {
7600+
for element in witness {
7601+
match element.len() {
7602+
// Possibly a DER-encoded ECDSA signature with a sighash type byte assuming low-S
7603+
70..=72 => {
7604+
if bitcoin::ecdsa::Signature::from_slice(element)
7605+
.map(|sig| matches!(sig.sighash_type, EcdsaSighashType::All))
7606+
.unwrap_or(true)
7607+
{
7608+
continue;
7609+
}
7610+
7611+
return Err(APIError::APIMisuseError {
7612+
err: format!(
7613+
"An ECDSA signature in a provided witness does not use SIGHASH_ALL"
7614+
),
7615+
});
7616+
},
7617+
// Schnorr sig + sighash type byte.
7618+
// If this were just 64 bytes, it would implicitly be SIGHASH_DEFAULT (= SIGHASH_ALL)
7619+
65 => {
7620+
if bitcoin::taproot::Signature::from_slice(element)
7621+
.map(|sig| matches!(sig.sighash_type, TapSighashType::All))
7622+
.unwrap_or(true)
7623+
{
7624+
continue;
7625+
}
7626+
7627+
return Err(APIError::APIMisuseError {
7628+
err:
7629+
format!("A Schnorr signature in a provided witness does not use SIGHASH_DEFAULT or SIGHASH_ALL")
7630+
});
7631+
},
7632+
_ => continue,
7633+
}
7634+
}
75937635
}
7636+
Ok(())
75947637
}
75957638

75967639
pub fn funding_transaction_signed<L: Deref>(
@@ -7599,7 +7642,7 @@ where
75997642
where
76007643
L::Target: Logger,
76017644
{
7602-
self.verify_interactive_tx_signatures(&witnesses);
7645+
self.verify_interactive_tx_signatures(&witnesses)?;
76037646
if let Some(ref mut signing_session) = self.interactive_tx_signing_session {
76047647
let logger = WithChannelContext::from(logger, &self.context, None);
76057648
if let Some(holder_tx_signatures) = signing_session

0 commit comments

Comments
 (0)