diff --git a/docs/hazmat/primitives/asymmetric/serialization.rst b/docs/hazmat/primitives/asymmetric/serialization.rst index c9fd3605a727..a19f71b0d428 100644 --- a/docs/hazmat/primitives/asymmetric/serialization.rst +++ b/docs/hazmat/primitives/asymmetric/serialization.rst @@ -1266,8 +1266,8 @@ contain certificates, CRLs, and much more. PKCS7 files commonly have a ``p7b``, The PKCS7 signature builder can create both basic PKCS7 signed messages as well as S/MIME messages, which are commonly used in email. S/MIME has - multiple versions, but this implements a subset of :rfc:`2632`, also known - as S/MIME Version 3. + multiple versions, most of this implementation follows S/MIME 2.0 (RFC 2311). + Only a small subset of :rfc:`2632`, also known as S/MIME version 3 is supported. .. versionadded:: 3.2 @@ -1344,8 +1344,8 @@ contain certificates, CRLs, and much more. PKCS7 files commonly have a ``p7b``, The PKCS7 envelope builder can create encrypted S/MIME messages, which are commonly used in email. S/MIME has multiple versions, - but this implements a subset of :rfc:`5751`, also known as S/MIME - Version 3.2. + most of this implementation follows S/MIME 2.0 (RFC 2311). + Only a small subset of :rfc:`2632`, also known as S/MIME version 3 is supported. .. versionadded:: 43.0.0 @@ -1434,7 +1434,8 @@ contain certificates, CRLs, and much more. PKCS7 files commonly have a ``p7b``, b'data to encrypt' Deserialize and decrypt a DER-encoded PKCS7 message. PKCS7 (or S/MIME) has multiple versions, - but this supports a subset of :rfc:`5751`, also known as S/MIME Version 3.2. + most of this implementation follows S/MIME 2.0 (RFC 2311). A small subset of :rfc:`2632`, + also known as S/MIME version 3 is supported. :param data: The data, encoded in DER format. :type data: bytes @@ -1489,8 +1490,9 @@ contain certificates, CRLs, and much more. PKCS7 files commonly have a ``p7b``, >>> pkcs7.pkcs7_decrypt_pem(enveloped, cert, key, options) b'data to encrypt' - Deserialize and decrypt a PEM-encoded PKCS7E message. PKCS7 (or S/MIME) has multiple versions, - but this supports a subset of :rfc:`5751`, also known as S/MIME Version 3.2. + Deserialize and decrypt a PEM-encoded PKCS7 message. PKCS7 (or S/MIME) has multiple versions, + most of this implementation follows S/MIME 2.0 (RFC 2311). A small subset of :rfc:`2632`, + also known as S/MIME version 3 is supported. :param data: The data, encoded in PEM format. :type data: bytes @@ -1547,7 +1549,8 @@ contain certificates, CRLs, and much more. PKCS7 files commonly have a ``p7b``, b'data to encrypt' Deserialize and decrypt a S/MIME-encoded PKCS7 message. PKCS7 (or S/MIME) has multiple versions, - but this supports a subset of :rfc:`5751`, also known as S/MIME Version 3.2. + most of this implementation follows S/MIME 2.0 (RFC 2311). A small subset of :rfc:`2632`, + also known as S/MIME version 3 is supported. :param data: The data. It should be in S/MIME format, meaning MIME with content type ``application/pkcs7-mime`` or ``application/x-pkcs7-mime``. diff --git a/src/cryptography/hazmat/primitives/serialization/pkcs7.py b/src/cryptography/hazmat/primitives/serialization/pkcs7.py index 456dc5b0831c..4fac500c8b50 100644 --- a/src/cryptography/hazmat/primitives/serialization/pkcs7.py +++ b/src/cryptography/hazmat/primitives/serialization/pkcs7.py @@ -266,8 +266,9 @@ def encrypt( if self._data is None: raise ValueError("You must add data to encrypt") - # The default content encryption algorithm is AES-128, which the S/MIME - # v3.2 RFC specifies as MUST support (https://datatracker.ietf.org/doc/html/rfc5751#section-2.7) + # The default content encryption algorithm is AES-128-CBC, which the + # S/MIME v3.2 RFC specifies as MUST support (https://datatracker.ietf.org/doc/html/rfc5751#section-2.7) + # however rest of S/MIME v3.2 is not currently supported content_encryption_algorithm = ( self._content_encryption_algorithm or algorithms.AES128 ) diff --git a/src/rust/cryptography-x509/src/pkcs7.rs b/src/rust/cryptography-x509/src/pkcs7.rs index c1f2626f2f5c..5538675b81cd 100644 --- a/src/rust/cryptography-x509/src/pkcs7.rs +++ b/src/rust/cryptography-x509/src/pkcs7.rs @@ -9,6 +9,11 @@ pub const PKCS7_SIGNED_DATA_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, pub const PKCS7_ENVELOPED_DATA_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 7, 3); pub const PKCS7_ENCRYPTED_DATA_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 7, 6); +// RFC 2315 section 7 +// +// ContentInfo ::= SEQUENCE { +// contentType ContentType, +// content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL } #[derive(asn1::Asn1Write, asn1::Asn1Read)] pub struct ContentInfo<'a> { pub _content_type: asn1::DefinedByMarker, @@ -30,6 +35,15 @@ pub enum Content<'a> { EncryptedData(asn1::Explicit, 0>), } +// RFC 2315 section 9.1 +// +// SignedData ::= SEQUENCE { +// version Version, +// digestAlgorithms DigestAlgorithmIdentifiers, +// contentInfo ContentInfo, +// certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL, +// crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, +// signerInfos SignerInfos } #[derive(asn1::Asn1Write, asn1::Asn1Read)] pub struct SignedData<'a> { pub version: u8, @@ -61,6 +75,16 @@ pub struct SignedData<'a> { >, } +// RFC 2315 section 9.2 +// +// SignerInfo ::= SEQUENCE { +// version Version, +// issuerAndSerialNumber IssuerAndSerialNumber, +// digestAlgorithm DigestAlgorithmIdentifier, +// authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL, +// digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier, +// encryptedDigest EncryptedDigest, +// unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL } #[derive(asn1::Asn1Write, asn1::Asn1Read)] pub struct SignerInfo<'a> { pub version: u8, @@ -76,6 +100,12 @@ pub struct SignerInfo<'a> { pub unauthenticated_attributes: Option>, } +// RFC 2315 section 10.1 +// +// EnvelopedData ::= SEQUENCE { +// version Version, +// recipientInfos RecipientInfos, +// encryptedContentInfo EncryptedContentInfo } #[derive(asn1::Asn1Write, asn1::Asn1Read)] pub struct EnvelopedData<'a> { pub version: u8, @@ -86,6 +116,13 @@ pub struct EnvelopedData<'a> { pub encrypted_content_info: EncryptedContentInfo<'a>, } +// RFC 2315 section 10.2 +// +// RecipientInfo ::= SEQUENCE { +// version Version, +// issuerAndSerialNumber IssuerAndSerialNumber, +// keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, +// encryptedKey EncryptedKey } #[derive(asn1::Asn1Write, asn1::Asn1Read)] pub struct RecipientInfo<'a> { pub version: u8, @@ -94,18 +131,34 @@ pub struct RecipientInfo<'a> { pub encrypted_key: &'a [u8], } +// RFC 2315 section 6.7 +// +// IssuerAndSerialNumber ::= SEQUENCE { +// issuer Name, +// serialNumber CertificateSerialNumber } #[derive(asn1::Asn1Write, asn1::Asn1Read)] pub struct IssuerAndSerialNumber<'a> { pub issuer: name::Name<'a>, pub serial_number: asn1::BigInt<'a>, } +// RFC 2315 section 13 +// +// EncryptedData ::= SEQUENCE { +// version Version, +// encryptedContentInfo EncryptedContentInfo } #[derive(asn1::Asn1Write, asn1::Asn1Read)] pub struct EncryptedData<'a> { pub version: u8, pub encrypted_content_info: EncryptedContentInfo<'a>, } +// RFC 2315 section 10.1 +// +// EncryptedContentInfo ::= SEQUENCE { +// contentType ContentType, +// contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, +// encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL } #[derive(asn1::Asn1Write, asn1::Asn1Read)] pub struct EncryptedContentInfo<'a> { pub content_type: asn1::ObjectIdentifier, @@ -114,6 +167,11 @@ pub struct EncryptedContentInfo<'a> { pub encrypted_content: Option<&'a [u8]>, } +// RFC 2315 section 9.4 +// +// DigestInfo ::= SEQUENCE { +// digestAlgorithm DigestAlgorithmIdentifier, +// digest Digest } #[derive(asn1::Asn1Write, asn1::Asn1Read)] pub struct DigestInfo<'a> { pub algorithm: common::AlgorithmIdentifier<'a>, diff --git a/src/rust/src/pkcs7.rs b/src/rust/src/pkcs7.rs index ae1d15d5ec78..541b13e64b53 100644 --- a/src/rust/src/pkcs7.rs +++ b/src/rust/src/pkcs7.rs @@ -130,6 +130,7 @@ fn encrypt_and_serialize<'p>( for cert in py_recipients.iter() { // Currently, keys are encrypted with RSA (PKCS #1 v1.5), which the S/MIME v3.2 RFC // specifies as MUST support (https://datatracker.ietf.org/doc/html/rfc5751#section-2.3) + // however rest of S/MIME v3.2 is not currently supported let encrypted_key = cert .call_method0(pyo3::intern!(py, "public_key"))? .call_method1(pyo3::intern!(py, "encrypt"), (&key, &padding))? @@ -293,7 +294,7 @@ fn decrypt_der<'p>( // The function can decrypt content encrypted with AES-128-CBC, which the S/MIME v3.2 // RFC specifies as MUST support, and AES-256-CBC, which is specified as SHOULD+ // support. More info: https://datatracker.ietf.org/doc/html/rfc5751#section-2.7 - // TODO: implement the possible algorithms from S/MIME 3.2 (and 4.0?) + // however rest of S/MIME v3.2 is not currently supported let algorithm_identifier = enveloped_data .encrypted_content_info .content_encryption_algorithm;