Enforce that CRL and CSR versions must be valid. (#7249)

Fixes #7231
This commit is contained in:
Alex Gaynor 2022-05-22 19:31:47 -04:00 committed by GitHub
parent 1407dd6339
commit d89cd38afa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 45 additions and 7 deletions

View file

@ -25,6 +25,10 @@ Changelog
details.
* Added two new OpenSSL functions to the bindings to support an upcoming
``pyOpenSSL`` release.
* When parsing :class:`~cryptography.x509.CertificateRevocationList` and
:class:`~cryptography.x509.CertificateSigningRequest` values, it is now
enforced that the ``version`` value in the input must be valid according to
the rules of :rfc:`2986` and :rfc:`5280`.
.. _v37-0-2:

View file

@ -7,7 +7,7 @@ X.509 Reference
pem_crl_data = b"""
-----BEGIN X509 CRL-----
MIIBtDCBnQIBAjANBgkqhkiG9w0BAQsFADAnMQswCQYDVQQGEwJVUzEYMBYGA1UE
MIIBtDCBnQIBATANBgkqhkiG9w0BAQsFADAnMQswCQYDVQQGEwJVUzEYMBYGA1UE
AwwPY3J5cHRvZ3JhcGh5LmlvGA8yMDE1MDEwMTAwMDAwMFoYDzIwMTYwMTAxMDAw
MDAwWjA+MDwCAQAYDzIwMTUwMTAxMDAwMDAwWjAmMBgGA1UdGAQRGA8yMDE1MDEw
MTAwMDAwMFowCgYDVR0VBAMKAQEwDQYJKoZIhvcNAQELBQADggEBABRA4ww50Lz5
@ -508,7 +508,7 @@ X.509 CRL (Certificate Revocation List) Object
>>> from cryptography.hazmat.primitives import hashes
>>> crl.fingerprint(hashes.SHA256())
b'e\xcf.\xc4:\x83?1\xdc\xf3\xfc\x95\xd7\xb3\x87\xb3\x8e\xf8\xb93!\x87\x07\x9d\x1b\xb4!\xb9\xe4W\xf4\x1f'
b'\xe3\x1d\xb5P\x18\x9ed\x9f\x16O\x9dm\xc1>\x8c\xca\xb1\xc6x?T\x9f\xe9t_\x1d\x8dF8V\xf78'
.. method:: get_revoked_certificate_by_serial_number(serial_number)

View file

@ -13,7 +13,7 @@ use std::sync::Arc;
#[pyo3::prelude::pyfunction]
fn load_der_x509_crl(
_py: pyo3::Python<'_>,
py: pyo3::Python<'_>,
data: &[u8],
) -> Result<CertificateRevocationList, PyAsn1Error> {
let raw = OwnedRawCertificateRevocationList::try_new(
@ -22,6 +22,16 @@ fn load_der_x509_crl(
|_| Ok(pyo3::once_cell::GILOnceCell::new()),
)?;
let version = raw.borrow_value().tbs_cert_list.version.unwrap_or(1);
if version != 1 {
let x509_module = py.import("cryptography.x509")?;
return Err(PyAsn1Error::from(pyo3::PyErr::from_instance(
x509_module
.getattr("InvalidVersion")?
.call1((format!("{} is not a valid CRL version", version), version))?,
)));
}
Ok(CertificateRevocationList {
raw: Arc::new(raw),
cached_extensions: None,

View file

@ -328,11 +328,19 @@ fn load_pem_x509_csr(py: pyo3::Python<'_>, data: &[u8]) -> PyAsn1Result<Certific
}
#[pyo3::prelude::pyfunction]
fn load_der_x509_csr(
_py: pyo3::Python<'_>,
data: &[u8],
) -> PyAsn1Result<CertificateSigningRequest> {
fn load_der_x509_csr(py: pyo3::Python<'_>, data: &[u8]) -> PyAsn1Result<CertificateSigningRequest> {
let raw = OwnedRawCsr::try_new(data.to_vec(), |data| asn1::parse_single(data))?;
let version = raw.borrow_value().csr_info.version;
if version != 0 {
let x509_module = py.import("cryptography.x509")?;
return Err(PyAsn1Error::from(pyo3::PyErr::from_instance(
x509_module
.getattr("InvalidVersion")?
.call1((format!("{} is not a valid CSR version", version), version))?,
)));
}
Ok(CertificateSigningRequest {
raw,
cached_extensions: None,

View file

@ -156,6 +156,14 @@ class TestCertificateRevocationList:
with pytest.raises(UnsupportedAlgorithm):
crl.signature_hash_algorithm
def test_invalid_version(self, backend):
with pytest.raises(x509.InvalidVersion):
_load_cert(
os.path.join("x509", "custom", "crl_bad_version.pem"),
x509.load_pem_x509_crl,
backend,
)
def test_issuer(self, backend):
crl = _load_cert(
os.path.join("x509", "PKITS_data", "crls", "GoodCACRL.crl"),
@ -1477,6 +1485,14 @@ class TestRSACertificateRequest:
with pytest.raises(UnsupportedAlgorithm):
request.signature_hash_algorithm
def test_invalid_version(self, backend):
with pytest.raises(x509.InvalidVersion):
_load_cert(
os.path.join("x509", "requests", "bad-version.pem"),
x509.load_pem_x509_csr,
backend,
)
def test_duplicate_extension(self, backend):
request = _load_cert(
os.path.join("x509", "requests", "two_basic_constraints.pem"),