removing caching mechanism for x509 properties
undo name change of CRLExtensionOID
use custom parsing mechanism for certIssuer entry extension
add new crl to vectors for testing invalid certIssuer entry ext
diff --git a/src/_cffi_src/openssl/x509v3.py b/src/_cffi_src/openssl/x509v3.py
index 84e4964..51cac62 100644
--- a/src/_cffi_src/openssl/x509v3.py
+++ b/src/_cffi_src/openssl/x509v3.py
@@ -290,6 +290,8 @@
void DIST_POINT_NAME_free(DIST_POINT_NAME *);
int i2d_CRL_DIST_POINTS(Cryptography_STACK_OF_DIST_POINT *, unsigned char **);
+GENERAL_NAMES *d2i_GENERAL_NAMES(GENERAL_NAMES **, const unsigned char **,
+ long);
"""
CUSTOMIZATIONS = """
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
index 7f7be54..073dfb1 100644
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -19,7 +19,7 @@
from cryptography.exceptions import UnsupportedAlgorithm
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.x509.oid import (
- CertificatePoliciesOID, ExtensionOID, RevokedExtensionOID
+ CRLExtensionOID, CertificatePoliciesOID, ExtensionOID
)
@@ -175,11 +175,11 @@
class _X509ExtensionParser(object):
- def __init__(self, ext_count, get_ext, handlers, supported_versions=None):
+ def __init__(self, ext_count, get_ext, handlers, unsupported_exts=None):
self.ext_count = ext_count
self.get_ext = get_ext
self.handlers = handlers
- self.supported_versions = supported_versions
+ self.unsupported_exts = unsupported_exts
def parse(self, backend, x509_obj):
extensions = []
@@ -190,13 +190,6 @@
crit = backend._lib.X509_EXTENSION_get_critical(ext)
critical = crit == 1
oid = x509.ObjectIdentifier(_obj2txt(backend, ext.object))
-
- # Filter out extensions we know are not supported by the backend
- if (self.supported_versions and oid in self.supported_versions and
- self.supported_versions[oid] >
- backend._lib.OPENSSL_VERSION_NUMBER):
- self.handlers.pop(oid, None)
-
if oid in seen_oids:
raise x509.DuplicateExtension(
"Duplicate {0} extension found".format(oid), oid
@@ -210,15 +203,18 @@
.format(oid), oid
)
else:
- d2i = backend._lib.X509V3_EXT_d2i(ext)
- if d2i == backend._ffi.NULL:
- backend._consume_errors()
- raise ValueError(
- "The {0} extension is invalid and can't be "
- "parsed".format(oid)
- )
+ if self.unsupported_exts and oid in self.unsupported_exts:
+ ext_data = ext
+ else:
+ ext_data = backend._lib.X509V3_EXT_d2i(ext)
+ if ext_data == backend._ffi.NULL:
+ backend._consume_errors()
+ raise ValueError(
+ "The {0} extension is invalid and can't be "
+ "parsed".format(oid)
+ )
- value = handler(backend, d2i)
+ value = handler(backend, ext_data)
extensions.append(x509.Extension(oid, critical, value))
seen_oids.add(oid)
@@ -687,8 +683,18 @@
return datetime.datetime.strptime(time, "%Y%m%d%H%M%SZ")
-def _decode_cert_issuer(backend, issuer):
- gns = backend._ffi.cast("GENERAL_NAMES *", issuer)
+def _decode_cert_issuer(backend, ext):
+ data_ptr_ptr = backend._ffi.new("const unsigned char **")
+ data_ptr_ptr[0] = ext.value.data
+ gns = backend._lib.d2i_GENERAL_NAMES(
+ backend._ffi.NULL, data_ptr_ptr, ext.value.length
+ )
+ if gns == backend._ffi.NULL:
+ backend._consume_errors()
+ raise ValueError(
+ "The {0} extension is corrupted and can't be parsed".format(
+ CRLExtensionOID.CERTIFICATE_ISSUER))
+
gns = backend._ffi.gc(gns, backend._lib.GENERAL_NAMES_free)
return x509.GeneralNames(_decode_general_names(backend, gns))
@@ -699,28 +705,16 @@
self._backend = backend
self._x509_revoked = x509_revoked
- self._serial_number = None
- self._revocation_date = None
- self._extensions = None
-
@property
def serial_number(self):
- if self._serial_number:
- return self._serial_number
-
asn1_int = self._x509_revoked.serialNumber
self._backend.openssl_assert(asn1_int != self._backend._ffi.NULL)
- self._serial_number = self._backend._asn1_integer_to_int(asn1_int)
- return self._serial_number
+ return self._backend._asn1_integer_to_int(asn1_int)
@property
def revocation_date(self):
- if self._revocation_date:
- return self._revocation_date
-
- self._revocation_date = self._backend._parse_asn1_time(
+ return self._backend._parse_asn1_time(
self._x509_revoked.revocationDate)
- return self._revocation_date
@property
def extensions(self):
@@ -765,11 +759,6 @@
self._backend = backend
self._x509_crl = x509_crl
- self._revoked = None
- self._issuer = None
- self._next_update = None
- self._last_update = None
-
def __eq__(self, other):
if not isinstance(other, x509.CertificateRevocationList):
return NotImplemented
@@ -803,38 +792,23 @@
@property
def issuer(self):
- if self._issuer:
- return self._issuer
-
issuer = self._backend._lib.X509_CRL_get_issuer(self._x509_crl)
self._backend.openssl_assert(issuer != self._backend._ffi.NULL)
- self._issuer = _decode_x509_name(self._backend, issuer)
- return self._issuer
+ return _decode_x509_name(self._backend, issuer)
@property
def next_update(self):
- if self._next_update:
- return self._next_update
-
nu = self._backend._lib.X509_CRL_get_nextUpdate(self._x509_crl)
self._backend.openssl_assert(nu != self._backend._ffi.NULL)
- self._next_update = self._backend._parse_asn1_time(nu)
- return self._next_update
+ return self._backend._parse_asn1_time(nu)
@property
def last_update(self):
- if self._last_update:
- return self._last_update
-
lu = self._backend._lib.X509_CRL_get_lastUpdate(self._x509_crl)
self._backend.openssl_assert(lu != self._backend._ffi.NULL)
- self._last_update = self._backend._parse_asn1_time(lu)
- return self._last_update
+ return self._backend._parse_asn1_time(lu)
def _revoked_certificates(self):
- if self._revoked:
- return self._revoked
-
revoked = self._backend._lib.X509_CRL_get_REVOKED(self._x509_crl)
self._backend.openssl_assert(revoked != self._backend._ffi.NULL)
@@ -845,8 +819,7 @@
self._backend.openssl_assert(r != self._backend._ffi.NULL)
revoked_list.append(_RevokedCertificate(self._backend, r))
- self._revoked = revoked_list
- return self._revoked
+ return revoked_list
def __iter__(self):
return iter(self._revoked_certificates())
@@ -943,14 +916,14 @@
}
_REVOKED_EXTENSION_HANDLERS = {
- RevokedExtensionOID.CRL_REASON: _decode_crl_reason,
- RevokedExtensionOID.INVALIDITY_DATE: _decode_invalidity_date,
- RevokedExtensionOID.CERTIFICATE_ISSUER: _decode_cert_issuer,
+ CRLExtensionOID.CRL_REASON: _decode_crl_reason,
+ CRLExtensionOID.INVALIDITY_DATE: _decode_invalidity_date,
+ CRLExtensionOID.CERTIFICATE_ISSUER: _decode_cert_issuer,
}
-_REVOKED_SUPPORTED_VERSIONS = {
- RevokedExtensionOID.CERTIFICATE_ISSUER: 0x10000000,
-}
+_REVOKED_UNSUPPORTED_EXTENSIONS = set([
+ CRLExtensionOID.CERTIFICATE_ISSUER,
+])
_CERTIFICATE_EXTENSION_PARSER = _X509ExtensionParser(
ext_count=lambda backend, x: backend._lib.X509_get_ext_count(x),
@@ -968,5 +941,5 @@
ext_count=lambda backend, x: backend._lib.X509_REVOKED_get_ext_count(x),
get_ext=lambda backend, x, i: backend._lib.X509_REVOKED_get_ext(x, i),
handlers=_REVOKED_EXTENSION_HANDLERS,
- supported_versions=_REVOKED_SUPPORTED_VERSIONS
+ unsupported_exts=_REVOKED_UNSUPPORTED_EXTENSIONS
)
diff --git a/src/cryptography/x509/__init__.py b/src/cryptography/x509/__init__.py
index 6438da9..70e1d3d 100644
--- a/src/cryptography/x509/__init__.py
+++ b/src/cryptography/x509/__init__.py
@@ -28,8 +28,8 @@
)
from cryptography.x509.name import Name, NameAttribute
from cryptography.x509.oid import (
- AuthorityInformationAccessOID, CertificatePoliciesOID, ExtendedKeyUsageOID,
- ExtensionOID, NameOID, ObjectIdentifier, RevokedExtensionOID,
+ AuthorityInformationAccessOID, CRLExtensionOID, CertificatePoliciesOID,
+ ExtendedKeyUsageOID, ExtensionOID, NameOID, ObjectIdentifier,
SignatureAlgorithmOID, _SIG_OIDS_TO_HASH
)
@@ -95,9 +95,9 @@
OID_CPS_QUALIFIER = CertificatePoliciesOID.CPS_QUALIFIER
OID_CPS_USER_NOTICE = CertificatePoliciesOID.CPS_USER_NOTICE
-OID_CERTIFICATE_ISSUER = RevokedExtensionOID.CERTIFICATE_ISSUER
-OID_CRL_REASON = RevokedExtensionOID.CRL_REASON
-OID_INVALIDITY_DATE = RevokedExtensionOID.INVALIDITY_DATE
+OID_CERTIFICATE_ISSUER = CRLExtensionOID.CERTIFICATE_ISSUER
+OID_CRL_REASON = CRLExtensionOID.CRL_REASON
+OID_INVALIDITY_DATE = CRLExtensionOID.INVALIDITY_DATE
OID_CA_ISSUERS = AuthorityInformationAccessOID.CA_ISSUERS
OID_OCSP = AuthorityInformationAccessOID.OCSP
diff --git a/src/cryptography/x509/oid.py b/src/cryptography/x509/oid.py
index 667045a..ead4016 100644
--- a/src/cryptography/x509/oid.py
+++ b/src/cryptography/x509/oid.py
@@ -58,7 +58,7 @@
OCSP_NO_CHECK = ObjectIdentifier("1.3.6.1.5.5.7.48.1.5")
-class RevokedExtensionOID(object):
+class CRLExtensionOID(object):
CERTIFICATE_ISSUER = ObjectIdentifier("2.5.29.29")
CRL_REASON = ObjectIdentifier("2.5.29.21")
INVALIDITY_DATE = ObjectIdentifier("2.5.29.24")
@@ -177,9 +177,9 @@
ExtensionOID.SUBJECT_ALTERNATIVE_NAME: "subjectAltName",
ExtensionOID.ISSUER_ALTERNATIVE_NAME: "issuerAltName",
ExtensionOID.BASIC_CONSTRAINTS: "basicConstraints",
- RevokedExtensionOID.CRL_REASON: "cRLReason",
- RevokedExtensionOID.INVALIDITY_DATE: "invalidityDate",
- RevokedExtensionOID.CERTIFICATE_ISSUER: "certificateIssuer",
+ CRLExtensionOID.CRL_REASON: "cRLReason",
+ CRLExtensionOID.INVALIDITY_DATE: "invalidityDate",
+ CRLExtensionOID.CERTIFICATE_ISSUER: "certificateIssuer",
ExtensionOID.NAME_CONSTRAINTS: "nameConstraints",
ExtensionOID.CRL_DISTRIBUTION_POINTS: "cRLDistributionPoints",
ExtensionOID.CERTIFICATE_POLICIES: "certificatePolicies",
diff --git a/tests/test_x509.py b/tests/test_x509.py
index 347ed1a..ded2f0e 100644
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -204,6 +204,13 @@
backend
)
+ exp_issuer = x509.GeneralNames([
+ x509.DirectoryName(x509.Name([
+ x509.NameAttribute(x509.OID_COUNTRY_NAME, u"US"),
+ x509.NameAttribute(x509.OID_COMMON_NAME, u"cryptography.io"),
+ ]))
+ ])
+
# First revoked cert doesn't have extensions, test if it is handled
# correctly.
rev0 = crl[0]
@@ -225,6 +232,10 @@
x509.OID_CRL_REASON).value
assert reason == x509.ReasonFlags.unspecified
+ issuer = rev1.extensions.get_extension_for_oid(
+ x509.OID_CERTIFICATE_ISSUER).value
+ assert issuer == exp_issuer
+
date = rev1.extensions.get_extension_for_oid(
x509.OID_INVALIDITY_DATE).value
assert isinstance(date, datetime.datetime)
@@ -232,6 +243,7 @@
# Test convenience function.
assert rev1.get_invalidity_date().isoformat() == "2015-01-01T00:00:00"
+ assert rev1.get_certificate_issuer() == exp_issuer
# Check if all reason flags can be found in the CRL.
flags = set(x509.ReasonFlags)
@@ -273,30 +285,17 @@
with pytest.raises(ValueError):
crl[0].extensions
- def test_cert_issuer_ext(self, backend):
- if backend._lib.OPENSSL_VERSION_NUMBER < 0x10000000:
- pytest.skip("Requires a newer OpenSSL. Must be at least 1.0.0")
-
+ def test_invalid_cert_issuer_ext(self, backend):
crl = _load_cert(
- os.path.join("x509", "custom", "crl_all_reasons.pem"),
+ os.path.join(
+ "x509", "custom", "crl_inval_cert_issuer_entry_ext.pem"
+ ),
x509.load_pem_x509_crl,
backend
)
- exp_issuer = x509.GeneralNames([
- x509.DirectoryName(x509.Name([
- x509.NameAttribute(x509.OID_COUNTRY_NAME, u"US"),
- x509.NameAttribute(x509.OID_COMMON_NAME, u"cryptography.io"),
- ]))
- ])
-
- rev = crl[1]
- issuer = rev.extensions.get_extension_for_oid(
- x509.OID_CERTIFICATE_ISSUER).value
- assert issuer == exp_issuer
-
- # Test convenience function.
- assert rev.get_certificate_issuer() == exp_issuer
+ with pytest.raises(ValueError):
+ crl[0].extensions
@pytest.mark.requires_backend_interface(interface=RSABackend)
diff --git a/vectors/cryptography_vectors/x509/custom/crl_inval_cert_issuer_entry_ext.pem b/vectors/cryptography_vectors/x509/custom/crl_inval_cert_issuer_entry_ext.pem
new file mode 100644
index 0000000..a54f240
--- /dev/null
+++ b/vectors/cryptography_vectors/x509/custom/crl_inval_cert_issuer_entry_ext.pem
@@ -0,0 +1,11 @@
+-----BEGIN X509 CRL-----
+MIIBlzCBgAIBAjANBgkqhkiG9w0BAQsFADAnMQswCQYDVQQGEwJVUzEYMBYGA1UE
+AwwPY3J5cHRvZ3JhcGh5LmlvGA8yMDE1MDEwMTAwMDAwMFoYDzIwMTYwMTAxMDAw
+MDAwWjAhMB8CAQAYDzIwMTUwMTAxMDAwMDAwWjAJMAcGA1UdHQQAMA0GCSqGSIb3
+DQEBCwUAA4IBAQCRSNP2LfnpubvOrZ8/UsETlVTvMNc38xM6dqzYKQV8vN+fcMXP
+1z/nTMBGNvnp7u7S+Dx/1Klq/iArtP5oOdNDeVuapfUdDgFJryXkvgX+2B0g/l9+
+/fiH9YNTEG6Yj2XC3lsVwXhid1Sx+A+b8ZXBdyjyZSJSoejPhzO5p/SQAk+ahY3I
+FZeL3CXlUUi1v3MtVLBPUQZvepZ9mIv5uRsEmHXFf6uTLmMdV/j7cQn4/K53Qb1N
+e+2WpNJOv0UIDugn2DKACF108T1YgZTcx2F4TYpnVDDkyjK4J1IMBrNie8hWA/R3
+y/9oP0PihPDhi4jcVBpDW7pRPqee+4z1KqXg
+-----END X509 CRL-----