diff options
| author | Alex Gaynor <alex.gaynor@gmail.com> | 2015-04-12 12:40:01 -0400 | 
|---|---|---|
| committer | Alex Gaynor <alex.gaynor@gmail.com> | 2015-04-12 12:40:01 -0400 | 
| commit | 249bbd0064d42d78ff51e9a0203db4492453418f (patch) | |
| tree | c277bb1f095ff7af89f51f845c9918ea25219014 | |
| parent | d459a8a16c417e0db59de0a643aeb9079b45b9bb (diff) | |
| parent | 4a704e07c61f7658c4c95befac0b1fc0d1aaf315 (diff) | |
| download | cryptography-249bbd0064d42d78ff51e9a0203db4492453418f.tar.gz cryptography-249bbd0064d42d78ff51e9a0203db4492453418f.tar.bz2 cryptography-249bbd0064d42d78ff51e9a0203db4492453418f.zip  | |
Merge pull request #1822 from reaperhulk/x509-keyusage-ossl
keyusage support in the OpenSSL backend
| -rw-r--r-- | docs/x509.rst | 1 | ||||
| -rw-r--r-- | src/cryptography/hazmat/backends/openssl/x509.py | 40 | ||||
| -rw-r--r-- | src/cryptography/hazmat/bindings/openssl/asn1.py | 1 | ||||
| -rw-r--r-- | tests/test_x509_ext.py | 60 | 
4 files changed, 93 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..57e6146b 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,35 @@ 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) +        bit_string = self._backend._ffi.gc( +            bit_string, self._backend._lib.ASN1_BIT_STRING_free +        ) +        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/src/cryptography/hazmat/bindings/openssl/asn1.py b/src/cryptography/hazmat/bindings/openssl/asn1.py index 45dfe758..475bd052 100644 --- a/src/cryptography/hazmat/bindings/openssl/asn1.py +++ b/src/cryptography/hazmat/bindings/openssl/asn1.py @@ -120,6 +120,7 @@ int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *, int, int);  """  MACROS = """ +void ASN1_BIT_STRING_free(ASN1_BIT_STRING *);  /* This is not a macro, but is const on some versions of OpenSSL */  int ASN1_BIT_STRING_get_bit(ASN1_BIT_STRING *, int);  ASN1_TIME *M_ASN1_TIME_dup(void *); 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  | 
