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