Skip to content

Commit

Permalink
Add PKCS7 APIs to access type and signed data certs
Browse files Browse the repository at this point in the history
  • Loading branch information
facutuesca committed Jan 4, 2024
1 parent 0743e6a commit 1ef2608
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 1 deletion.
4 changes: 4 additions & 0 deletions openssl/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased]

### Added

* Added `Pkcs7Ref::{type_,signed_data_certificates}`.

## [v0.10.62] - 2023-12-22

### Added
Expand Down
108 changes: 107 additions & 1 deletion openssl/src/pkcs7.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,31 @@ use libc::c_int;
use std::mem;
use std::ptr;

use crate::asn1::Asn1ObjectRef;
use crate::bio::{MemBio, MemBioSlice};
use crate::error::ErrorStack;
use crate::nid::Nid;
use crate::pkey::{HasPrivate, PKeyRef};
use crate::stack::{Stack, StackRef};
use crate::stack::{Stack, StackRef, Stackable};
use crate::symm::Cipher;
use crate::util::ForeignTypeRefExt;
use crate::x509::store::X509StoreRef;
use crate::x509::{X509Ref, X509};
use crate::{cvt, cvt_p};
use openssl_macros::corresponds;

foreign_type_and_impl_send_sync! {
type CType = ffi::PKCS7_SIGNER_INFO;
fn drop = ffi::PKCS7_SIGNER_INFO_free;

pub struct Pkcs7SignerInfo;
pub struct Pkcs7SignerInfoRef;
}

impl Stackable for Pkcs7SignerInfo {
type StackType = ffi::stack_st_PKCS7_SIGNER_INFO;
}

foreign_type_and_impl_send_sync! {
type CType = ffi::PKCS7;
fn drop = ffi::PKCS7_free;
Expand Down Expand Up @@ -281,11 +296,37 @@ impl Pkcs7Ref {
Ok(stack)
}
}

// Return the type of a PKCS#7 structure as an Asn1Object
pub fn type_(&self) -> Option<&Asn1ObjectRef> {
unsafe {
let ptr = (*self.as_ptr()).type_;
Asn1ObjectRef::from_const_ptr_opt(ptr)
}
}

// Retrieve all the certificates from a PKCS#7 structure used for signed data
pub fn signed_data_certificates(&self) -> Result<Option<&StackRef<X509>>, ErrorStack> {
unsafe {
if self.type_().map(|x| x.nid()) != Some(Nid::PKCS7_SIGNED) {
return Ok(None);
}
// Get the stack of certificates from the PKCS7_SIGNED object
let stack_certs = (*self.as_ptr())
.d
.sign
.as_mut()
.and_then(|x| x.cert.as_mut())
.and_then(|x| StackRef::<X509>::from_const_ptr_opt(x));
Ok(stack_certs)
}
}
}

#[cfg(test)]
mod tests {
use crate::hash::MessageDigest;
use crate::nid::Nid;
use crate::pkcs7::{Pkcs7, Pkcs7Flags};
use crate::pkey::PKey;
use crate::stack::Stack;
Expand All @@ -307,6 +348,10 @@ mod tests {

let pkcs7 =
Pkcs7::encrypt(&certs, message.as_bytes(), cipher, flags).expect("should succeed");
assert_eq!(
pkcs7.type_().expect("PKCS7 should have a type").nid(),
Nid::PKCS7_ENVELOPED
);

let encrypted = pkcs7
.to_smime(message.as_bytes(), flags)
Expand Down Expand Up @@ -340,6 +385,10 @@ mod tests {

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

let signed = pkcs7
.to_smime(message.as_bytes(), flags)
Expand Down Expand Up @@ -384,6 +433,10 @@ mod tests {

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

let signed = pkcs7
.to_smime(message.as_bytes(), flags)
Expand Down Expand Up @@ -421,6 +474,10 @@ mod tests {

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

let signed = pkcs7
.to_smime(message.as_bytes(), flags)
Expand All @@ -445,4 +502,53 @@ mod tests {

assert!(result.is_err());
}

#[test]
fn signed_data_certificates() {
let cert = include_bytes!("../test/cert.pem");
let cert = X509::from_pem(cert).unwrap();
let mut extra_certs = Stack::<X509>::new().unwrap();
for cert in
X509::stack_from_pem(include_bytes!("../test/certs.pem")).expect("should succeed")
{
extra_certs.push(cert).expect("should succeed");
}

let message = "foo";
let flags = Pkcs7Flags::STREAM;
let pkey = include_bytes!("../test/key.pem");
let pkey = PKey::private_key_from_pem(pkey).unwrap();

let pkcs7 = Pkcs7::sign(&cert, &pkey, &extra_certs, message.as_bytes(), flags)
.expect("should succeed");
assert_eq!(
pkcs7.type_().expect("PKCS7 should have a type").nid(),
Nid::PKCS7_SIGNED
);
let signed_data_certs = pkcs7.signed_data_certificates().expect("should succeed");
assert_eq!(signed_data_certs.expect("should succeed").len(), 3);
}

#[test]
fn signed_data_certificates_no_signed_data() {
let cert = include_bytes!("../test/certs.pem");
let cert = X509::from_pem(cert).unwrap();
let mut certs = Stack::new().unwrap();
certs.push(cert).unwrap();
let message: String = String::from("foo");
let cipher = Cipher::des_ede3_cbc();
let flags = Pkcs7Flags::STREAM;

// Use `Pkcs7::encrypt` since it populates the PKCS7_ENVELOPE struct rather than
// PKCS7_SIGNED
let pkcs7 =
Pkcs7::encrypt(&certs, message.as_bytes(), cipher, flags).expect("should succeed");
assert_eq!(
pkcs7.type_().expect("PKCS7 should have a type").nid(),
Nid::PKCS7_ENVELOPED
);

let signed_data_certs = pkcs7.signed_data_certificates().expect("should succeed");
assert!(signed_data_certs.is_none())
}
}

0 comments on commit 1ef2608

Please sign in to comment.