diff options
-rw-r--r-- | docs/x509.rst | 1 | ||||
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/x509.py | 37 | ||||
-rw-r--r-- | tests/test_x509_ext.py | 60 |
3 files changed, 89 insertions, 9 deletions
diff --git a/docs/x509.rst b/docs/x509.rst index d09651fb..19f7c405 100644 --- a/docs/x509.rst +++ b/docs/x509.rst @@ -276,6 +276,7 @@ X.509 Certificate Object >>> for ext in cert.extensions: ... print(ext) <Extension(oid=<ObjectIdentifier(oid=2.5.29.14, name=subjectKeyIdentifier)>, critical=False, value=<SubjectKeyIdentifier(digest='X\x01\x84$\x1b\xbc+R\x94J=\xa5\x10r\x14Q\xf5\xaf:\xc9')>)> + <Extension(oid=<ObjectIdentifier(oid=2.5.29.15, name=keyUsage)>, critical=True, value=<KeyUsage(digital_signature=False, content_commitment=False, key_encipherment=False, data_encipherment=False, key_agreement=False, key_cert_sign=True, crl_sign=True, encipher_only=N/A, decipher_only=N/A)>)> <Extension(oid=<ObjectIdentifier(oid=2.5.29.19, name=basicConstraints)>, critical=True, value=<BasicConstraints(ca=True, path_length=None)>)> X.509 CSR (Certificate Signing Request) Object diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 5d47c5ea..13f57e84 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -14,7 +14,6 @@ from __future__ import absolute_import, division, print_function import datetime -import warnings from cryptography import utils, x509 from cryptography.exceptions import UnsupportedAlgorithm @@ -172,14 +171,8 @@ class _Certificate(object): value = self._build_basic_constraints(ext) elif oid == x509.OID_SUBJECT_KEY_IDENTIFIER: value = self._build_subject_key_identifier(ext) - elif oid == x509.OID_KEY_USAGE and critical: - # TODO: remove this obviously. - warnings.warn( - "Extension support is not fully implemented. A key usage " - "extension with the critical flag was seen and IGNORED." - ) - seen_oids.add(oid) - continue + elif oid == x509.OID_KEY_USAGE: + value = self._build_key_usage(ext) elif critical: raise x509.UnsupportedExtension( "{0} is not currently supported".format(oid), oid @@ -232,6 +225,32 @@ class _Certificate(object): self._backend._ffi.buffer(asn1_string.data, asn1_string.length)[:] ) + def _build_key_usage(self, ext): + bit_string = self._backend._lib.X509V3_EXT_d2i(ext) + assert bit_string != self._backend._ffi.NULL + bit_string = self._backend._ffi.cast("ASN1_BIT_STRING *", bit_string) + get_bit = self._backend._lib.ASN1_BIT_STRING_get_bit + digital_signature = get_bit(bit_string, 0) == 1 + content_commitment = get_bit(bit_string, 1) == 1 + key_encipherment = get_bit(bit_string, 2) == 1 + data_encipherment = get_bit(bit_string, 3) == 1 + key_agreement = get_bit(bit_string, 4) == 1 + key_cert_sign = get_bit(bit_string, 5) == 1 + crl_sign = get_bit(bit_string, 6) == 1 + encipher_only = get_bit(bit_string, 7) == 1 + decipher_only = get_bit(bit_string, 8) == 1 + return x509.KeyUsage( + digital_signature, + content_commitment, + key_encipherment, + data_encipherment, + key_agreement, + key_cert_sign, + crl_sign, + encipher_only, + decipher_only + ) + @utils.register_interface(x509.CertificateSigningRequest) class _CertificateSigningRequest(object): diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py index c2d33d92..acfe761d 100644 --- a/tests/test_x509_ext.py +++ b/tests/test_x509_ext.py @@ -463,3 +463,63 @@ class TestSubjectKeyIdentifierExtension(object): cert.extensions.get_extension_for_oid( x509.OID_SUBJECT_KEY_IDENTIFIER ) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestKeyUsageExtension(object): + def test_no_key_usage(self, backend): + cert = _load_cert( + os.path.join("x509", "verisign_md2_root.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions + with pytest.raises(x509.ExtensionNotFound) as exc: + ext.get_extension_for_oid(x509.OID_KEY_USAGE) + + assert exc.value.oid == x509.OID_KEY_USAGE + + def test_all_purposes(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "all_key_usages.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + extensions = cert.extensions + ext = extensions.get_extension_for_oid(x509.OID_KEY_USAGE) + assert ext is not None + + ku = ext.value + assert ku.digital_signature is True + assert ku.content_commitment is True + assert ku.key_encipherment is True + assert ku.data_encipherment is True + assert ku.key_agreement is True + assert ku.key_cert_sign is True + assert ku.crl_sign is True + assert ku.encipher_only is True + assert ku.decipher_only is True + + def test_key_cert_sign_crl_sign(self, backend): + cert = _load_cert( + os.path.join( + "x509", "PKITS_data", "certs", "pathLenConstraint6CACert.crt" + ), + x509.load_der_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid(x509.OID_KEY_USAGE) + assert ext is not None + assert ext.critical is True + + ku = ext.value + assert ku.digital_signature is False + assert ku.content_commitment is False + assert ku.key_encipherment is False + assert ku.data_encipherment is False + assert ku.key_agreement is False + assert ku.key_cert_sign is True + assert ku.crl_sign is True |