aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.rst8
-rw-r--r--docs/random-numbers.rst8
-rw-r--r--src/cryptography/hazmat/backends/openssl/backend.py32
-rw-r--r--src/cryptography/x509.py4
-rw-r--r--tests/test_x509.py76
5 files changed, 127 insertions, 1 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 63877d8a..5c808f39 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -48,10 +48,16 @@ Changelog
* Add support for creating signed certificates with
:class:`~cryptography.x509.CertificateBuilder`. This includes support for
- the following extensions
+ the following extensions:
* :class:`~cryptography.x509.BasicConstraints`
* :class:`~cryptography.x509.SubjectAlternativeName`
+ * :class:`~cryptography.x509.KeyUsage`
+ * :class:`~cryptography.x509.ExtendedKeyUsage`
+ * :class:`~cryptography.x509.SubjectKeyIdentifier`
+ * :class:`~cryptography.x509.AuthorityKeyIdentifier`
+ * :class:`~cryptography.x509.AuthorityInformationAccess`
+ * :class:`~cryptography.x509.CRLDistributionPoints`
0.9.3 - 2015-07-09
~~~~~~~~~~~~~~~~~~
diff --git a/docs/random-numbers.rst b/docs/random-numbers.rst
index 8b119a3e..5f94bf13 100644
--- a/docs/random-numbers.rst
+++ b/docs/random-numbers.rst
@@ -21,4 +21,12 @@ you can obtain them with:
This will use ``/dev/urandom`` on UNIX platforms, and ``CryptGenRandom`` on
Windows.
+If you need your random number as an integer (for example, for
+:meth:`~cryptography.x509.CertificateBuilder.serial_number`), you can use
+``int.from_bytes`` to convert the result of ``os.urandom``:
+
+.. code-block:: pycon
+
+ >>> serial = int.from_bytes(os.urandom(20), byteorder="big")
+
.. _`always use your operating system's provided random number generator`: http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index fdd38fa3..6675f677 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -182,6 +182,36 @@ def _encode_key_usage(backend, key_usage):
return pp, r
+def _encode_authority_key_identifier(backend, authority_keyid):
+ akid = backend._lib.AUTHORITY_KEYID_new()
+ assert akid != backend._ffi.NULL
+ akid = backend._ffi.gc(akid, backend._lib.AUTHORITY_KEYID_free)
+ if authority_keyid.key_identifier is not None:
+ akid.keyid = _encode_asn1_str(
+ backend,
+ authority_keyid.key_identifier,
+ len(authority_keyid.key_identifier)
+ )
+
+ if authority_keyid.authority_cert_issuer is not None:
+ akid.issuer = _encode_general_names(
+ backend, authority_keyid.authority_cert_issuer
+ )
+
+ if authority_keyid.authority_cert_serial_number is not None:
+ akid.serial = _encode_asn1_int(
+ backend, authority_keyid.authority_cert_serial_number
+ )
+
+ pp = backend._ffi.new('unsigned char **')
+ r = backend._lib.i2d_AUTHORITY_KEYID(akid, 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(
@@ -1240,6 +1270,8 @@ class Backend(object):
for i, extension in enumerate(builder._extensions):
if isinstance(extension.value, x509.BasicConstraints):
pp, r = _encode_basic_constraints(self, extension.value)
+ elif isinstance(extension.value, x509.AuthorityKeyIdentifier):
+ pp, r = _encode_authority_key_identifier(self, extension.value)
elif isinstance(extension.value, x509.KeyUsage):
pp, r = _encode_key_usage(self, extension.value)
elif isinstance(extension.value, x509.ExtendedKeyUsage):
diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py
index da7603c4..397274e8 100644
--- a/src/cryptography/x509.py
+++ b/src/cryptography/x509.py
@@ -1812,6 +1812,10 @@ class CertificateBuilder(object):
"""
if isinstance(extension, BasicConstraints):
extension = Extension(OID_BASIC_CONSTRAINTS, critical, extension)
+ elif isinstance(extension, AuthorityKeyIdentifier):
+ extension = Extension(
+ OID_AUTHORITY_KEY_IDENTIFIER, critical, extension
+ )
elif isinstance(extension, KeyUsage):
extension = Extension(OID_KEY_USAGE, critical, extension)
elif isinstance(extension, ExtendedKeyUsage):
diff --git a/tests/test_x509.py b/tests/test_x509.py
index 1cbff511..9ca8931d 100644
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -2026,6 +2026,82 @@ class TestCertificateSigningRequestBuilder(object):
)
assert ext.value == ski
+ @pytest.mark.parametrize(
+ "aki",
+ [
+ x509.AuthorityKeyIdentifier(
+ b"\xc3\x9c\xf3\xfc\xd3F\x084\xbb\xceF\x7f\xa0|[\xf3\xe2\x08"
+ b"\xcbY",
+ None,
+ None
+ ),
+ x509.AuthorityKeyIdentifier(
+ b"\xc3\x9c\xf3\xfc\xd3F\x084\xbb\xceF\x7f\xa0|[\xf3\xe2\x08"
+ b"\xcbY",
+ [
+ x509.DirectoryName(
+ x509.Name([
+ x509.NameAttribute(
+ x509.OID_ORGANIZATION_NAME, u"PyCA"
+ ),
+ x509.NameAttribute(
+ x509.OID_COMMON_NAME, u"cryptography CA"
+ )
+ ])
+ )
+ ],
+ 333
+ ),
+ x509.AuthorityKeyIdentifier(
+ None,
+ [
+ x509.DirectoryName(
+ x509.Name([
+ x509.NameAttribute(
+ x509.OID_ORGANIZATION_NAME, u"PyCA"
+ ),
+ x509.NameAttribute(
+ x509.OID_COMMON_NAME, u"cryptography CA"
+ )
+ ])
+ )
+ ],
+ 333
+ ),
+ ]
+ )
+ @pytest.mark.requires_backend_interface(interface=RSABackend)
+ @pytest.mark.requires_backend_interface(interface=X509Backend)
+ def test_build_cert_with_aki(self, aki, backend):
+ issuer_private_key = RSA_KEY_2048.private_key(backend)
+ subject_private_key = RSA_KEY_2048.private_key(backend)
+
+ not_valid_before = datetime.datetime(2002, 1, 1, 12, 1)
+ not_valid_after = datetime.datetime(2030, 12, 31, 8, 30)
+
+ builder = x509.CertificateBuilder().serial_number(
+ 777
+ ).issuer_name(x509.Name([
+ x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US'),
+ ])).subject_name(x509.Name([
+ x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US'),
+ ])).public_key(
+ subject_private_key.public_key()
+ ).add_extension(
+ aki, critical=False
+ ).not_valid_before(
+ not_valid_before
+ ).not_valid_after(
+ not_valid_after
+ )
+
+ cert = builder.sign(issuer_private_key, hashes.SHA256(), backend)
+
+ ext = cert.extensions.get_extension_for_oid(
+ x509.OID_AUTHORITY_KEY_IDENTIFIER
+ )
+ assert ext.value == aki
+
@pytest.mark.requires_backend_interface(interface=DSABackend)
@pytest.mark.requires_backend_interface(interface=X509Backend)