@@ -9,11 +9,17 @@ use std::ops::Deref;
99use cryptography_x509:: csr:: Attribute ;
1010use cryptography_x509:: { common, oid, pkcs7} ;
1111use once_cell:: sync:: Lazy ;
12+ #[ cfg( not( CRYPTOGRAPHY_IS_BORINGSSL ) ) ]
13+ use openssl:: pkcs7:: Pkcs7 ;
14+ #[ cfg( not( CRYPTOGRAPHY_IS_BORINGSSL ) ) ]
15+ use pyo3:: IntoPy ;
1216
1317use crate :: asn1:: encode_der_data;
1418use crate :: buf:: CffiBuf ;
15- use crate :: error:: CryptographyResult ;
16- use crate :: { types, x509} ;
19+ use crate :: error:: { CryptographyError , CryptographyResult } ;
20+ #[ cfg( not( CRYPTOGRAPHY_IS_BORINGSSL ) ) ]
21+ use crate :: x509:: certificate:: load_der_x509_certificate;
22+ use crate :: { exceptions, types, x509} ;
1723
1824const PKCS7_CONTENT_TYPE_OID : asn1:: ObjectIdentifier = asn1:: oid!( 1 , 2 , 840 , 113549 , 1 , 9 , 3 ) ;
1925const PKCS7_MESSAGE_DIGEST_OID : asn1:: ObjectIdentifier = asn1:: oid!( 1 , 2 , 840 , 113549 , 1 , 9 , 4 ) ;
@@ -290,11 +296,96 @@ fn smime_canonicalize(data: &[u8], text_mode: bool) -> (Cow<'_, [u8]>, Cow<'_, [
290296 }
291297}
292298
299+ #[ cfg( not( CRYPTOGRAPHY_IS_BORINGSSL ) ) ]
300+ fn load_pkcs7_certificates (
301+ py : pyo3:: Python < ' _ > ,
302+ pkcs7 : Pkcs7 ,
303+ ) -> CryptographyResult < & pyo3:: types:: PyList > {
304+ let nid = pkcs7. type_ ( ) . map ( |t| t. nid ( ) ) ;
305+ if nid != Some ( openssl:: nid:: Nid :: PKCS7_SIGNED ) {
306+ let nid_string = nid. map_or ( "empty" . to_string ( ) , |n| n. as_raw ( ) . to_string ( ) ) ;
307+ return Err ( CryptographyError :: from (
308+ exceptions:: UnsupportedAlgorithm :: new_err ( (
309+ format ! ( "Only basic signed structures are currently supported. NID for this data was {}" , nid_string) ,
310+ exceptions:: Reasons :: UNSUPPORTED_SERIALIZATION ,
311+ ) ) ,
312+ ) ) ;
313+ }
314+
315+ let signed_certificates = pkcs7. signed ( ) . and_then ( |x| x. certificates ( ) ) ;
316+ match signed_certificates {
317+ None => Err ( CryptographyError :: from (
318+ pyo3:: exceptions:: PyValueError :: new_err (
319+ "The provided PKCS7 has no certificate data, but a cert loading method was called." ,
320+ ) ,
321+ ) ) ,
322+ Some ( certificates) => {
323+ let result = pyo3:: types:: PyList :: empty ( py) ;
324+ for c in certificates {
325+ let cert_der = pyo3:: types:: PyBytes :: new ( py, c. to_der ( ) ?. as_slice ( ) ) . into_py ( py) ;
326+ let cert = load_der_x509_certificate ( py, cert_der, None ) ?;
327+ result. append ( cert. into_py ( py) ) ?;
328+ }
329+ Ok ( result)
330+ }
331+ }
332+ }
333+
334+ #[ pyo3:: prelude:: pyfunction]
335+ fn load_pem_pkcs7_certificates < ' p > (
336+ py : pyo3:: Python < ' p > ,
337+ data : & [ u8 ] ,
338+ ) -> CryptographyResult < & ' p pyo3:: types:: PyList > {
339+ cfg_if:: cfg_if! {
340+ if #[ cfg( not( CRYPTOGRAPHY_IS_BORINGSSL ) ) ] {
341+ let pkcs7_decoded = openssl:: pkcs7:: Pkcs7 :: from_pem( data) . map_err( |_| {
342+ CryptographyError :: from( pyo3:: exceptions:: PyValueError :: new_err(
343+ "Unable to parse PKCS7 data" ,
344+ ) )
345+ } ) ?;
346+ load_pkcs7_certificates( py, pkcs7_decoded)
347+ } else {
348+ return Err ( CryptographyError :: from(
349+ exceptions:: UnsupportedAlgorithm :: new_err( (
350+ "PKCS#7 is not supported by this backend." ,
351+ exceptions:: Reasons :: UNSUPPORTED_SERIALIZATION ,
352+ ) ) ,
353+ ) ) ;
354+ }
355+ }
356+ }
357+
358+ #[ pyo3:: prelude:: pyfunction]
359+ fn load_der_pkcs7_certificates < ' p > (
360+ py : pyo3:: Python < ' p > ,
361+ data : & [ u8 ] ,
362+ ) -> CryptographyResult < & ' p pyo3:: types:: PyList > {
363+ cfg_if:: cfg_if! {
364+ if #[ cfg( not( CRYPTOGRAPHY_IS_BORINGSSL ) ) ] {
365+ let pkcs7_decoded = openssl:: pkcs7:: Pkcs7 :: from_der( data) . map_err( |_| {
366+ CryptographyError :: from( pyo3:: exceptions:: PyValueError :: new_err(
367+ "Unable to parse PKCS7 data" ,
368+ ) )
369+ } ) ?;
370+ load_pkcs7_certificates( py, pkcs7_decoded)
371+ } else {
372+ return Err ( CryptographyError :: from(
373+ exceptions:: UnsupportedAlgorithm :: new_err( (
374+ "PKCS#7 is not supported by this backend." ,
375+ exceptions:: Reasons :: UNSUPPORTED_SERIALIZATION ,
376+ ) ) ,
377+ ) ) ;
378+ }
379+ }
380+ }
381+
293382pub ( crate ) fn create_submodule ( py : pyo3:: Python < ' _ > ) -> pyo3:: PyResult < & pyo3:: prelude:: PyModule > {
294383 let submod = pyo3:: prelude:: PyModule :: new ( py, "pkcs7" ) ?;
295384
296385 submod. add_function ( pyo3:: wrap_pyfunction!( serialize_certificates, submod) ?) ?;
297386 submod. add_function ( pyo3:: wrap_pyfunction!( sign_and_serialize, submod) ?) ?;
387+ submod. add_function ( pyo3:: wrap_pyfunction!( load_pem_pkcs7_certificates, submod) ?) ?;
388+ submod. add_function ( pyo3:: wrap_pyfunction!( load_der_pkcs7_certificates, submod) ?) ?;
298389
299390 Ok ( submod)
300391}
0 commit comments