diff --git a/crates/claims/crates/cose/src/lib.rs b/crates/claims/crates/cose/src/lib.rs index bb3803883..da6cf3fe4 100644 --- a/crates/claims/crates/cose/src/lib.rs +++ b/crates/claims/crates/cose/src/lib.rs @@ -152,6 +152,12 @@ pub trait CosePayload { } } +impl CosePayload for [u8] { + fn payload_bytes(&self) -> Cow<[u8]> { + Cow::Borrowed(self) + } +} + pub const TYP_LABEL: Label = Label::Int(16); /// COSE payload type. diff --git a/crates/claims/crates/cose/src/signature.rs b/crates/claims/crates/cose/src/signature.rs index 9fc01d400..fc90f0e26 100644 --- a/crates/claims/crates/cose/src/signature.rs +++ b/crates/claims/crates/cose/src/signature.rs @@ -90,3 +90,68 @@ impl<'a, T: CoseSigner> CoseSigner for &'a T { T::sign(*self, payload, additional_data, tagged).await } } + +#[cfg(test)] +mod tests { + use crate::{key::CoseKeyGenerate, CosePayload, DecodedCoseSign1}; + use coset::CoseKey; + use ssi_claims_core::VerificationParameters; + + async fn sign_with(key: &CoseKey, tagged: bool) { + let bytes = b"PAYLOAD".sign(key, tagged).await.unwrap(); + let decoded: DecodedCoseSign1 = bytes.decode(tagged).unwrap(); + + assert_eq!(decoded.signing_bytes.payload.as_bytes(), b"PAYLOAD"); + + let params = VerificationParameters::from_resolver(key); + assert_eq!(decoded.verify(params).await.unwrap(), Ok(())); + } + + #[cfg(feature = "ed25519")] + #[async_std::test] + async fn sign_ed25519() { + sign_with(&CoseKey::generate_ed25519(), false).await + } + + #[cfg(feature = "ed25519")] + #[async_std::test] + async fn sign_ed25519_tagged() { + sign_with(&CoseKey::generate_ed25519(), true).await + } + + #[cfg(feature = "secp256k1")] + #[async_std::test] + async fn sign_secp256k1() { + sign_with(&CoseKey::generate_secp256k1(), false).await + } + + #[cfg(feature = "secp256k1")] + #[async_std::test] + async fn sign_secp256k1_tagged() { + sign_with(&CoseKey::generate_secp256k1(), true).await + } + + #[cfg(feature = "secp256r1")] + #[async_std::test] + async fn sign_p256() { + sign_with(&CoseKey::generate_p256(), false).await + } + + #[cfg(feature = "secp256r1")] + #[async_std::test] + async fn sign_p256_tagged() { + sign_with(&CoseKey::generate_p256(), true).await + } + + #[cfg(feature = "secp384r1")] + #[async_std::test] + async fn sign_p384() { + sign_with(&CoseKey::generate_p384(), false).await + } + + #[cfg(feature = "secp384r1")] + #[async_std::test] + async fn sign_p384_tagged() { + sign_with(&CoseKey::generate_p384(), true).await + } +} diff --git a/crates/claims/crates/cose/src/verification.rs b/crates/claims/crates/cose/src/verification.rs index 95eaf6c16..b627394ca 100644 --- a/crates/claims/crates/cose/src/verification.rs +++ b/crates/claims/crates/cose/src/verification.rs @@ -46,6 +46,8 @@ pub trait ValidateCoseHeader

{ } } +impl

ValidateCoseHeader

for () {} + impl ValidateClaims for UnsignedCoseSign1 where T: ValidateClaims + ValidateCoseHeader, diff --git a/crates/crypto/src/signature.rs b/crates/crypto/src/signature.rs index 3bf3a4200..a6424786b 100644 --- a/crates/crypto/src/signature.rs +++ b/crates/crypto/src/signature.rs @@ -13,6 +13,28 @@ impl AlgorithmInstance { #[allow(unused)] pub fn sign(&self, key: &SecretKey, signing_bytes: &[u8]) -> Result, SignatureError> { match self { + #[cfg(feature = "ed25519")] + Self::EdDSA => match key { + SecretKey::Ed25519(key) => { + use ed25519_dalek::Signer; + Ok(key.sign(signing_bytes).to_bytes().to_vec()) + } + #[allow(unreachable_patterns)] + _ => Err(SignatureError::IncompatibleKey), + }, + #[cfg(feature = "secp256k1")] + Self::ES256K => { + match key { + SecretKey::Secp256k1(key) => { + use k256::ecdsa::{signature::Signer, Signature}; + let signing_key = k256::ecdsa::SigningKey::from(key); + let signature: Signature = signing_key.try_sign(signing_bytes).unwrap(); // Uses SHA-256 by default. + Ok(signature.to_bytes().to_vec()) + } + #[allow(unreachable_patterns)] + _ => Err(SignatureError::IncompatibleKey), + } + } #[cfg(feature = "secp256r1")] Self::ES256 => { match key { diff --git a/crates/crypto/src/verification.rs b/crates/crypto/src/verification.rs index 165ce6b5b..614dc42d4 100644 --- a/crates/crypto/src/verification.rs +++ b/crates/crypto/src/verification.rs @@ -21,6 +21,30 @@ impl AlgorithmInstance { signature_bytes: &[u8], ) -> Result { match self { + #[cfg(feature = "ed25519")] + Self::EdDSA => match key { + PublicKey::Ed25519(key) => { + use ed25519_dalek::Verifier; + let signature: ed25519_dalek::Signature = signature_bytes + .try_into() + .map_err(|_| VerificationError::InvalidSignature)?; + Ok(key.verify(signing_bytes, &signature).is_ok()) + } + #[allow(unreachable_patterns)] + _ => Err(VerificationError::IncompatibleKey), + }, + #[cfg(feature = "secp256k1")] + Self::ES256K => match key { + PublicKey::Secp256k1(key) => { + use k256::ecdsa::signature::Verifier; + let verifying_key = k256::ecdsa::VerifyingKey::from(key); + let sig = k256::ecdsa::Signature::try_from(signature_bytes) + .map_err(|_| VerificationError::InvalidSignature)?; + Ok(verifying_key.verify(signing_bytes, &sig).is_ok()) + } + #[allow(unreachable_patterns)] + _ => Err(VerificationError::IncompatibleKey), + }, #[cfg(feature = "secp256r1")] Self::ES256 => match key { PublicKey::P256(key) => {