aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Gaynor <alex.gaynor@gmail.com>2015-04-12 12:40:01 -0400
committerAlex Gaynor <alex.gaynor@gmail.com>2015-04-12 12:40:01 -0400
commit249bbd0064d42d78ff51e9a0203db4492453418f (patch)
treec277bb1f095ff7af89f51f845c9918ea25219014
parentd459a8a16c417e0db59de0a643aeb9079b45b9bb (diff)
parent4a704e07c61f7658c4c95befac0b1fc0d1aaf315 (diff)
downloadcryptography-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.rst1
-rw-r--r--src/cryptography/hazmat/backends/openssl/x509.py40
-rw-r--r--src/cryptography/hazmat/bindings/openssl/asn1.py1
-rw-r--r--tests/test_x509_ext.py60
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