isideload_cryptographic_message_syntax/
signing.rs1use {
8 crate::{
9 CmsError,
10 asn1::rfc5652::{
11 CertificateChoices, CertificateSet, CmsVersion, DigestAlgorithmIdentifier,
12 DigestAlgorithmIdentifiers, EncapsulatedContentInfo, IssuerAndSerialNumber,
13 OID_CONTENT_TYPE, OID_ID_DATA, OID_ID_SIGNED_DATA, OID_MESSAGE_DIGEST,
14 OID_SIGNING_TIME, SignatureValue, SignedAttributes, SignedData, SignerIdentifier,
15 SignerInfo, SignerInfos,
16 },
17 },
18 bcder::{
19 Captured, Mode, OctetString, Oid,
20 encode::{PrimitiveContent, Values},
21 },
22 bytes::Bytes,
23 std::collections::HashSet,
24 x509_certificate::{
25 CapturedX509Certificate, DigestAlgorithm, KeyInfoSigner, SignatureAlgorithm,
26 asn1time::UtcTime,
27 rfc5652::{Attribute, AttributeValue},
28 },
29};
30
31#[derive(Clone)]
36pub struct SignerBuilder<'a> {
37 signing_key: &'a dyn KeyInfoSigner,
39
40 signer_identifier: SignerIdentifier,
43
44 signing_certificate: Option<CapturedX509Certificate>,
46
47 digest_algorithm: DigestAlgorithm,
49
50 message_id_content: Option<Vec<u8>>,
53
54 content_type: Oid,
59
60 extra_signed_attributes: Vec<Attribute>,
62}
63
64impl<'a> SignerBuilder<'a> {
65 pub fn new(
69 signing_key: &'a dyn KeyInfoSigner,
70 signing_certificate: CapturedX509Certificate,
71 ) -> Self {
72 Self {
73 signing_key,
74 signer_identifier: SignerIdentifier::IssuerAndSerialNumber(IssuerAndSerialNumber {
75 issuer: signing_certificate.issuer_name().clone(),
76 serial_number: signing_certificate.serial_number_asn1().clone(),
77 }),
78 signing_certificate: Some(signing_certificate),
79 digest_algorithm: DigestAlgorithm::Sha256,
80 message_id_content: None,
81 content_type: Oid(Bytes::copy_from_slice(OID_ID_DATA.as_ref())),
82 extra_signed_attributes: Vec::new(),
83 }
84 }
85
86 pub fn new_with_signer_identifier(
91 signing_key: &'a dyn KeyInfoSigner,
92 signer_identifier: SignerIdentifier,
93 ) -> Self {
94 Self {
95 signing_key,
96 signer_identifier,
97 signing_certificate: None,
98 digest_algorithm: DigestAlgorithm::Sha256,
99 message_id_content: None,
100 content_type: Oid(Bytes::copy_from_slice(OID_ID_DATA.as_ref())),
101 extra_signed_attributes: Vec::new(),
102 }
103 }
104
105 pub fn signature_algorithm(&self) -> Result<SignatureAlgorithm, CmsError> {
107 Ok(self.signing_key.signature_algorithm()?)
108 }
109
110 #[must_use]
117 pub fn message_id_content(mut self, data: Vec<u8>) -> Self {
118 self.message_id_content = Some(data);
119 self
120 }
121
122 #[must_use]
124 pub fn content_type(mut self, oid: Oid) -> Self {
125 self.content_type = oid;
126 self
127 }
128
129 #[must_use]
131 pub fn signed_attribute(mut self, typ: Oid, values: Vec<AttributeValue>) -> Self {
132 self.extra_signed_attributes.push(Attribute { typ, values });
133 self
134 }
135
136 #[must_use]
141 pub fn signed_attribute_octet_string(self, typ: Oid, data: &[u8]) -> Self {
142 self.signed_attribute(
143 typ,
144 vec![AttributeValue::new(Captured::from_values(
145 Mode::Der,
146 data.encode_ref(),
147 ))],
148 )
149 }
150}
151
152enum SignedContent {
154 None,
156
157 Inline(Vec<u8>),
159
160 External(Vec<u8>),
164}
165
166pub struct SignedDataBuilder<'a> {
173 signed_content: SignedContent,
175
176 signers: Vec<SignerBuilder<'a>>,
178
179 certificates: Vec<CapturedX509Certificate>,
181
182 content_type: Oid,
188
189 signing_time: UtcTime,
193}
194
195impl Default for SignedDataBuilder<'_> {
196 fn default() -> Self {
197 Self {
198 signed_content: SignedContent::None,
199 signers: vec![],
200 certificates: vec![],
201 content_type: Oid(OID_ID_SIGNED_DATA.as_ref().into()),
202 signing_time: UtcTime::now(),
203 }
204 }
205}
206
207impl<'a> SignedDataBuilder<'a> {
208 #[must_use]
210 pub fn content_inline(mut self, content: Vec<u8>) -> Self {
211 self.signed_content = SignedContent::Inline(content);
212 self
213 }
214
215 #[must_use]
221 pub fn content_external(mut self, content: Vec<u8>) -> Self {
222 self.signed_content = SignedContent::External(content);
223 self
224 }
225
226 #[must_use]
231 pub fn signer(mut self, signer: SignerBuilder<'a>) -> Self {
232 self.signers.push(signer);
233 self
234 }
235
236 #[must_use]
238 pub fn certificate(mut self, cert: CapturedX509Certificate) -> Self {
239 if !self.certificates.iter().any(|x| x == &cert) {
240 self.certificates.push(cert);
241 }
242
243 self
244 }
245
246 #[must_use]
248 pub fn certificates(mut self, certs: impl Iterator<Item = CapturedX509Certificate>) -> Self {
249 for cert in certs {
250 if !self.certificates.iter().any(|x| x == &cert) {
251 self.certificates.push(cert);
252 }
253 }
254
255 self
256 }
257
258 #[must_use]
260 pub fn content_type(mut self, oid: Oid) -> Self {
261 self.content_type = oid;
262 self
263 }
264
265 #[must_use]
269 pub fn signing_time(mut self, time: UtcTime) -> Self {
270 self.signing_time = time;
271 self
272 }
273
274 pub fn build_signed_data(&self) -> Result<SignedData, CmsError> {
276 let mut signer_infos = SignerInfos::default();
277 let mut seen_digest_algorithms = HashSet::new();
278 let mut seen_certificates = self.certificates.clone();
279
280 for signer in &self.signers {
281 seen_digest_algorithms.insert(signer.digest_algorithm);
282
283 if let Some(signing_certificate) = &signer.signing_certificate {
284 if !seen_certificates.iter().any(|x| x == signing_certificate) {
285 seen_certificates.push(signing_certificate.clone());
286 }
287 }
288
289 let version = CmsVersion::V1;
290 let digest_algorithm = DigestAlgorithmIdentifier {
291 algorithm: signer.digest_algorithm.into(),
292 parameters: None,
293 };
294
295 let mut hasher = signer.digest_algorithm.digester();
301 if let Some(content) = &signer.message_id_content {
302 hasher.update(content);
303 } else {
304 match &self.signed_content {
305 SignedContent::None => {}
306 SignedContent::Inline(content) | SignedContent::External(content) => {
307 hasher.update(content)
308 }
309 }
310 }
311 let digest = hasher.finish();
312
313 let mut signed_attributes = SignedAttributes::default();
314
315 signed_attributes.push(Attribute {
317 typ: Oid(Bytes::copy_from_slice(OID_CONTENT_TYPE.as_ref())),
318 values: vec![AttributeValue::new(Captured::from_values(
319 Mode::Der,
320 signer.content_type.encode_ref(),
321 ))],
322 });
323
324 signed_attributes.push(Attribute {
326 typ: Oid(Bytes::copy_from_slice(OID_MESSAGE_DIGEST.as_ref())),
327 values: vec![AttributeValue::new(Captured::from_values(
328 Mode::Der,
329 digest.as_ref().encode(),
330 ))],
331 });
332
333 signed_attributes.push(Attribute {
335 typ: Oid(Bytes::copy_from_slice(OID_SIGNING_TIME.as_ref())),
336 values: vec![AttributeValue::new(Captured::from_values(
337 Mode::Der,
338 self.signing_time.clone().encode(),
339 ))],
340 });
341
342 signed_attributes.extend(signer.extra_signed_attributes.iter().cloned());
343
344 let signed_attributes = signed_attributes.as_sorted()?;
348
349 let signed_attributes = Some(signed_attributes);
350
351 let signature_algorithm = signer.signature_algorithm()?.into();
352
353 let mut signer_info = SignerInfo {
357 version,
358 sid: signer.signer_identifier.clone(),
359 digest_algorithm,
360 signed_attributes,
361 signature_algorithm,
362 signature: SignatureValue::new(Bytes::copy_from_slice(&[])),
363 unsigned_attributes: None,
364 signed_attributes_data: None,
365 };
366
367 let signed_content = signer_info
371 .signed_attributes_digested_content()?
372 .expect("presence of signed attributes should ensure this is Some(T)");
373
374 let signature = signer.signing_key.try_sign(&signed_content)?;
375 let signature_algorithm = signer.signing_key.signature_algorithm()?;
376
377 signer_info.signature = SignatureValue::new(Bytes::from(signature.clone()));
378 signer_info.signature_algorithm = signature_algorithm.into();
379
380 signer_infos.push(signer_info);
381 }
382
383 let mut digest_algorithms = DigestAlgorithmIdentifiers::default();
384 digest_algorithms.extend(seen_digest_algorithms.into_iter().map(|alg| {
385 DigestAlgorithmIdentifier {
386 algorithm: alg.into(),
387 parameters: None,
388 }
389 }));
390
391 seen_certificates.sort_by(|a, b| a.compare_issuer(b));
395
396 let mut certificates = CertificateSet::default();
397 certificates.extend(
398 seen_certificates
399 .into_iter()
400 .map(|cert| CertificateChoices::Certificate(Box::new(cert.into()))),
401 );
402
403 let signed_data = SignedData {
407 version: CmsVersion::V1,
408 digest_algorithms,
409 content_info: EncapsulatedContentInfo {
410 content_type: self.content_type.clone(),
411 content: match &self.signed_content {
412 SignedContent::None | SignedContent::External(_) => None,
413 SignedContent::Inline(content) => {
414 Some(OctetString::new(Bytes::copy_from_slice(content)))
415 }
416 },
417 },
418 certificates: if certificates.is_empty() {
419 None
420 } else {
421 Some(certificates)
422 },
423 crls: None,
424 signer_infos,
425 };
426
427 Ok(signed_data)
428 }
429
430 pub fn build_der(&self) -> Result<Vec<u8>, CmsError> {
436 let signed_data = self.build_signed_data()?;
437
438 let mut ber = Vec::new();
439 signed_data
440 .encode_ref()
441 .write_encoded(Mode::Der, &mut ber)?;
442
443 Ok(ber)
444 }
445}