use alloc::vec::Vec;
use crate::claims::{Claims, ProtectedHeaders, ValidationParams};
use crate::codec::{self, Sign1Layer};
use crate::error::{BuildError, VerifyError};
use crate::traits::{Signer, Verifier};
use crate::types::{ContentType, CoseBytes, ExternalAad, KeyId, Signature};
#[derive(Debug, Clone)]
pub struct SignParams<'a> {
pub content_type: ContentType,
pub payload: &'a [u8],
pub claims: Option<Claims>,
pub external_aad: ExternalAad,
}
pub async fn build_signed<S: Signer>(
params: &SignParams<'_>,
signer: &S,
) -> Result<CoseBytes, BuildError> {
build_signed_with_headers(params, &ProtectedHeaders::default(), signer).await
}
pub async fn build_signed_with_headers<S: Signer>(
params: &SignParams<'_>,
protected_headers: &ProtectedHeaders,
signer: &S,
) -> Result<CoseBytes, BuildError> {
if let Some(claims) = ¶ms.claims {
if let Some(sender) = &claims.sender_key_id
&& sender != signer.key_id()
{
return Err(BuildError::SenderKeyMismatch);
}
if let Some(k) = &claims.response_key_id
&& k.as_catalog_name().is_none()
{
return Err(BuildError::ResponseKeyNotText);
}
}
let protected = codec::encode_sign1_protected_bare_with_headers(
signer.algorithm(),
signer.key_id(),
¶ms.content_type,
params.claims.as_ref(),
Some(protected_headers),
)
.map_err(|codec::CodecError| BuildError::Codec)?;
let sig_structure =
codec::sig_structure(&protected, params.external_aad.as_bytes(), params.payload)
.map_err(|codec::CodecError| BuildError::Codec)?;
let signature = signer.sign(&sig_structure).await?;
codec::assemble_sign1(&protected, params.payload, signature.as_bytes())
.map(CoseBytes::new)
.map_err(|codec::CodecError| BuildError::Codec)
}
#[derive(Debug, Clone)]
pub struct VerifySignedParams<'a> {
pub external_aad: ExternalAad,
pub validation: Option<&'a ValidationParams>,
}
#[derive(Debug, Clone)]
pub struct VerifiedSigned {
pub content_type: ContentType,
pub payload: Vec<u8>,
pub claims: Option<Claims>,
pub protected_headers: ProtectedHeaders,
pub signer_key_id: KeyId,
}
pub async fn verify_signed<V: Verifier>(
bytes: &[u8],
verifier: &V,
params: &VerifySignedParams<'_>,
) -> Result<VerifiedSigned, VerifyError> {
let decoded = codec::decode_sign1_strict(bytes, Sign1Layer::Bare)?;
let sig_structure = codec::sig_structure(
&decoded.protected,
params.external_aad.as_bytes(),
&decoded.payload,
)
.map_err(|codec::CodecError| VerifyError::SignatureInvalid)?;
let signature = Signature::from_bytes(decoded.signature.clone())
.map_err(|_| VerifyError::SignatureInvalid)?;
verifier
.verify(
&decoded.kid,
decoded.algorithm,
&decoded.protected_headers,
&sig_structure,
&signature,
)
.await?;
match (params.validation, &decoded.claims) {
(Some(validation), Some(claims)) => {
if let Some(sender) = &claims.sender_key_id
&& sender != &decoded.kid
{
return Err(VerifyError::SenderKeyMismatch);
}
claims.validate(validation)?;
}
(None, None) => {}
_ => return Err(VerifyError::ClaimsPresenceMismatch),
}
let Some(content_type) = decoded.content_type else {
return Err(VerifyError::Decode(
crate::error::DecodeError::MissingHeader {
label: crate::label::HDR_CONTENT_TYPE,
},
));
};
Ok(VerifiedSigned {
content_type,
payload: decoded.payload,
claims: decoded.claims,
protected_headers: decoded.protected_headers,
signer_key_id: decoded.kid,
})
}