Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changelog/tempo-signature-compat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"mpp": patch
---

Allowed Tempo signature variants without primitive key metadata while safely rejecting unsupported proof signatures.
29 changes: 18 additions & 11 deletions src/protocol/methods/tempo/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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);
Expand Down
24 changes: 14 additions & 10 deletions src/protocol/methods/tempo/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}

Expand All @@ -182,11 +183,14 @@ pub fn recover_proof_signer(
) -> Result<Address, crate::error::MppError> {
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")]
Expand Down
Loading