Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions docs/hazmat/primitives/asymmetric/serialization.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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``.
Expand Down
5 changes: 3 additions & 2 deletions src/cryptography/hazmat/primitives/serialization/pkcs7.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down
58 changes: 58 additions & 0 deletions src/rust/cryptography-x509/src/pkcs7.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<asn1::ObjectIdentifier>,
Expand All @@ -30,6 +35,15 @@ pub enum Content<'a> {
EncryptedData(asn1::Explicit<EncryptedData<'a>, 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,
Expand Down Expand Up @@ -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,
Expand All @@ -76,6 +100,12 @@ pub struct SignerInfo<'a> {
pub unauthenticated_attributes: Option<csr::Attributes<'a>>,
}

// 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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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>,
Expand Down
3 changes: 2 additions & 1 deletion src/rust/src/pkcs7.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))?
Expand Down Expand Up @@ -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;
Expand Down