From c0e10ea3c78b4e7e5c8bc2628272917323510d72 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 15 Nov 2023 12:11:38 -0500 Subject: [PATCH] Add domain restricted signature API to identities. --- src/lib.rs | 7 +++++++ src/p384.rs | 14 ++++++++++++++ src/x25519.rs | 15 +++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 513299f..9086197 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,6 +52,9 @@ pub trait Identity: /// Verify a signature made by this identity's corresponding secret. fn verify_signature(&self, data: &[u8], signature: &[u8]) -> bool; + + /// Verify a signature with a domain restriction parameter. + fn verify_domain_restricted_signature(&self, domain: &[u8], data: &[u8], signature: &[u8]) -> bool; } /// Secret keys that correspond to a public Identity. @@ -71,6 +74,10 @@ pub trait IdentitySecret: Sync + Send + Clone + PartialEq + Eq + Serialize + Des /// Cryptographically sign a message with this identity. fn sign(&self, data: &[u8]) -> Self::Signature; + + /// Cryptographically sign a message with this identity. + /// This version takes a domain parameter that helps defend against signature misuse + fn sign_domain_restricted(&self, domain: &[u8], data: &[u8]) -> Self::Signature; } mod base24; diff --git a/src/p384.rs b/src/p384.rs index 9ccab4e..9eb9650 100644 --- a/src/p384.rs +++ b/src/p384.rs @@ -611,6 +611,15 @@ impl crate::Identity for Identity { false } } + + #[inline(always)] + fn verify_domain_restricted_signature(&self, domain: &[u8], data: &[u8], signature: &[u8]) -> bool { + if let Ok(sig) = signature.try_into() { + self.ecdsa.verify(domain, data, sig) + } else { + false + } + } } /// Secret NIST P-384 identity (also contains public). @@ -777,6 +786,11 @@ impl crate::IdentitySecret for IdentitySecret { fn sign(&self, data: &[u8]) -> Self::Signature { self.ecdsa.sign_raw(data) } + + #[inline(always)] + fn sign_domain_restricted(&self, domain: &[u8], data: &[u8]) -> Self::Signature { + self.ecdsa.sign(domain, data) + } } impl ToFromBytes for IdentitySecret { diff --git a/src/x25519.rs b/src/x25519.rs index 47eafbf..9dec66d 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -292,6 +292,11 @@ impl crate::Identity for Identity { fn verify_signature(&self, data: &[u8], signature: &[u8]) -> bool { ed25519_verify(&self.eddsa, signature, data) } + + #[inline(always)] + fn verify_domain_restricted_signature(&self, domain: &[u8], data: &[u8], signature: &[u8]) -> bool { + ed25519_verify_domain_restricted(&self.eddsa, signature, domain, data) + } } impl Serialize for Identity { @@ -424,6 +429,16 @@ impl crate::IdentitySecret for IdentitySecret { fn sign(&self, data: &[u8]) -> Self::Signature { self.eddsa.sign_zt(data) } + + #[inline(always)] + fn sign_domain_restricted(&self, domain: &[u8], data: &[u8]) -> Self::Signature { + // Note: this identity type returns a 96-byte signature for backward compatibility with old ZT, but + // the last 32 bytes of this signature aren't actually used. Since the domain restricted version is + // not used with old ZT, just leave these bytes zero. Only the first 64 bytes matter. + let mut tmp = [0u8; 96]; + tmp[..64].copy_from_slice(&self.eddsa.sign_domain_restricted(domain, data)); + tmp + } } #[derive(Serialize, Deserialize, Zeroize, ZeroizeOnDrop)]