diff options
author | Alex Gaynor <alex.gaynor@gmail.com> | 2015-07-23 18:00:57 -0400 |
---|---|---|
committer | Alex Gaynor <alex.gaynor@gmail.com> | 2015-07-23 18:00:57 -0400 |
commit | ef8a72273d639be239d3d7c2380a0912083811da (patch) | |
tree | 5d7a89c36fd968c4f536f1c96e8f8fe2e49d78c1 | |
parent | 7a217fe8d216b5897689c99a2b72eea5d5d5ffa1 (diff) | |
parent | dce91f0b2923daf60a6fdfd811eb5b3d81ac7c88 (diff) | |
download | cryptography-ef8a72273d639be239d3d7c2380a0912083811da.tar.gz cryptography-ef8a72273d639be239d3d7c2380a0912083811da.tar.bz2 cryptography-ef8a72273d639be239d3d7c2380a0912083811da.zip |
Merge pull request #2168 from reaperhulk/encode-ku
Support encoding KeyUsage into certificate signing requests
-rw-r--r-- | src/_cffi_src/openssl/asn1.py | 2 | ||||
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/backend.py | 40 | ||||
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/x509.py | 1 | ||||
-rw-r--r-- | src/cryptography/x509.py | 2 | ||||
-rw-r--r-- | tests/test_x509.py | 66 |
5 files changed, 109 insertions, 2 deletions
diff --git a/src/_cffi_src/openssl/asn1.py b/src/_cffi_src/openssl/asn1.py index 5f8ca697..96eff7d3 100644 --- a/src/_cffi_src/openssl/asn1.py +++ b/src/_cffi_src/openssl/asn1.py @@ -125,7 +125,9 @@ int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *, int, int); """ MACROS = """ +ASN1_BIT_STRING *ASN1_BIT_STRING_new(void); void ASN1_BIT_STRING_free(ASN1_BIT_STRING *); +int i2d_ASN1_BIT_STRING(ASN1_BIT_STRING *, unsigned char **); /* 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/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 9cfe73c1..046a1739 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -131,6 +131,44 @@ def _txt2obj(backend, name): return obj +def _encode_key_usage(backend, key_usage): + set_bit = backend._lib.ASN1_BIT_STRING_set_bit + ku = backend._lib.ASN1_BIT_STRING_new() + ku = backend._ffi.gc(ku, backend._lib.ASN1_BIT_STRING_free) + res = set_bit(ku, 0, key_usage.digital_signature) + assert res == 1 + res = set_bit(ku, 1, key_usage.content_commitment) + assert res == 1 + res = set_bit(ku, 2, key_usage.key_encipherment) + assert res == 1 + res = set_bit(ku, 3, key_usage.data_encipherment) + assert res == 1 + res = set_bit(ku, 4, key_usage.key_agreement) + assert res == 1 + res = set_bit(ku, 5, key_usage.key_cert_sign) + assert res == 1 + res = set_bit(ku, 6, key_usage.crl_sign) + assert res == 1 + if key_usage.key_agreement: + res = set_bit(ku, 7, key_usage.encipher_only) + assert res == 1 + res = set_bit(ku, 8, key_usage.decipher_only) + assert res == 1 + else: + res = set_bit(ku, 7, 0) + assert res == 1 + res = set_bit(ku, 8, 0) + assert res == 1 + + pp = backend._ffi.new('unsigned char **') + r = backend._lib.i2d_ASN1_BIT_STRING(ku, pp) + assert r > 0 + pp = backend._ffi.gc( + pp, lambda pointer: backend._lib.OPENSSL_free(pointer[0]) + ) + return pp, r + + def _encode_basic_constraints(backend, basic_constraints): constraints = backend._lib.BASIC_CONSTRAINTS_new() constraints = backend._ffi.gc( @@ -964,6 +1002,8 @@ class Backend(object): pp, r = _encode_basic_constraints(self, extension.value) elif isinstance(extension.value, x509.SubjectAlternativeName): pp, r = _encode_subject_alt_name(self, extension.value) + elif isinstance(extension.value, x509.KeyUsage): + pp, r = _encode_key_usage(self, extension.value) else: raise NotImplementedError('Extension not yet supported.') diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 472d8a70..943cfd78 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -816,6 +816,7 @@ _CSR_EXTENSION_PARSER = _X509ExtensionParser( get_ext=lambda backend, x, i: backend._lib.sk_X509_EXTENSION_value(x, i), handlers={ x509.OID_BASIC_CONSTRAINTS: _decode_basic_constraints, + x509.OID_KEY_USAGE: _decode_key_usage, x509.OID_SUBJECT_ALTERNATIVE_NAME: _decode_subject_alt_name, } ) diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index 58e1a37c..5d108ee6 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -1577,6 +1577,8 @@ class CertificateSigningRequestBuilder(object): ) elif isinstance(extension, KeyUsage): extension = Extension(OID_KEY_USAGE, critical, extension) + elif isinstance(extension, InhibitAnyPolicy): + extension = Extension(OID_INHIBIT_ANY_POLICY, critical, extension) else: raise NotImplementedError('Unsupported X.509 extension.') # TODO: This is quadratic in the number of extensions diff --git a/tests/test_x509.py b/tests/test_x509.py index b2262c71..af7d9421 100644 --- a/tests/test_x509.py +++ b/tests/test_x509.py @@ -962,6 +962,20 @@ class TestCertificateSigningRequestBuilder(object): x509.SubjectAlternativeName([x509.DNSName(u"cryptography.io")]), critical=False, ).add_extension( + x509.InhibitAnyPolicy(0), + critical=False + ) + with pytest.raises(NotImplementedError): + builder.sign(private_key, hashes.SHA256(), backend) + + def test_key_usage(self, backend): + private_key = RSA_KEY_2048.private_key(backend) + builder = x509.CertificateSigningRequestBuilder() + request = builder.subject_name( + x509.Name([ + x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US'), + ]) + ).add_extension( x509.KeyUsage( digital_signature=True, content_commitment=True, @@ -974,9 +988,57 @@ class TestCertificateSigningRequestBuilder(object): decipher_only=False ), critical=False + ).sign(private_key, hashes.SHA256(), backend) + assert len(request.extensions) == 1 + ext = request.extensions.get_extension_for_oid(x509.OID_KEY_USAGE) + assert ext.critical is False + assert ext.value == x509.KeyUsage( + digital_signature=True, + content_commitment=True, + key_encipherment=False, + data_encipherment=False, + key_agreement=False, + key_cert_sign=True, + crl_sign=False, + encipher_only=False, + decipher_only=False + ) + + def test_key_usage_key_agreement_bit(self, backend): + private_key = RSA_KEY_2048.private_key(backend) + builder = x509.CertificateSigningRequestBuilder() + request = builder.subject_name( + x509.Name([ + x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US'), + ]) + ).add_extension( + x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=True, + key_cert_sign=True, + crl_sign=False, + encipher_only=False, + decipher_only=True + ), + critical=False + ).sign(private_key, hashes.SHA256(), backend) + assert len(request.extensions) == 1 + ext = request.extensions.get_extension_for_oid(x509.OID_KEY_USAGE) + assert ext.critical is False + assert ext.value == x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=True, + key_cert_sign=True, + crl_sign=False, + encipher_only=False, + decipher_only=True ) - with pytest.raises(NotImplementedError): - builder.sign(private_key, hashes.SHA256(), backend) def test_add_two_extensions(self, backend): private_key = RSA_KEY_2048.private_key(backend) |