#37814 [BC-High] Signers can crash other signers by sending an invalid `DkgPrivateShares` due to missing check before passing the payload to `SignerStateMachine::process`
Network not being able to confirm new transactions (total network shutdown)
Description
Summary
Signers do not verify received DkgPrivateShares payloads enough, allowing any signer to send such a payload with a share containing an empty bytes object, which will cause the signer to crash due to an OOB read in the wsts library.
Finding Description
When a signer receives a DkgPrivateShares message, they process the received message without doing much verification of the message:
After a few steps, this then calls wsts::dkg_private_shares which calls wsts::decrypt:
pub fn decrypt(key: &[u8; 32], data: &[u8]) -> Result<Vec<u8>, AesGcmError> {
let nonce_vec = data[..AES_GCM_NONCE_SIZE].to_vec();
let cipher_vec = data[AES_GCM_NONCE_SIZE..].to_vec();
let nonce = Nonce::from_slice(&nonce_vec);
let cipher = Aes256Gcm::new(key.into());
cipher.decrypt(nonce, cipher_vec.as_ref())
}
Here key and data are passed and taken from the DkgPrivateShares message without validation. Since there is no validation, the slicings will cause the program to crash since it accesses OOB memory.
Impact
Since DkgPrivateShares messages are accepted by any signer and not only the coordinator, this allows ANY signer in the signer set to crash all other signers, causing a complete network shutdown.
Mitigation
Consider verifying the validity of received wsts payloads either in the signer itself or the wsts library.
Proof of Concept
PoC
In this PoC I simulate sending such a malformed payload.
Please apply the following diff and execute the test with cargo test --package signer --test integration -- transaction_coordinator::sign_bitcoin_transaction --exact --show-output --ignored --nocapture. This will crash at <PATH>/.cargo/git/checkouts/wsts-deb3c7c6853b6eab/ebd7d77/src/util.rs:66:25.
diff --git a/signer/src/transaction_signer.rs b/signer/src/transaction_signer.rs
index e5aa9575..662a19c1 100644
--- a/signer/src/transaction_signer.rs
+++ b/signer/src/transaction_signer.rs
@@ -613,7 +613,25 @@ where
if signer_public_key != msg_public_key {
return Err(Error::InvalidSignature);
}
- self.relay_message(msg.txid, &msg.inner, bitcoin_chain_tip)
+
+ let mut msg_copy = msg.clone();
+
+ let out = match msg_copy.inner {
+ wsts::net::Message::DkgPrivateShares(mut msg) => {
+ for (id, second) in msg.shares.clone() {
+ for (key, bytes) in second {
+ let mut reference = msg.shares[0].1.get_mut(&key).unwrap();
+ let mut vec: Vec<u8> = Vec::new();
+ *reference = vec;
+ break;
+ }
+ }
+ wsts::net::Message::DkgPrivateShares(msg)
+ },
+ _ => {msg_copy.inner}
+ };
+
+ self.relay_message(msg.txid, &out, bitcoin_chain_tip)
.await?;
}
WstsNetMessage::DkgEndBegin(_) => {