Skip to content

Commit 951d771

Browse files
authored
Merge pull request #2111 from trail-of-forks/pkcs7-add-apis
Add two methods to the PKCS7 API
2 parents fb57f9f + 3d69fe9 commit 951d771

File tree

2 files changed

+131
-1
lines changed

2 files changed

+131
-1
lines changed

openssl/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
## [Unreleased]
44

5+
### Added
6+
7+
* Added `Pkcs7Ref::{type_,signed}`.
8+
* Added `Pkcs7SignedRef::certificates`.
9+
510
## [v0.10.62] - 2023-12-22
611

712
### Added

openssl/src/pkcs7.rs

Lines changed: 126 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,31 @@ use libc::c_int;
44
use std::mem;
55
use std::ptr;
66

7+
use crate::asn1::Asn1ObjectRef;
78
use crate::bio::{MemBio, MemBioSlice};
89
use crate::error::ErrorStack;
10+
use crate::nid::Nid;
911
use crate::pkey::{HasPrivate, PKeyRef};
10-
use crate::stack::{Stack, StackRef};
12+
use crate::stack::{Stack, StackRef, Stackable};
1113
use crate::symm::Cipher;
14+
use crate::util::ForeignTypeRefExt;
1215
use crate::x509::store::X509StoreRef;
1316
use crate::x509::{X509Ref, X509};
1417
use crate::{cvt, cvt_p};
1518
use openssl_macros::corresponds;
1619

20+
foreign_type_and_impl_send_sync! {
21+
type CType = ffi::PKCS7_SIGNER_INFO;
22+
fn drop = ffi::PKCS7_SIGNER_INFO_free;
23+
24+
pub struct Pkcs7SignerInfo;
25+
pub struct Pkcs7SignerInfoRef;
26+
}
27+
28+
impl Stackable for Pkcs7SignerInfo {
29+
type StackType = ffi::stack_st_PKCS7_SIGNER_INFO;
30+
}
31+
1732
foreign_type_and_impl_send_sync! {
1833
type CType = ffi::PKCS7;
1934
fn drop = ffi::PKCS7_free;
@@ -27,6 +42,19 @@ foreign_type_and_impl_send_sync! {
2742
pub struct Pkcs7Ref;
2843
}
2944

45+
foreign_type_and_impl_send_sync! {
46+
type CType = ffi::PKCS7_SIGNED;
47+
fn drop = ffi::PKCS7_SIGNED_free;
48+
49+
/// A PKCS#7 signed data structure.
50+
///
51+
/// Contains signed data.
52+
pub struct Pkcs7Signed;
53+
54+
/// Reference to `Pkcs7Signed`
55+
pub struct Pkcs7SignedRef;
56+
}
57+
3058
bitflags! {
3159
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
3260
#[repr(transparent)]
@@ -281,11 +309,43 @@ impl Pkcs7Ref {
281309
Ok(stack)
282310
}
283311
}
312+
313+
/// Return the type of a PKCS#7 structure as an Asn1Object
314+
pub fn type_(&self) -> Option<&Asn1ObjectRef> {
315+
unsafe {
316+
let ptr = (*self.as_ptr()).type_;
317+
Asn1ObjectRef::from_const_ptr_opt(ptr)
318+
}
319+
}
320+
321+
/// Get the signed data of a PKCS#7 structure of type PKCS7_SIGNED
322+
pub fn signed(&self) -> Option<&Pkcs7SignedRef> {
323+
unsafe {
324+
if self.type_().map(|x| x.nid()) != Some(Nid::PKCS7_SIGNED) {
325+
return None;
326+
}
327+
let signed_data = (*self.as_ptr()).d.sign;
328+
Pkcs7SignedRef::from_const_ptr_opt(signed_data)
329+
}
330+
}
331+
}
332+
333+
impl Pkcs7SignedRef {
334+
/// Get the stack of certificates from the PKCS7_SIGNED object
335+
pub fn certificates(&self) -> Option<&StackRef<X509>> {
336+
unsafe {
337+
self.as_ptr()
338+
.as_ref()
339+
.and_then(|x| x.cert.as_mut())
340+
.and_then(|x| StackRef::<X509>::from_const_ptr_opt(x))
341+
}
342+
}
284343
}
285344

286345
#[cfg(test)]
287346
mod tests {
288347
use crate::hash::MessageDigest;
348+
use crate::nid::Nid;
289349
use crate::pkcs7::{Pkcs7, Pkcs7Flags};
290350
use crate::pkey::PKey;
291351
use crate::stack::Stack;
@@ -307,6 +367,10 @@ mod tests {
307367

308368
let pkcs7 =
309369
Pkcs7::encrypt(&certs, message.as_bytes(), cipher, flags).expect("should succeed");
370+
assert_eq!(
371+
pkcs7.type_().expect("PKCS7 should have a type").nid(),
372+
Nid::PKCS7_ENVELOPED
373+
);
310374

311375
let encrypted = pkcs7
312376
.to_smime(message.as_bytes(), flags)
@@ -340,6 +404,10 @@ mod tests {
340404

341405
let pkcs7 =
342406
Pkcs7::sign(&cert, &pkey, &certs, message.as_bytes(), flags).expect("should succeed");
407+
assert_eq!(
408+
pkcs7.type_().expect("PKCS7 should have a type").nid(),
409+
Nid::PKCS7_SIGNED
410+
);
343411

344412
let signed = pkcs7
345413
.to_smime(message.as_bytes(), flags)
@@ -384,6 +452,10 @@ mod tests {
384452

385453
let pkcs7 =
386454
Pkcs7::sign(&cert, &pkey, &certs, message.as_bytes(), flags).expect("should succeed");
455+
assert_eq!(
456+
pkcs7.type_().expect("PKCS7 should have a type").nid(),
457+
Nid::PKCS7_SIGNED
458+
);
387459

388460
let signed = pkcs7
389461
.to_smime(message.as_bytes(), flags)
@@ -421,6 +493,10 @@ mod tests {
421493

422494
let pkcs7 =
423495
Pkcs7::sign(&cert, &pkey, &certs, message.as_bytes(), flags).expect("should succeed");
496+
assert_eq!(
497+
pkcs7.type_().expect("PKCS7 should have a type").nid(),
498+
Nid::PKCS7_SIGNED
499+
);
424500

425501
let signed = pkcs7
426502
.to_smime(message.as_bytes(), flags)
@@ -445,4 +521,53 @@ mod tests {
445521

446522
assert!(result.is_err());
447523
}
524+
525+
#[test]
526+
fn signed_data_certificates() {
527+
let cert = include_bytes!("../test/cert.pem");
528+
let cert = X509::from_pem(cert).unwrap();
529+
let mut extra_certs = Stack::<X509>::new().unwrap();
530+
for cert in
531+
X509::stack_from_pem(include_bytes!("../test/certs.pem")).expect("should succeed")
532+
{
533+
extra_certs.push(cert).expect("should succeed");
534+
}
535+
536+
let message = "foo";
537+
let flags = Pkcs7Flags::STREAM;
538+
let pkey = include_bytes!("../test/key.pem");
539+
let pkey = PKey::private_key_from_pem(pkey).unwrap();
540+
541+
let pkcs7 = Pkcs7::sign(&cert, &pkey, &extra_certs, message.as_bytes(), flags)
542+
.expect("should succeed");
543+
assert_eq!(
544+
pkcs7.type_().expect("PKCS7 should have a type").nid(),
545+
Nid::PKCS7_SIGNED
546+
);
547+
let signed_data_certs = pkcs7.signed().and_then(|x| x.certificates());
548+
assert_eq!(signed_data_certs.expect("should succeed").len(), 3);
549+
}
550+
551+
#[test]
552+
fn signed_data_certificates_no_signed_data() {
553+
let cert = include_bytes!("../test/certs.pem");
554+
let cert = X509::from_pem(cert).unwrap();
555+
let mut certs = Stack::new().unwrap();
556+
certs.push(cert).unwrap();
557+
let message: String = String::from("foo");
558+
let cipher = Cipher::des_ede3_cbc();
559+
let flags = Pkcs7Flags::STREAM;
560+
561+
// Use `Pkcs7::encrypt` since it populates the PKCS7_ENVELOPE struct rather than
562+
// PKCS7_SIGNED
563+
let pkcs7 =
564+
Pkcs7::encrypt(&certs, message.as_bytes(), cipher, flags).expect("should succeed");
565+
assert_eq!(
566+
pkcs7.type_().expect("PKCS7 should have a type").nid(),
567+
Nid::PKCS7_ENVELOPED
568+
);
569+
570+
let signed_data_certs = pkcs7.signed().and_then(|x| x.certificates());
571+
assert!(signed_data_certs.is_none())
572+
}
448573
}

0 commit comments

Comments
 (0)