aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErik Trauschke <erik.trauschke@gmail.com>2015-10-15 14:45:38 -0700
committerErik Trauschke <erik.trauschke@gmail.com>2015-10-15 14:45:38 -0700
commitd4e7d43416077f18a37008298abdc566bd3f069d (patch)
tree8052c19063d69fe93ac301e1c3d03fda99e06086
parent164bae538cfe5fcb320ebe5ee7e080598ad7ec5f (diff)
downloadcryptography-d4e7d43416077f18a37008298abdc566bd3f069d.tar.gz
cryptography-d4e7d43416077f18a37008298abdc566bd3f069d.tar.bz2
cryptography-d4e7d43416077f18a37008298abdc566bd3f069d.zip
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
-rw-r--r--src/_cffi_src/openssl/x509v3.py2
-rw-r--r--src/cryptography/hazmat/backends/openssl/x509.py107
-rw-r--r--src/cryptography/x509/__init__.py10
-rw-r--r--src/cryptography/x509/oid.py8
-rw-r--r--tests/test_x509.py37
-rw-r--r--vectors/cryptography_vectors/x509/custom/crl_inval_cert_issuer_entry_ext.pem11
6 files changed, 80 insertions, 95 deletions
diff --git a/src/_cffi_src/openssl/x509v3.py b/src/_cffi_src/openssl/x509v3.py
index 84e49640..51cac62b 100644
--- a/src/_cffi_src/openssl/x509v3.py
+++ b/src/_cffi_src/openssl/x509v3.py
@@ -290,6 +290,8 @@ DIST_POINT_NAME *DIST_POINT_NAME_new(void);
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 7f7be545..073dfb1e 100644
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -19,7 +19,7 @@ from cryptography import utils, x509
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 @@ def _decode_ocsp_no_check(backend, ext):
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 @@ class _X509ExtensionParser(object):
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 @@ class _X509ExtensionParser(object):
.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)
- )
-
- value = handler(backend, d2i)
+ 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, ext_data)
extensions.append(x509.Extension(oid, critical, value))
seen_oids.add(oid)
@@ -687,8 +683,18 @@ def _decode_invalidity_date(backend, inv_date):
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 @@ class _RevokedCertificate(object):
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 @@ class _CertificateRevocationList(object):
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 @@ class _CertificateRevocationList(object):
@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 @@ class _CertificateRevocationList(object):
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 @@ _EXTENSION_HANDLERS = {
}
_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 @@ _REVOKED_CERTIFICATE_EXTENSION_PARSER = _X509ExtensionParser(
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 6438da9c..70e1d3da 100644
--- a/src/cryptography/x509/__init__.py
+++ b/src/cryptography/x509/__init__.py
@@ -28,8 +28,8 @@ from cryptography.x509.general_name import (
)
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_ANY_POLICY = CertificatePoliciesOID.ANY_POLICY
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 667045af..ead40169 100644
--- a/src/cryptography/x509/oid.py
+++ b/src/cryptography/x509/oid.py
@@ -58,7 +58,7 @@ class ExtensionOID(object):
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 @@ _OID_NAMES = {
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 347ed1a6..ded2f0ee 100644
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -204,6 +204,13 @@ class TestRevokedCertificate(object):
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 @@ class TestRevokedCertificate(object):
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 @@ class TestRevokedCertificate(object):
# 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 @@ class TestRevokedCertificate(object):
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 00000000..a54f2409
--- /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-----