1use bitflags::bitflags;
2use foreign_types::{ForeignType, ForeignTypeRef};
3use libc::c_int;
4use std::mem;
5use std::ptr;
6
7use crate::asn1::Asn1ObjectRef;
8use crate::bio::{MemBio, MemBioSlice};
9use crate::error::ErrorStack;
10#[cfg(not(awslc))]
11use crate::nid::Nid;
12use crate::pkey::{HasPrivate, PKeyRef};
13use crate::stack::{Stack, StackRef, Stackable};
14use crate::symm::Cipher;
15use crate::util::ForeignTypeRefExt;
16use crate::x509::store::X509StoreRef;
17use crate::x509::{X509Ref, X509};
18use crate::{cvt, cvt_p};
19use openssl_macros::corresponds;
20
21foreign_type_and_impl_send_sync! {
22 type CType = ffi::PKCS7_SIGNER_INFO;
23 fn drop = ffi::PKCS7_SIGNER_INFO_free;
24
25 pub struct Pkcs7SignerInfo;
26 pub struct Pkcs7SignerInfoRef;
27}
28
29impl Stackable for Pkcs7SignerInfo {
30 type StackType = ffi::stack_st_PKCS7_SIGNER_INFO;
31}
32
33foreign_type_and_impl_send_sync! {
34 type CType = ffi::PKCS7;
35 fn drop = ffi::PKCS7_free;
36
37 pub struct Pkcs7;
41
42 pub struct Pkcs7Ref;
44}
45
46#[cfg(not(awslc))]
48foreign_type_and_impl_send_sync! {
49 type CType = ffi::PKCS7_SIGNED;
50 fn drop = ffi::PKCS7_SIGNED_free;
51
52 pub struct Pkcs7Signed;
56
57 pub struct Pkcs7SignedRef;
59}
60
61bitflags! {
62 #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
63 #[repr(transparent)]
64 pub struct Pkcs7Flags: c_int {
65 const TEXT = ffi::PKCS7_TEXT;
66 const NOCERTS = ffi::PKCS7_NOCERTS;
67 const NOSIGS = ffi::PKCS7_NOSIGS;
68 const NOCHAIN = ffi::PKCS7_NOCHAIN;
69 const NOINTERN = ffi::PKCS7_NOINTERN;
70 const NOVERIFY = ffi::PKCS7_NOVERIFY;
71 const DETACHED = ffi::PKCS7_DETACHED;
72 const BINARY = ffi::PKCS7_BINARY;
73 const NOATTR = ffi::PKCS7_NOATTR;
74 const NOSMIMECAP = ffi::PKCS7_NOSMIMECAP;
75 #[cfg(not(awslc))]
76 const NOOLDMIMETYPE = ffi::PKCS7_NOOLDMIMETYPE;
77 #[cfg(not(awslc))]
78 const CRLFEOL = ffi::PKCS7_CRLFEOL;
79 const STREAM = ffi::PKCS7_STREAM;
80 #[cfg(not(awslc))]
81 const NOCRL = ffi::PKCS7_NOCRL;
82 const PARTIAL = ffi::PKCS7_PARTIAL;
83 #[cfg(not(awslc))]
84 const REUSE_DIGEST = ffi::PKCS7_REUSE_DIGEST;
85 #[cfg(ossl110)]
86 const NO_DUAL_CONTENT = ffi::PKCS7_NO_DUAL_CONTENT;
87 }
88}
89
90impl Pkcs7 {
91 from_pem! {
92 #[corresponds(PEM_read_bio_PKCS7)]
96 from_pem,
97 Pkcs7,
98 ffi::PEM_read_bio_PKCS7
99 }
100
101 from_der! {
102 #[corresponds(d2i_PKCS7)]
104 from_der,
105 Pkcs7,
106 ffi::d2i_PKCS7
107 }
108
109 #[corresponds(SMIME_read_PKCS7)]
114 #[cfg(not(awslc))]
115 pub fn from_smime(input: &[u8]) -> Result<(Pkcs7, Option<Vec<u8>>), ErrorStack> {
116 ffi::init();
117
118 let input_bio = MemBioSlice::new(input)?;
119 let mut bcont_bio = ptr::null_mut();
120 unsafe {
121 let pkcs7 =
122 cvt_p(ffi::SMIME_read_PKCS7(input_bio.as_ptr(), &mut bcont_bio)).map(Pkcs7)?;
123 let out = if !bcont_bio.is_null() {
124 let bcont_bio = MemBio::from_ptr(bcont_bio);
125 Some(bcont_bio.get_buf().to_vec())
126 } else {
127 None
128 };
129 Ok((pkcs7, out))
130 }
131 }
132
133 #[corresponds(PKCS7_encrypt)]
139 pub fn encrypt(
140 certs: &StackRef<X509>,
141 input: &[u8],
142 cipher: Cipher,
143 flags: Pkcs7Flags,
144 ) -> Result<Pkcs7, ErrorStack> {
145 let input_bio = MemBioSlice::new(input)?;
146
147 unsafe {
148 cvt_p(ffi::PKCS7_encrypt(
149 certs.as_ptr(),
150 input_bio.as_ptr(),
151 cipher.as_ptr(),
152 flags.bits(),
153 ))
154 .map(Pkcs7)
155 }
156 }
157
158 #[corresponds(PKCS7_sign)]
165 pub fn sign<PT>(
166 signcert: &X509Ref,
167 pkey: &PKeyRef<PT>,
168 certs: &StackRef<X509>,
169 input: &[u8],
170 flags: Pkcs7Flags,
171 ) -> Result<Pkcs7, ErrorStack>
172 where
173 PT: HasPrivate,
174 {
175 let input_bio = MemBioSlice::new(input)?;
176 unsafe {
177 cvt_p(ffi::PKCS7_sign(
178 signcert.as_ptr(),
179 pkey.as_ptr(),
180 certs.as_ptr(),
181 input_bio.as_ptr(),
182 flags.bits(),
183 ))
184 .map(Pkcs7)
185 }
186 }
187}
188
189impl Pkcs7Ref {
190 #[corresponds(SMIME_write_PKCS7)]
192 #[cfg(not(awslc))]
193 pub fn to_smime(&self, input: &[u8], flags: Pkcs7Flags) -> Result<Vec<u8>, ErrorStack> {
194 let input_bio = MemBioSlice::new(input)?;
195 let output = MemBio::new()?;
196 unsafe {
197 cvt(ffi::SMIME_write_PKCS7(
198 output.as_ptr(),
199 self.as_ptr(),
200 input_bio.as_ptr(),
201 flags.bits(),
202 ))
203 .map(|_| output.get_buf().to_owned())
204 }
205 }
206
207 to_pem! {
208 #[corresponds(PEM_write_bio_PKCS7)]
212 to_pem,
213 ffi::PEM_write_bio_PKCS7
214 }
215
216 to_der! {
217 #[corresponds(i2d_PKCS7)]
219 to_der,
220 ffi::i2d_PKCS7
221 }
222
223 #[corresponds(PKCS7_decrypt)]
230 pub fn decrypt<PT>(
231 &self,
232 pkey: &PKeyRef<PT>,
233 cert: &X509Ref,
234 flags: Pkcs7Flags,
235 ) -> Result<Vec<u8>, ErrorStack>
236 where
237 PT: HasPrivate,
238 {
239 let output = MemBio::new()?;
240
241 unsafe {
242 cvt(ffi::PKCS7_decrypt(
243 self.as_ptr(),
244 pkey.as_ptr(),
245 cert.as_ptr(),
246 output.as_ptr(),
247 flags.bits(),
248 ))
249 .map(|_| output.get_buf().to_owned())
250 }
251 }
252
253 #[corresponds(PKCS7_verify)]
260 pub fn verify(
261 &self,
262 certs: &StackRef<X509>,
263 store: &X509StoreRef,
264 indata: Option<&[u8]>,
265 out: Option<&mut Vec<u8>>,
266 flags: Pkcs7Flags,
267 ) -> Result<(), ErrorStack> {
268 let out_bio = MemBio::new()?;
269
270 let indata_bio = match indata {
271 Some(data) => Some(MemBioSlice::new(data)?),
272 None => None,
273 };
274 let indata_bio_ptr = indata_bio.as_ref().map_or(ptr::null_mut(), |p| p.as_ptr());
275
276 unsafe {
277 cvt(ffi::PKCS7_verify(
278 self.as_ptr(),
279 certs.as_ptr(),
280 store.as_ptr(),
281 indata_bio_ptr,
282 out_bio.as_ptr(),
283 flags.bits(),
284 ))
285 .map(|_| ())?
286 }
287
288 if let Some(data) = out {
289 data.clear();
290 data.extend_from_slice(out_bio.get_buf());
291 }
292
293 Ok(())
294 }
295
296 #[corresponds(PKCS7_get0_signers)]
298 pub fn signers(
299 &self,
300 certs: &StackRef<X509>,
301 flags: Pkcs7Flags,
302 ) -> Result<Stack<X509>, ErrorStack> {
303 unsafe {
304 let ptr = cvt_p(ffi::PKCS7_get0_signers(
305 self.as_ptr(),
306 certs.as_ptr(),
307 flags.bits(),
308 ))?;
309
310 let stack = Stack::<X509>::from_ptr(ptr);
314 for cert in &stack {
315 mem::forget(cert.to_owned());
316 }
317
318 Ok(stack)
319 }
320 }
321
322 pub fn type_(&self) -> Option<&Asn1ObjectRef> {
324 unsafe {
325 let ptr = (*self.as_ptr()).type_;
326 Asn1ObjectRef::from_const_ptr_opt(ptr)
327 }
328 }
329
330 #[cfg(not(awslc))]
332 pub fn signed(&self) -> Option<&Pkcs7SignedRef> {
333 unsafe {
334 if self.type_().map(|x| x.nid()) != Some(Nid::PKCS7_SIGNED) {
335 return None;
336 }
337 let signed_data = (*self.as_ptr()).d.sign;
338 Pkcs7SignedRef::from_const_ptr_opt(signed_data)
339 }
340 }
341}
342
343#[cfg(not(awslc))]
344impl Pkcs7SignedRef {
345 pub fn certificates(&self) -> Option<&StackRef<X509>> {
347 unsafe {
348 self.as_ptr()
349 .as_ref()
350 .and_then(|x| x.cert.as_mut())
351 .and_then(|x| StackRef::<X509>::from_const_ptr_opt(x))
352 }
353 }
354}
355
356#[cfg(test)]
357mod tests {
358 use crate::hash::MessageDigest;
359 use crate::nid::Nid;
360 use crate::pkcs7::{Pkcs7, Pkcs7Flags};
361 use crate::pkey::PKey;
362 use crate::stack::Stack;
363 use crate::symm::Cipher;
364 use crate::x509::store::X509StoreBuilder;
365 use crate::x509::X509;
366
367 #[test]
368 fn encrypt_decrypt_test() {
369 let cert = include_bytes!("../test/certs.pem");
370 let cert = X509::from_pem(cert).unwrap();
371 let mut certs = Stack::new().unwrap();
372 certs.push(cert.clone()).unwrap();
373 let message: String = String::from("foo");
374 let cipher = Cipher::des_ede3_cbc();
375 let flags = Pkcs7Flags::STREAM;
376 let pkey = include_bytes!("../test/key.pem");
377 let pkey = PKey::private_key_from_pem(pkey).unwrap();
378
379 let pkcs7 =
380 Pkcs7::encrypt(&certs, message.as_bytes(), cipher, flags).expect("should succeed");
381 assert_eq!(
382 pkcs7.type_().expect("PKCS7 should have a type").nid(),
383 Nid::PKCS7_ENVELOPED
384 );
385
386 #[cfg(not(awslc))]
387 let pkcs7_decoded = {
388 let encrypted = pkcs7
389 .to_smime(message.as_bytes(), flags)
390 .expect("should succeed");
391
392 Pkcs7::from_smime(encrypted.as_slice())
393 .expect("should succeed")
394 .0
395 };
396 #[cfg(awslc)]
398 let pkcs7_decoded = {
399 let encrypted = pkcs7.to_pem().expect("should succeed");
400 Pkcs7::from_pem(encrypted.as_slice()).expect("should succeed")
401 };
402
403 let decoded = pkcs7_decoded
404 .decrypt(&pkey, &cert, Pkcs7Flags::empty())
405 .expect("should succeed");
406
407 assert_eq!(decoded, message.into_bytes());
408 }
409
410 #[test]
411 fn sign_verify_test_detached() {
412 let cert = include_bytes!("../test/cert.pem");
413 let cert = X509::from_pem(cert).unwrap();
414 let certs = Stack::new().unwrap();
415 let message = "foo";
416 let flags = Pkcs7Flags::STREAM | Pkcs7Flags::DETACHED;
417 let pkey = include_bytes!("../test/key.pem");
418 let pkey = PKey::private_key_from_pem(pkey).unwrap();
419 let mut store_builder = X509StoreBuilder::new().expect("should succeed");
420
421 let root_ca = include_bytes!("../test/root-ca.pem");
422 let root_ca = X509::from_pem(root_ca).unwrap();
423 store_builder.add_cert(root_ca).expect("should succeed");
424
425 let store = store_builder.build();
426
427 let pkcs7 =
428 Pkcs7::sign(&cert, &pkey, &certs, message.as_bytes(), flags).expect("should succeed");
429 assert_eq!(
430 pkcs7.type_().expect("PKCS7 should have a type").nid(),
431 Nid::PKCS7_SIGNED
432 );
433
434 #[cfg(not(awslc))]
435 let (pkcs7_decoded, content) = {
436 let signed = pkcs7
437 .to_smime(message.as_bytes(), flags)
438 .expect("should succeed");
439 println!("{:?}", String::from_utf8(signed.clone()).unwrap());
440 Pkcs7::from_smime(signed.as_slice()).expect("should succeed")
441 };
442 #[cfg(awslc)]
444 let pkcs7_decoded = {
445 let signed = pkcs7.to_pem().expect("should succeed");
446 Pkcs7::from_pem(signed.as_slice()).expect("should succeed")
447 };
448
449 let mut output = Vec::new();
450 pkcs7_decoded
451 .verify(
452 &certs,
453 &store,
454 Some(message.as_bytes()),
455 Some(&mut output),
456 flags,
457 )
458 .expect("should succeed");
459
460 assert_eq!(output, message.as_bytes());
461 #[cfg(not(awslc))]
462 assert_eq!(content.expect("should be non-empty"), message.as_bytes());
463 }
464
465 #[test]
467 #[cfg_attr(all(libressl360, not(libressl361)), ignore)]
468 fn sign_verify_test_normal() {
469 let cert = include_bytes!("../test/cert.pem");
470 let cert = X509::from_pem(cert).unwrap();
471 let certs = Stack::new().unwrap();
472 let message = "foo";
473 let flags = Pkcs7Flags::STREAM;
474 let pkey = include_bytes!("../test/key.pem");
475 let pkey = PKey::private_key_from_pem(pkey).unwrap();
476 let mut store_builder = X509StoreBuilder::new().expect("should succeed");
477
478 let root_ca = include_bytes!("../test/root-ca.pem");
479 let root_ca = X509::from_pem(root_ca).unwrap();
480 store_builder.add_cert(root_ca).expect("should succeed");
481
482 let store = store_builder.build();
483
484 let pkcs7 =
485 Pkcs7::sign(&cert, &pkey, &certs, message.as_bytes(), flags).expect("should succeed");
486 assert_eq!(
487 pkcs7.type_().expect("PKCS7 should have a type").nid(),
488 Nid::PKCS7_SIGNED
489 );
490
491 #[cfg(not(awslc))]
492 let (pkcs7_decoded, content) = {
493 let signed = pkcs7
494 .to_smime(message.as_bytes(), flags)
495 .expect("should succeed");
496
497 Pkcs7::from_smime(signed.as_slice()).expect("should succeed")
498 };
499 #[cfg(awslc)]
501 let pkcs7_decoded = {
502 let signed = pkcs7.to_pem().expect("should succeed");
503 Pkcs7::from_pem(signed.as_slice()).expect("should succeed")
504 };
505
506 let mut output = Vec::new();
507 pkcs7_decoded
508 .verify(&certs, &store, None, Some(&mut output), flags)
509 .expect("should succeed");
510
511 assert_eq!(output, message.as_bytes());
512 #[cfg(not(awslc))]
513 assert!(content.is_none());
514 }
515
516 #[test]
518 #[cfg_attr(all(libressl360, not(libressl361)), ignore)]
519 fn signers() {
520 let cert = include_bytes!("../test/cert.pem");
521 let cert = X509::from_pem(cert).unwrap();
522 let cert_digest = cert.digest(MessageDigest::sha256()).unwrap();
523 let certs = Stack::new().unwrap();
524 let message = "foo";
525 let flags = Pkcs7Flags::STREAM;
526 let pkey = include_bytes!("../test/key.pem");
527 let pkey = PKey::private_key_from_pem(pkey).unwrap();
528 let mut store_builder = X509StoreBuilder::new().expect("should succeed");
529
530 let root_ca = include_bytes!("../test/root-ca.pem");
531 let root_ca = X509::from_pem(root_ca).unwrap();
532 store_builder.add_cert(root_ca).expect("should succeed");
533
534 let pkcs7 =
535 Pkcs7::sign(&cert, &pkey, &certs, message.as_bytes(), flags).expect("should succeed");
536 assert_eq!(
537 pkcs7.type_().expect("PKCS7 should have a type").nid(),
538 Nid::PKCS7_SIGNED
539 );
540
541 #[cfg(not(awslc))]
542 let pkcs7_decoded = {
543 let signed = pkcs7
544 .to_smime(message.as_bytes(), flags)
545 .expect("should succeed");
546
547 Pkcs7::from_smime(signed.as_slice())
548 .expect("should succeed")
549 .0
550 };
551 #[cfg(awslc)]
553 let pkcs7_decoded = {
554 let signed = pkcs7.to_pem().expect("should succeed");
555 Pkcs7::from_pem(signed.as_slice()).expect("should succeed")
556 };
557
558 let empty_certs = Stack::new().unwrap();
559 let signer_certs = pkcs7_decoded
560 .signers(&empty_certs, flags)
561 .expect("should succeed");
562 assert_eq!(empty_certs.len(), 0);
563 assert_eq!(signer_certs.len(), 1);
564 let signer_digest = signer_certs[0].digest(MessageDigest::sha256()).unwrap();
565 assert_eq!(*cert_digest, *signer_digest);
566 }
567
568 #[test]
569 #[cfg(not(awslc))]
570 fn invalid_from_smime() {
571 let input = String::from("Invalid SMIME Message");
572 let result = Pkcs7::from_smime(input.as_bytes());
573
574 assert!(result.is_err());
575 }
576
577 #[test]
578 #[cfg(not(awslc))]
579 fn signed_data_certificates() {
580 let cert = include_bytes!("../test/cert.pem");
581 let cert = X509::from_pem(cert).unwrap();
582 let mut extra_certs = Stack::<X509>::new().unwrap();
583 for cert in
584 X509::stack_from_pem(include_bytes!("../test/certs.pem")).expect("should succeed")
585 {
586 extra_certs.push(cert).expect("should succeed");
587 }
588
589 let message = "foo";
590 let flags = Pkcs7Flags::STREAM;
591 let pkey = include_bytes!("../test/key.pem");
592 let pkey = PKey::private_key_from_pem(pkey).unwrap();
593
594 let pkcs7 = Pkcs7::sign(&cert, &pkey, &extra_certs, message.as_bytes(), flags)
595 .expect("should succeed");
596 assert_eq!(
597 pkcs7.type_().expect("PKCS7 should have a type").nid(),
598 Nid::PKCS7_SIGNED
599 );
600 let signed_data_certs = pkcs7.signed().and_then(|x| x.certificates());
601 assert_eq!(signed_data_certs.expect("should succeed").len(), 3);
602 }
603
604 #[test]
605 #[cfg(not(awslc))]
606 fn signed_data_certificates_no_signed_data() {
607 let cert = include_bytes!("../test/certs.pem");
608 let cert = X509::from_pem(cert).unwrap();
609 let mut certs = Stack::new().unwrap();
610 certs.push(cert).unwrap();
611 let message: String = String::from("foo");
612 let cipher = Cipher::des_ede3_cbc();
613 let flags = Pkcs7Flags::STREAM;
614
615 let pkcs7 =
618 Pkcs7::encrypt(&certs, message.as_bytes(), cipher, flags).expect("should succeed");
619 assert_eq!(
620 pkcs7.type_().expect("PKCS7 should have a type").nid(),
621 Nid::PKCS7_ENVELOPED
622 );
623
624 let signed_data_certs = pkcs7.signed().and_then(|x| x.certificates());
625 assert!(signed_data_certs.is_none())
626 }
627}