diff --git a/.changelog/tempo-signature-compat.md b/.changelog/tempo-signature-compat.md new file mode 100644 index 00000000..7a630e04 --- /dev/null +++ b/.changelog/tempo-signature-compat.md @@ -0,0 +1,5 @@ +--- +"mpp": patch +--- + +Allowed Tempo signature variants without primitive key metadata while safely rejecting unsupported proof signatures. diff --git a/src/protocol/methods/tempo/method.rs b/src/protocol/methods/tempo/method.rs index 269605c9..34a78fa1 100644 --- a/src/protocol/methods/tempo/method.rs +++ b/src/protocol/methods/tempo/method.rs @@ -1488,22 +1488,29 @@ where // node sizes signature gas from `keyType`/`keyData` (primitive // p256/webauthn included) and selects the keychain key via `keyId`. let (key_id, key_type, key_data) = { - let (key_id, primitive_sig) = match signed.signature() { - TempoSignature::Keychain(keychain_sig) => { + let (key_id, primitive_sig) = + if let TempoSignature::Keychain(keychain_sig) = signed.signature() { let key_id = keychain_sig.key_id(&signed.signature_hash()).map_err(|e| { VerificationError::new(format!( "Failed to recover keychain access key for simulation: {e}" )) })?; - (Some(key_id), &keychain_sig.signature) - } - TempoSignature::Primitive(primitive_sig) => (None, primitive_sig), - }; - let key_data = match primitive_sig { - PrimitiveSignature::WebAuthn(webauthn) => Some(webauthn.webauthn_data.clone()), - _ => None, + (Some(key_id), Some(&keychain_sig.signature)) + } else if let TempoSignature::Primitive(primitive_sig) = signed.signature() { + (None, Some(primitive_sig)) + } else { + (None, None) + }; + let (key_type, key_data) = if let Some(primitive_sig) = primitive_sig { + let key_data = match primitive_sig { + PrimitiveSignature::WebAuthn(webauthn) => Some(webauthn.webauthn_data.clone()), + _ => None, + }; + (Some(primitive_sig.signature_type()), key_data) + } else { + (None, None) }; - (key_id, primitive_sig.signature_type(), key_data) + (key_id, key_type, key_data) }; let mut req: TempoTransactionRequest = signed.into(); @@ -1521,7 +1528,7 @@ where req.inner.value = Some(tail.value); req.inner.input = tail.input.into(); - req.key_type = Some(key_type); + req.key_type = key_type; req.key_data = key_data; if let Some(key_id) = key_id { req.key_id = Some(key_id); diff --git a/src/protocol/methods/tempo/proof.rs b/src/protocol/methods/tempo/proof.rs index 8b23362e..5107e91e 100644 --- a/src/protocol/methods/tempo/proof.rs +++ b/src/protocol/methods/tempo/proof.rs @@ -160,12 +160,13 @@ pub fn verify_proof( Err(_) => return false, }; - match signature { - TempoSignature::Primitive(signature) => signature + if let TempoSignature::Primitive(signature) = &signature { + signature .recover_signer(&signing_hash(account, chain_id, challenge_id, realm)) - .is_ok_and(|recovered| recovered == expected_signer), - // Keychain envelopes require a separate on-chain authorization check. - TempoSignature::Keychain(_) => false, + .is_ok_and(|recovered| recovered == expected_signer) + } else { + // Non-primitive envelopes require a separate on-chain authorization check. + false } } @@ -182,11 +183,14 @@ pub fn recover_proof_signer( ) -> Result
{ let signature = parse_signature(signature_hex)?; let hash = signing_hash(account, chain_id, challenge_id, realm); - match signature { - TempoSignature::Primitive(signature) => signature.recover_signer(&hash), - TempoSignature::Keychain(signature) => signature.key_id(&hash), - } - .map_err(|_| MppError::invalid_payload("proof signature recovery failed")) + let recovered = if let TempoSignature::Primitive(signature) = &signature { + signature.recover_signer(&hash) + } else if let TempoSignature::Keychain(signature) = &signature { + signature.key_id(&hash) + } else { + return Err(MppError::invalid_payload("unsupported proof signature")); + }; + recovered.map_err(|_| MppError::invalid_payload("proof signature recovery failed")) } #[cfg(feature = "evm")]