Skip to content

Commit

Permalink
add CRL pyopenssl fallback (#6325)
Browse files Browse the repository at this point in the history
* add tests to verify we haven't broken the current pyopenssl release

* add CRL pyopenssl fallback

* simplify CRL with helpers

* more readable pyopenssl-release
  • Loading branch information
reaperhulk committed Sep 28, 2021
1 parent 57e5176 commit 0f2c416
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 10 deletions.
18 changes: 18 additions & 0 deletions .github/downstream.d/pyopenssl-release.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash -ex

case "${1}" in
install)
VERSION=$(curl https://pypi.org/pypi/pyOpenSSL/json | jq -r .info.version)
git clone https://github.com/pyca/pyopenssl
cd pyopenssl
git checkout "$VERSION"
pip install -e ".[test]"
;;
run)
cd pyopenssl
pytest tests
;;
*)
exit 1
;;
esac
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,7 @@ jobs:
DOWNSTREAM:
- paramiko
- pyopenssl
- pyopenssl-release
- aws-encryption-sdk
- dynamodb-encryption-sdk
- certbot
Expand Down
28 changes: 18 additions & 10 deletions src/cryptography/hazmat/backends/openssl/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -1140,10 +1140,7 @@ def create_x509_crl(
errors = self._consume_errors_with_text()
raise ValueError("Signing failed", errors)

bio = self._create_mem_bio_gc()
res = self._lib.i2d_X509_CRL_bio(bio, x509_crl)
self.openssl_assert(res == 1)
return rust_x509.load_der_x509_crl(self._read_mem_bio(bio))
return self._ossl2crl(x509_crl)

def _create_x509_extensions(
self, extensions, handlers, x509_obj, add_func, gc
Expand Down Expand Up @@ -1377,6 +1374,22 @@ def _ossl2csr(
self.openssl_assert(res == 1)
return rust_x509.load_der_x509_csr(self._read_mem_bio(bio))

def _crl2ossl(self, crl: x509.CertificateRevocationList) -> typing.Any:
data = crl.public_bytes(serialization.Encoding.DER)
mem_bio = self._bytes_to_bio(data)
x509_crl = self._lib.d2i_X509_CRL_bio(mem_bio.bio, self._ffi.NULL)
self.openssl_assert(x509_crl != self._ffi.NULL)
x509_crl = self._ffi.gc(x509_crl, self._lib.X509_CRL_free)
return x509_crl

def _ossl2crl(
self, x509_crl: typing.Any
) -> x509.CertificateRevocationList:
bio = self._create_mem_bio_gc()
res = self._lib.i2d_X509_CRL_bio(bio, x509_crl)
self.openssl_assert(res == 1)
return rust_x509.load_der_x509_crl(self._read_mem_bio(bio))

def _crl_is_signature_valid(
self, crl: x509.CertificateRevocationList, public_key: PUBLIC_KEY_TYPES
) -> bool:
Expand All @@ -1392,12 +1405,7 @@ def _crl_is_signature_valid(
"Expecting one of DSAPublicKey, RSAPublicKey,"
" or EllipticCurvePublicKey."
)
data = crl.public_bytes(serialization.Encoding.DER)
mem_bio = self._bytes_to_bio(data)
x509_crl = self._lib.d2i_X509_CRL_bio(mem_bio.bio, self._ffi.NULL)
self.openssl_assert(x509_crl != self._ffi.NULL)
x509_crl = self._ffi.gc(x509_crl, self._lib.X509_CRL_free)

x509_crl = self._crl2ossl(crl)
res = self._lib.X509_CRL_verify(x509_crl, public_key._evp_pkey)

if res != 1:
Expand Down
13 changes: 13 additions & 0 deletions src/cryptography/hazmat/backends/openssl/x509.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,19 @@ def _CertificateSigningRequest( # noqa: N802
return backend._ossl2csr(x509_req)


# This exists for pyOpenSSL compatibility and SHOULD NOT BE USED
# WE WILL REMOVE THIS VERY SOON.
def _CertificateRevocationList( # noqa: N802
backend, x509_crl
) -> x509.CertificateRevocationList:
warnings.warn(
"This version of cryptography contains a temporary pyOpenSSL "
"fallback path. Upgrade pyOpenSSL now.",
utils.DeprecatedIn35,
)
return backend._ossl2crl(x509_crl)


class _RawRevokedCertificate(x509.RevokedCertificate):
def __init__(
self,
Expand Down
22 changes: 22 additions & 0 deletions src/rust/src/x509.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1043,6 +1043,28 @@ impl CertificateRevocationList {
.getattr("backend")?;
backend.call_method1("_crl_is_signature_valid", (slf, public_key))
}

// This getter exists for compatibility with pyOpenSSL and will be removed.
// DO NOT RELY ON IT. WE WILL BREAK YOU WHEN WE FEEL LIKE IT.
#[getter]
fn _x509_crl<'p>(
slf: pyo3::PyRef<'_, Self>,
py: pyo3::Python<'p>,
) -> Result<&'p pyo3::PyAny, PyAsn1Error> {
let cryptography_warning = py.import("cryptography.utils")?.getattr("DeprecatedIn35")?;
let warnings = py.import("warnings")?;
warnings.call_method1(
"warn",
(
"This version of cryptography contains a temporary pyOpenSSL fallback path. Upgrade pyOpenSSL now.",
cryptography_warning,
),
)?;
let backend = py
.import("cryptography.hazmat.backends.openssl.backend")?
.getattr("backend")?;
Ok(backend.call_method1("_crl2ossl", (slf,))?)
}
}

#[pyo3::prelude::pyproto]
Expand Down
18 changes: 18 additions & 0 deletions tests/hazmat/backends/test_openssl.py
Original file line number Diff line number Diff line change
Expand Up @@ -708,3 +708,21 @@ def test_pyopenssl_csr_fallback():

with pytest.warns(utils.CryptographyDeprecationWarning):
_CertificateSigningRequest(backend, req_ossl)


def test_pyopenssl_crl_fallback():
cert = _load_cert(
os.path.join("x509", "PKITS_data", "crls", "GoodCACRL.crl"),
x509.load_der_x509_crl,
)
req_crl = None
with pytest.warns(utils.CryptographyDeprecationWarning):
req_crl = cert._x509_crl
assert req_crl is not None

from cryptography.hazmat.backends.openssl.x509 import (
_CertificateRevocationList,
)

with pytest.warns(utils.CryptographyDeprecationWarning):
_CertificateRevocationList(backend, req_crl)

0 comments on commit 0f2c416

Please sign in to comment.