1use std::time::{Duration, SystemTime, UNIX_EPOCH};
2
3use bitflags::bitflags;
4use serde_json::Value;
5
6use crate::bridge;
7use crate::certificate::Certificate;
8use crate::error::{Result, SecurityError};
9use crate::identity::Identity;
10use crate::policy::Policy;
11
12bitflags! {
13 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14 pub struct CmsSignedAttributes: u32 {
15 const NONE = 0;
16 const SMIME_CAPABILITIES = 0x0001;
17 const SMIME_ENCRYPTION_KEY_PREFS = 0x0002;
18 const SMIME_MS_ENCRYPTION_KEY_PREFS = 0x0004;
19 const SIGNING_TIME = 0x0008;
20 const APPLE_CODESIGNING_HASH_AGILITY = 0x0010;
21 const APPLE_CODESIGNING_HASH_AGILITY_V2 = 0x0020;
22 const APPLE_EXPIRATION_TIME = 0x0040;
23 }
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
27#[repr(u32)]
28pub enum CmsCertificateChainMode {
29 None = 0,
30 SignerOnly = 1,
31 Chain = 2,
32 ChainWithRoot = 3,
33 ChainWithRootOrFail = 4,
34}
35
36impl CmsCertificateChainMode {
37 fn from_raw(raw: u32) -> Result<Self> {
38 match raw {
39 0 => Ok(Self::None),
40 1 => Ok(Self::SignerOnly),
41 2 => Ok(Self::Chain),
42 3 => Ok(Self::ChainWithRoot),
43 4 => Ok(Self::ChainWithRootOrFail),
44 _ => Err(SecurityError::InvalidArgument(format!(
45 "unexpected CMS certificate chain mode: {raw}"
46 ))),
47 }
48 }
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
52pub enum CmsDigestAlgorithm {
53 Sha1,
54 Sha256,
55}
56
57impl CmsDigestAlgorithm {
58 const fn as_bridge_name(self) -> &'static str {
59 match self {
60 Self::Sha1 => "sha1",
61 Self::Sha256 => "sha256",
62 }
63 }
64}
65
66#[derive(Debug)]
67pub struct CmsDecoder {
68 handle: bridge::Handle,
69}
70
71impl CmsDecoder {
72 fn from_handle(handle: bridge::Handle) -> Self {
73 Self { handle }
74 }
75
76 pub fn type_id() -> usize {
77 unsafe { bridge::security_cms_decoder_get_type_id() }
78 }
79
80 pub fn update_message(&mut self, data: &[u8]) -> Result<()> {
81 let mut error = std::ptr::null_mut();
82 let status = unsafe {
83 bridge::security_cms_decoder_update_message(
84 self.handle.as_ptr(),
85 data.as_ptr().cast(),
86 bridge::len_to_isize(data.len())?,
87 &mut error,
88 )
89 };
90 bridge::status_result("security_cms_decoder_update_message", status, error)
91 }
92
93 pub fn finalize_message(&mut self) -> Result<()> {
94 let mut error = std::ptr::null_mut();
95 let status = unsafe {
96 bridge::security_cms_decoder_finalize_message(self.handle.as_ptr(), &mut error)
97 };
98 bridge::status_result("security_cms_decoder_finalize_message", status, error)
99 }
100
101 pub fn set_detached_content(&mut self, data: &[u8]) -> Result<()> {
102 let mut error = std::ptr::null_mut();
103 let status = unsafe {
104 bridge::security_cms_decoder_set_detached_content(
105 self.handle.as_ptr(),
106 data.as_ptr().cast(),
107 bridge::len_to_isize(data.len())?,
108 &mut error,
109 )
110 };
111 bridge::status_result("security_cms_decoder_set_detached_content", status, error)
112 }
113
114 pub fn detached_content(&self) -> Result<Option<Vec<u8>>> {
115 let mut status = 0;
116 let mut error = std::ptr::null_mut();
117 let raw = unsafe {
118 bridge::security_cms_decoder_copy_detached_content(
119 self.handle.as_ptr(),
120 &mut status,
121 &mut error,
122 )
123 };
124 if status != 0 {
125 return Err(bridge::status_error(
126 "security_cms_decoder_copy_detached_content",
127 status,
128 error,
129 )?);
130 }
131 bridge::optional_data(raw)
132 }
133
134 pub fn num_signers(&self) -> Result<usize> {
135 let mut status = 0;
136 let mut error = std::ptr::null_mut();
137 let count = unsafe {
138 bridge::security_cms_decoder_get_num_signers(
139 self.handle.as_ptr(),
140 &mut status,
141 &mut error,
142 )
143 };
144 if status != 0 {
145 return Err(bridge::status_error(
146 "security_cms_decoder_get_num_signers",
147 status,
148 error,
149 )?);
150 }
151 usize::try_from(count).map_err(|_| {
152 SecurityError::Serialization("negative signer count from bridge".to_owned())
153 })
154 }
155
156 pub fn signer_status(
157 &self,
158 signer_index: usize,
159 policy: Option<&Policy>,
160 evaluate_sec_trust: bool,
161 ) -> Result<Value> {
162 let mut status = 0;
163 let mut error = std::ptr::null_mut();
164 let raw = unsafe {
165 bridge::security_cms_decoder_copy_signer_status(
166 self.handle.as_ptr(),
167 bridge::len_to_isize(signer_index)?,
168 policy.map_or(std::ptr::null_mut(), |value| value.handle().as_ptr()),
169 evaluate_sec_trust,
170 &mut status,
171 &mut error,
172 )
173 };
174 bridge::required_json(
175 "security_cms_decoder_copy_signer_status",
176 raw,
177 status,
178 error,
179 )
180 }
181
182 pub fn signer_email_address(&self, signer_index: usize) -> Result<Option<String>> {
183 let mut status = 0;
184 let mut error = std::ptr::null_mut();
185 let raw = unsafe {
186 bridge::security_cms_decoder_copy_signer_email_address(
187 self.handle.as_ptr(),
188 bridge::len_to_isize(signer_index)?,
189 &mut status,
190 &mut error,
191 )
192 };
193 if raw.is_null() && status == 0 {
194 Ok(None)
195 } else {
196 bridge::required_string(
197 "security_cms_decoder_copy_signer_email_address",
198 raw,
199 status,
200 error,
201 )
202 .map(Some)
203 }
204 }
205
206 pub fn signer_certificate(&self, signer_index: usize) -> Result<Certificate> {
207 let mut status = 0;
208 let mut error = std::ptr::null_mut();
209 let raw = unsafe {
210 bridge::security_cms_decoder_copy_signer_cert(
211 self.handle.as_ptr(),
212 bridge::len_to_isize(signer_index)?,
213 &mut status,
214 &mut error,
215 )
216 };
217 bridge::required_handle("security_cms_decoder_copy_signer_cert", raw, status, error)
218 .map(Certificate::from_handle)
219 }
220
221 pub fn is_content_encrypted(&self) -> Result<bool> {
222 let mut status = 0;
223 let mut error = std::ptr::null_mut();
224 let encrypted = unsafe {
225 bridge::security_cms_decoder_is_content_encrypted(
226 self.handle.as_ptr(),
227 &mut status,
228 &mut error,
229 )
230 };
231 if status != 0 {
232 return Err(bridge::status_error(
233 "security_cms_decoder_is_content_encrypted",
234 status,
235 error,
236 )?);
237 }
238 Ok(encrypted)
239 }
240
241 pub fn encapsulated_content_type(&self) -> Result<Option<Vec<u8>>> {
242 let mut status = 0;
243 let mut error = std::ptr::null_mut();
244 let raw = unsafe {
245 bridge::security_cms_decoder_copy_encapsulated_content_type(
246 self.handle.as_ptr(),
247 &mut status,
248 &mut error,
249 )
250 };
251 if status != 0 {
252 return Err(bridge::status_error(
253 "security_cms_decoder_copy_encapsulated_content_type",
254 status,
255 error,
256 )?);
257 }
258 bridge::optional_data(raw)
259 }
260
261 pub fn content(&self) -> Result<Option<Vec<u8>>> {
262 let mut status = 0;
263 let mut error = std::ptr::null_mut();
264 let raw = unsafe {
265 bridge::security_cms_decoder_copy_content(self.handle.as_ptr(), &mut status, &mut error)
266 };
267 if status != 0 {
268 return Err(bridge::status_error(
269 "security_cms_decoder_copy_content",
270 status,
271 error,
272 )?);
273 }
274 bridge::optional_data(raw)
275 }
276
277 pub fn signer_signing_time(&self, signer_index: usize) -> Result<Option<SystemTime>> {
278 decode_optional_cms_date("security_cms_decoder_copy_signer_signing_time", unsafe {
279 let mut status = 0;
280 let mut error = std::ptr::null_mut();
281 let raw = bridge::security_cms_decoder_copy_signer_signing_time(
282 self.handle.as_ptr(),
283 bridge::len_to_isize(signer_index)?,
284 &mut status,
285 &mut error,
286 );
287 (raw, status, error)
288 })
289 }
290
291 pub fn signer_timestamp(&self, signer_index: usize) -> Result<Option<SystemTime>> {
292 decode_optional_cms_date("security_cms_decoder_copy_signer_timestamp", unsafe {
293 let mut status = 0;
294 let mut error = std::ptr::null_mut();
295 let raw = bridge::security_cms_decoder_copy_signer_timestamp(
296 self.handle.as_ptr(),
297 bridge::len_to_isize(signer_index)?,
298 &mut status,
299 &mut error,
300 );
301 (raw, status, error)
302 })
303 }
304
305 pub fn signer_timestamp_with_policy(
306 &self,
307 policy: Option<&Policy>,
308 signer_index: usize,
309 ) -> Result<Option<SystemTime>> {
310 decode_optional_cms_date(
311 "security_cms_decoder_copy_signer_timestamp_with_policy",
312 unsafe {
313 let mut status = 0;
314 let mut error = std::ptr::null_mut();
315 let raw = bridge::security_cms_decoder_copy_signer_timestamp_with_policy(
316 self.handle.as_ptr(),
317 policy.map_or(std::ptr::null_mut(), |value| value.handle().as_ptr()),
318 bridge::len_to_isize(signer_index)?,
319 &mut status,
320 &mut error,
321 );
322 (raw, status, error)
323 },
324 )
325 }
326
327 pub fn signer_timestamp_certificates(&self, signer_index: usize) -> Result<Value> {
328 let mut status = 0;
329 let mut error = std::ptr::null_mut();
330 let raw = unsafe {
331 bridge::security_cms_decoder_copy_signer_timestamp_certificates(
332 self.handle.as_ptr(),
333 bridge::len_to_isize(signer_index)?,
334 &mut status,
335 &mut error,
336 )
337 };
338 bridge::required_json(
339 "security_cms_decoder_copy_signer_timestamp_certificates",
340 raw,
341 status,
342 error,
343 )
344 }
345
346 pub fn all_certificates(&self) -> Result<Vec<Certificate>> {
347 let mut status = 0;
348 let mut error = std::ptr::null_mut();
349 let raw = unsafe {
350 bridge::security_cms_decode_all_certificates(
351 std::ptr::null(),
352 0,
353 &mut status,
354 &mut error,
355 )
356 };
357 let _ = raw;
358 Err(SecurityError::InvalidArgument(
359 "CmsDecoder::all_certificates is not available; use Cms::decode_all_certificates"
360 .to_owned(),
361 ))
362 }
363}
364
365#[derive(Debug)]
366pub struct CmsEncoder {
367 handle: bridge::Handle,
368}
369
370impl CmsEncoder {
371 fn from_handle(handle: bridge::Handle) -> Self {
372 Self { handle }
373 }
374
375 pub fn type_id() -> usize {
376 unsafe { bridge::security_cms_encoder_get_type_id() }
377 }
378
379 pub fn set_signer_algorithm(&mut self, algorithm: CmsDigestAlgorithm) -> Result<()> {
380 let algorithm = bridge::cstring(algorithm.as_bridge_name())?;
381 let mut error = std::ptr::null_mut();
382 let status = unsafe {
383 bridge::security_cms_encoder_set_signer_algorithm(
384 self.handle.as_ptr(),
385 algorithm.as_ptr(),
386 &mut error,
387 )
388 };
389 bridge::status_result("security_cms_encoder_set_signer_algorithm", status, error)
390 }
391
392 pub fn add_signers(&mut self, signers: &[Identity]) -> Result<()> {
393 let handles = signers.iter().map(Identity::handle).collect::<Vec<_>>();
394 let pointers = bridge::handle_pointer_array(&handles);
395 let mut error = std::ptr::null_mut();
396 let status = unsafe {
397 bridge::security_cms_encoder_add_signers(
398 self.handle.as_ptr(),
399 pointers.as_ptr(),
400 bridge::len_to_isize(pointers.len())?,
401 &mut error,
402 )
403 };
404 bridge::status_result("security_cms_encoder_add_signers", status, error)
405 }
406
407 pub fn signers(&self) -> Result<Value> {
408 let mut status = 0;
409 let mut error = std::ptr::null_mut();
410 let raw = unsafe {
411 bridge::security_cms_encoder_copy_signers(self.handle.as_ptr(), &mut status, &mut error)
412 };
413 bridge::required_json("security_cms_encoder_copy_signers", raw, status, error)
414 }
415
416 pub fn add_recipients(&mut self, recipients: &[Certificate]) -> Result<()> {
417 let handles = recipients
418 .iter()
419 .map(Certificate::handle)
420 .collect::<Vec<_>>();
421 let pointers = bridge::handle_pointer_array(&handles);
422 let mut error = std::ptr::null_mut();
423 let status = unsafe {
424 bridge::security_cms_encoder_add_recipients(
425 self.handle.as_ptr(),
426 pointers.as_ptr(),
427 bridge::len_to_isize(pointers.len())?,
428 &mut error,
429 )
430 };
431 bridge::status_result("security_cms_encoder_add_recipients", status, error)
432 }
433
434 pub fn recipients(&self) -> Result<Value> {
435 let mut status = 0;
436 let mut error = std::ptr::null_mut();
437 let raw = unsafe {
438 bridge::security_cms_encoder_copy_recipients(
439 self.handle.as_ptr(),
440 &mut status,
441 &mut error,
442 )
443 };
444 bridge::required_json("security_cms_encoder_copy_recipients", raw, status, error)
445 }
446
447 pub fn set_has_detached_content(&mut self, detached_content: bool) -> Result<()> {
448 let mut error = std::ptr::null_mut();
449 let status = unsafe {
450 bridge::security_cms_encoder_set_has_detached_content(
451 self.handle.as_ptr(),
452 detached_content,
453 &mut error,
454 )
455 };
456 bridge::status_result(
457 "security_cms_encoder_set_has_detached_content",
458 status,
459 error,
460 )
461 }
462
463 pub fn has_detached_content(&self) -> Result<bool> {
464 let mut status = 0;
465 let mut error = std::ptr::null_mut();
466 let detached = unsafe {
467 bridge::security_cms_encoder_get_has_detached_content(
468 self.handle.as_ptr(),
469 &mut status,
470 &mut error,
471 )
472 };
473 if status != 0 {
474 return Err(bridge::status_error(
475 "security_cms_encoder_get_has_detached_content",
476 status,
477 error,
478 )?);
479 }
480 Ok(detached)
481 }
482
483 pub fn set_encapsulated_content_type_oid(&mut self, oid: &str) -> Result<()> {
484 let oid = bridge::cstring(oid)?;
485 let mut error = std::ptr::null_mut();
486 let status = unsafe {
487 bridge::security_cms_encoder_set_encapsulated_content_type_oid(
488 self.handle.as_ptr(),
489 oid.as_ptr(),
490 &mut error,
491 )
492 };
493 bridge::status_result(
494 "security_cms_encoder_set_encapsulated_content_type_oid",
495 status,
496 error,
497 )
498 }
499
500 pub fn encapsulated_content_type(&self) -> Result<Option<Vec<u8>>> {
501 let mut status = 0;
502 let mut error = std::ptr::null_mut();
503 let raw = unsafe {
504 bridge::security_cms_encoder_copy_encapsulated_content_type(
505 self.handle.as_ptr(),
506 &mut status,
507 &mut error,
508 )
509 };
510 if status != 0 {
511 return Err(bridge::status_error(
512 "security_cms_encoder_copy_encapsulated_content_type",
513 status,
514 error,
515 )?);
516 }
517 bridge::optional_data(raw)
518 }
519
520 pub fn add_supporting_certificates(&mut self, certificates: &[Certificate]) -> Result<()> {
521 let handles = certificates
522 .iter()
523 .map(Certificate::handle)
524 .collect::<Vec<_>>();
525 let pointers = bridge::handle_pointer_array(&handles);
526 let mut error = std::ptr::null_mut();
527 let status = unsafe {
528 bridge::security_cms_encoder_add_supporting_certs(
529 self.handle.as_ptr(),
530 pointers.as_ptr(),
531 bridge::len_to_isize(pointers.len())?,
532 &mut error,
533 )
534 };
535 bridge::status_result("security_cms_encoder_add_supporting_certs", status, error)
536 }
537
538 pub fn supporting_certificates(&self) -> Result<Value> {
539 let mut status = 0;
540 let mut error = std::ptr::null_mut();
541 let raw = unsafe {
542 bridge::security_cms_encoder_copy_supporting_certs(
543 self.handle.as_ptr(),
544 &mut status,
545 &mut error,
546 )
547 };
548 bridge::required_json(
549 "security_cms_encoder_copy_supporting_certs",
550 raw,
551 status,
552 error,
553 )
554 }
555
556 pub fn add_signed_attributes(&mut self, signed_attributes: CmsSignedAttributes) -> Result<()> {
557 let mut error = std::ptr::null_mut();
558 let status = unsafe {
559 bridge::security_cms_encoder_add_signed_attributes(
560 self.handle.as_ptr(),
561 signed_attributes.bits(),
562 &mut error,
563 )
564 };
565 bridge::status_result("security_cms_encoder_add_signed_attributes", status, error)
566 }
567
568 pub fn set_certificate_chain_mode(
569 &mut self,
570 chain_mode: CmsCertificateChainMode,
571 ) -> Result<()> {
572 let mut error = std::ptr::null_mut();
573 let status = unsafe {
574 bridge::security_cms_encoder_set_certificate_chain_mode(
575 self.handle.as_ptr(),
576 chain_mode as u32,
577 &mut error,
578 )
579 };
580 bridge::status_result(
581 "security_cms_encoder_set_certificate_chain_mode",
582 status,
583 error,
584 )
585 }
586
587 pub fn certificate_chain_mode(&self) -> Result<CmsCertificateChainMode> {
588 let mut status = 0;
589 let mut error = std::ptr::null_mut();
590 let mode = unsafe {
591 bridge::security_cms_encoder_get_certificate_chain_mode(
592 self.handle.as_ptr(),
593 &mut status,
594 &mut error,
595 )
596 };
597 if status != 0 {
598 return Err(bridge::status_error(
599 "security_cms_encoder_get_certificate_chain_mode",
600 status,
601 error,
602 )?);
603 }
604 CmsCertificateChainMode::from_raw(mode)
605 }
606
607 pub fn update_content(&mut self, data: &[u8]) -> Result<()> {
608 let mut error = std::ptr::null_mut();
609 let status = unsafe {
610 bridge::security_cms_encoder_update_content(
611 self.handle.as_ptr(),
612 data.as_ptr().cast(),
613 bridge::len_to_isize(data.len())?,
614 &mut error,
615 )
616 };
617 bridge::status_result("security_cms_encoder_update_content", status, error)
618 }
619
620 pub fn encoded_content(&self) -> Result<Vec<u8>> {
621 let mut status = 0;
622 let mut error = std::ptr::null_mut();
623 let raw = unsafe {
624 bridge::security_cms_encoder_copy_encoded_content(
625 self.handle.as_ptr(),
626 &mut status,
627 &mut error,
628 )
629 };
630 bridge::required_data(
631 "security_cms_encoder_copy_encoded_content",
632 raw,
633 status,
634 error,
635 )
636 }
637
638 pub fn signer_timestamp(&self, signer_index: usize) -> Result<Option<SystemTime>> {
639 decode_optional_cms_date("security_cms_encoder_copy_signer_timestamp", unsafe {
640 let mut status = 0;
641 let mut error = std::ptr::null_mut();
642 let raw = bridge::security_cms_encoder_copy_signer_timestamp(
643 self.handle.as_ptr(),
644 bridge::len_to_isize(signer_index)?,
645 &mut status,
646 &mut error,
647 );
648 (raw, status, error)
649 })
650 }
651
652 pub fn signer_timestamp_with_policy(
653 &self,
654 policy: Option<&Policy>,
655 signer_index: usize,
656 ) -> Result<Option<SystemTime>> {
657 decode_optional_cms_date(
658 "security_cms_encoder_copy_signer_timestamp_with_policy",
659 unsafe {
660 let mut status = 0;
661 let mut error = std::ptr::null_mut();
662 let raw = bridge::security_cms_encoder_copy_signer_timestamp_with_policy(
663 self.handle.as_ptr(),
664 policy.map_or(std::ptr::null_mut(), |value| value.handle().as_ptr()),
665 bridge::len_to_isize(signer_index)?,
666 &mut status,
667 &mut error,
668 );
669 (raw, status, error)
670 },
671 )
672 }
673}
674
675pub struct Cms;
676
677impl Cms {
678 pub fn encoder() -> Result<CmsEncoder> {
679 let mut status = 0;
680 let mut error = std::ptr::null_mut();
681 let raw = unsafe { bridge::security_cms_encoder_create(&mut status, &mut error) };
682 bridge::required_handle("security_cms_encoder_create", raw, status, error)
683 .map(CmsEncoder::from_handle)
684 }
685
686 pub fn decoder() -> Result<CmsDecoder> {
687 let mut status = 0;
688 let mut error = std::ptr::null_mut();
689 let raw = unsafe { bridge::security_cms_decoder_create(&mut status, &mut error) };
690 bridge::required_handle("security_cms_decoder_create", raw, status, error)
691 .map(CmsDecoder::from_handle)
692 }
693
694 pub fn encode_supporting_certificates(certificates: &[Certificate]) -> Result<Vec<u8>> {
695 let mut encoder = Self::encoder()?;
696 encoder.add_supporting_certificates(certificates)?;
697 encoder.encoded_content()
698 }
699
700 pub fn decode_all_certificates(data: &[u8]) -> Result<Vec<Certificate>> {
701 let mut status = 0;
702 let mut error = std::ptr::null_mut();
703 let raw = unsafe {
704 bridge::security_cms_decode_all_certificates(
705 data.as_ptr().cast(),
706 bridge::len_to_isize(data.len())?,
707 &mut status,
708 &mut error,
709 )
710 };
711 let array_handle =
712 bridge::required_handle("security_cms_decode_all_certificates", raw, status, error)?;
713 let count = usize::try_from(unsafe {
714 bridge::security_certificate_array_get_count(array_handle.as_ptr())
715 })
716 .unwrap_or_default();
717 let mut certificates = Vec::with_capacity(count);
718 for index in 0..count {
719 let mut status = 0;
720 let mut error = std::ptr::null_mut();
721 let raw = unsafe {
722 bridge::security_certificate_array_copy_item(
723 array_handle.as_ptr(),
724 bridge::len_to_isize(index)?,
725 &mut status,
726 &mut error,
727 )
728 };
729 let handle = bridge::required_handle(
730 "security_certificate_array_copy_item",
731 raw,
732 status,
733 error,
734 )?;
735 certificates.push(Certificate::from_handle(handle));
736 }
737 Ok(certificates)
738 }
739
740 pub fn encode_content(
741 signers: &[Identity],
742 recipients: &[Certificate],
743 encapsulated_content_type_oid: Option<&str>,
744 detached_content: bool,
745 signed_attributes: CmsSignedAttributes,
746 content: &[u8],
747 ) -> Result<Vec<u8>> {
748 let signer_handles = signers.iter().map(Identity::handle).collect::<Vec<_>>();
749 let signer_pointers = bridge::handle_pointer_array(&signer_handles);
750 let recipient_handles = recipients
751 .iter()
752 .map(Certificate::handle)
753 .collect::<Vec<_>>();
754 let recipient_pointers = bridge::handle_pointer_array(&recipient_handles);
755 let encapsulated_content_type_oid = encapsulated_content_type_oid
756 .map(bridge::cstring)
757 .transpose()?;
758 let mut status = 0;
759 let mut error = std::ptr::null_mut();
760 let raw = unsafe {
761 bridge::security_cms_encode_content(
762 signer_pointers.as_ptr(),
763 bridge::len_to_isize(signer_pointers.len())?,
764 recipient_pointers.as_ptr(),
765 bridge::len_to_isize(recipient_pointers.len())?,
766 encapsulated_content_type_oid
767 .as_ref()
768 .map_or(std::ptr::null(), |value| value.as_ptr()),
769 detached_content,
770 signed_attributes.bits(),
771 content.as_ptr().cast(),
772 bridge::len_to_isize(content.len())?,
773 &mut status,
774 &mut error,
775 )
776 };
777 bridge::required_data("security_cms_encode_content", raw, status, error)
778 }
779}
780
781fn decode_optional_cms_date(
782 operation: &'static str,
783 result: (*mut std::ffi::c_void, i32, *mut std::ffi::c_void),
784) -> Result<Option<SystemTime>> {
785 let (raw, status, error) = result;
786 if status != 0 {
787 return Err(bridge::status_error(operation, status, error)?);
788 }
789 bridge::optional_json::<Value>(raw)?.map_or(Ok(None), |value| {
790 decode_cms_date(value, operation).map(Some)
791 })
792}
793
794fn decode_cms_date(value: Value, operation: &'static str) -> Result<SystemTime> {
795 let unix =
796 value
797 .get("unix")
798 .and_then(Value::as_f64)
799 .ok_or_else(|| SecurityError::UnexpectedType {
800 operation,
801 expected: "date JSON object",
802 })?;
803 let duration = Duration::from_secs_f64(unix.abs());
804 if unix >= 0.0 {
805 Ok(UNIX_EPOCH + duration)
806 } else {
807 UNIX_EPOCH.checked_sub(duration).ok_or_else(|| {
808 SecurityError::InvalidArgument("CMS date preceded UNIX_EPOCH by too much".to_owned())
809 })
810 }
811}