Skip to content

Commit

Permalink
first failing code for certificate verification
Browse files Browse the repository at this point in the history
  • Loading branch information
nitneuqr committed Jan 11, 2025
1 parent aaa8cae commit e47d6df
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 1 deletion.
6 changes: 6 additions & 0 deletions docs/hazmat/primitives/asymmetric/serialization.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1695,6 +1695,12 @@ contain certificates, CRLs, and much more. PKCS7 files commonly have a ``p7b``,
obtain the signer's certificate by other means (for example from a
previously signed message).

.. attribute:: NoVerify

For S/MIME verification only. Don't verify signers certificate. This is
useful when the signer's certificate is not available or when the signer's
certificate is not trusted.

Serialization Formats
~~~~~~~~~~~~~~~~~~~~~

Expand Down
8 changes: 8 additions & 0 deletions src/cryptography/hazmat/primitives/serialization/pkcs7.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
algorithms,
)
from cryptography.utils import _check_byteslike
from cryptography.x509.verification import PolicyBuilder, Store

load_pem_pkcs7_certificates = rust_pkcs7.load_pem_pkcs7_certificates

Expand Down Expand Up @@ -51,6 +52,7 @@ class PKCS7Options(utils.Enum):
NoCapabilities = "Don't embed SMIME capabilities"
NoAttributes = "Don't embed authenticatedAttributes"
NoCerts = "Don't embed signer certificate"
NoVerify = "Don't verify signers certificate"


class PKCS7SignatureBuilder:
Expand Down Expand Up @@ -390,6 +392,12 @@ def _smime_signed_decode(data: bytes) -> tuple[bytes | None, bytes]:
raise ValueError("Not an S/MIME signed message")


def _verify_pkcs7_certificates(certificates: list[x509.Certificate]) -> None:
builder = PolicyBuilder().store(Store(certificates))
verifier = builder.build_client_verifier()
verifier.verify(certificates[0], certificates[1:])


def _smime_enveloped_encode(data: bytes) -> bytes:
m = email.message.Message()
m.add_header("MIME-Version", "1.0")
Expand Down
21 changes: 20 additions & 1 deletion src/rust/src/pkcs7.rs
Original file line number Diff line number Diff line change
Expand Up @@ -800,7 +800,14 @@ fn verify_der<'p>(
data,
)?;

// TODO: verify the certificates?
// Verify the certificate
if !options.contains(types::PKCS7_NO_VERIFY.get(py)?)? {
let certificates = pyo3::types::PyList::empty(py);
certificates.append(certificate)?;
types::VERIFY_PKCS7_CERTIFICATES
.get(py)?
.call1((certificates,))?;
}
}
_ => {
return Err(CryptographyError::from(
Expand Down Expand Up @@ -830,6 +837,18 @@ fn check_verify_options<'p>(
}
}

// Check if any option is not PKCS7Options::NoVerify
let no_verify_option = types::PKCS7_NO_VERIFY.get(py)?;
for opt in options.iter() {
if !opt.eq(no_verify_option.clone())? {
return Err(CryptographyError::from(
pyo3::exceptions::PyValueError::new_err(
"Only the following options are supported for verification: NoVerify",
),
));
}
}

Ok(())
}

Expand Down
9 changes: 9 additions & 0 deletions src/rust/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,10 @@ pub static PKCS7_DETACHED_SIGNATURE: LazyPyImport = LazyPyImport::new(
"cryptography.hazmat.primitives.serialization.pkcs7",
&["PKCS7Options", "DetachedSignature"],
);
pub static PKCS7_NO_VERIFY: LazyPyImport = LazyPyImport::new(
"cryptography.hazmat.primitives.serialization.pkcs7",
&["PKCS7Options", "NoVerify"],
);

pub static SMIME_ENVELOPED_ENCODE: LazyPyImport = LazyPyImport::new(
"cryptography.hazmat.primitives.serialization.pkcs7",
Expand All @@ -375,6 +379,11 @@ pub static SMIME_SIGNED_DECODE: LazyPyImport = LazyPyImport::new(
&["_smime_signed_decode"],
);

pub static VERIFY_PKCS7_CERTIFICATES: LazyPyImport = LazyPyImport::new(
"cryptography.hazmat.primitives.serialization.pkcs7",
&["_verify_pkcs7_certificates"],
);

pub static PKCS12KEYANDCERTIFICATES: LazyPyImport = LazyPyImport::new(
"cryptography.hazmat.primitives.serialization.pkcs12",
&["PKCS12KeyAndCertificates"],
Expand Down
15 changes: 15 additions & 0 deletions tests/hazmat/primitives/test_pkcs7.py
Original file line number Diff line number Diff line change
Expand Up @@ -924,6 +924,21 @@ def test_pkcs7_verify_der_no_content(
# Verification
pkcs7.pkcs7_verify_der(signature, None, certificate, [])

def test_pkcs7_verify_der_no_verify(
self, backend, data, certificate, private_key
):
# Signature
builder = (
pkcs7.PKCS7SignatureBuilder()
.set_data(data)
.add_signer(certificate, private_key, hashes.SHA256())
)
signature = builder.sign(serialization.Encoding.DER, [])

# Verification
options = [pkcs7.PKCS7Options.NoVerify]
pkcs7.pkcs7_verify_der(signature, data, certificate, options)

def test_pkcs7_verify_der_no_data(
self, backend, data, certificate, private_key
):
Expand Down

0 comments on commit e47d6df

Please sign in to comment.