1use alloc::vec::Vec;
9
10use crate::claims::{Claims, ProtectedHeaders, ValidationParams};
11use crate::codec::{self, Sign1Layer};
12use crate::error::{BuildError, VerifyError};
13use crate::traits::{Signer, Verifier};
14use crate::types::{ContentType, CoseBytes, ExternalAad, KeyId, Signature};
15
16#[derive(Debug, Clone)]
18pub struct SignParams<'a> {
19 pub content_type: ContentType,
21 pub payload: &'a [u8],
24 pub claims: Option<Claims>,
26 pub external_aad: ExternalAad,
28}
29
30pub async fn build_signed<S: Signer>(
37 params: &SignParams<'_>,
38 signer: &S,
39) -> Result<CoseBytes, BuildError> {
40 build_signed_with_headers(params, &ProtectedHeaders::default(), signer).await
41}
42
43pub async fn build_signed_with_headers<S: Signer>(
50 params: &SignParams<'_>,
51 protected_headers: &ProtectedHeaders,
52 signer: &S,
53) -> Result<CoseBytes, BuildError> {
54 if let Some(claims) = ¶ms.claims {
55 if let Some(sender) = &claims.sender_key_id
56 && sender != signer.key_id()
57 {
58 return Err(BuildError::SenderKeyMismatch);
59 }
60 if let Some(k) = &claims.response_key_id
61 && k.as_catalog_name().is_none()
62 {
63 return Err(BuildError::ResponseKeyNotText);
64 }
65 }
66 let protected = codec::encode_sign1_protected_bare_with_headers(
67 signer.algorithm(),
68 signer.key_id(),
69 ¶ms.content_type,
70 params.claims.as_ref(),
71 Some(protected_headers),
72 )
73 .map_err(|codec::CodecError| BuildError::Codec)?;
74 let sig_structure =
75 codec::sig_structure(&protected, params.external_aad.as_bytes(), params.payload)
76 .map_err(|codec::CodecError| BuildError::Codec)?;
77 let signature = signer.sign(&sig_structure).await?;
78 codec::assemble_sign1(&protected, params.payload, signature.as_bytes())
79 .map(CoseBytes::new)
80 .map_err(|codec::CodecError| BuildError::Codec)
81}
82
83#[derive(Debug, Clone)]
85pub struct VerifySignedParams<'a> {
86 pub external_aad: ExternalAad,
88 pub validation: Option<&'a ValidationParams>,
91}
92
93#[derive(Debug, Clone)]
95pub struct VerifiedSigned {
96 pub content_type: ContentType,
98 pub payload: Vec<u8>,
100 pub claims: Option<Claims>,
102 pub protected_headers: ProtectedHeaders,
104 pub signer_key_id: KeyId,
106}
107
108pub async fn verify_signed<V: Verifier>(
119 bytes: &[u8],
120 verifier: &V,
121 params: &VerifySignedParams<'_>,
122) -> Result<VerifiedSigned, VerifyError> {
123 let decoded = codec::decode_sign1_strict(bytes, Sign1Layer::Bare)?;
124
125 let sig_structure = codec::sig_structure(
126 &decoded.protected,
127 params.external_aad.as_bytes(),
128 &decoded.payload,
129 )
130 .map_err(|codec::CodecError| VerifyError::SignatureInvalid)?;
131 let signature = Signature::from_bytes(decoded.signature.clone())
132 .map_err(|_| VerifyError::SignatureInvalid)?;
133 verifier
134 .verify(
135 &decoded.kid,
136 decoded.algorithm,
137 &decoded.protected_headers,
138 &sig_structure,
139 &signature,
140 )
141 .await?;
142
143 match (params.validation, &decoded.claims) {
144 (Some(validation), Some(claims)) => {
145 if let Some(sender) = &claims.sender_key_id
146 && sender != &decoded.kid
147 {
148 return Err(VerifyError::SenderKeyMismatch);
149 }
150 claims.validate(validation)?;
151 }
152 (None, None) => {}
153 _ => return Err(VerifyError::ClaimsPresenceMismatch),
154 }
155
156 let Some(content_type) = decoded.content_type else {
157 return Err(VerifyError::Decode(
159 crate::error::DecodeError::MissingHeader {
160 label: crate::label::HDR_CONTENT_TYPE,
161 },
162 ));
163 };
164 Ok(VerifiedSigned {
165 content_type,
166 payload: decoded.payload,
167 claims: decoded.claims,
168 protected_headers: decoded.protected_headers,
169 signer_key_id: decoded.kid,
170 })
171}