diff options
-rw-r--r-- | CHANGELOG.rst | 2 | ||||
-rw-r--r-- | docs/x509/reference.rst | 29 | ||||
-rw-r--r-- | src/cryptography/x509/__init__.py | 2 | ||||
-rw-r--r-- | src/cryptography/x509/base.py | 5 | ||||
-rw-r--r-- | tests/test_x509.py | 17 |
5 files changed, 47 insertions, 8 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7a03644f..2e38ae56 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -22,6 +22,8 @@ Changelog support to :class:`~cryptography.x509.CertificateRevocationList`. * Added support for :class:`~cryptography.hazmat.primitives.kdf.scrypt.Scrypt` when using OpenSSL 1.1.0. +* Added support for generating a + :meth:`~cryptography.x509.random_serial_number`. 1.5 - 2016-08-26 diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst index bd88b023..bee7c176 100644 --- a/docs/x509/reference.rst +++ b/docs/x509/reference.rst @@ -582,7 +582,6 @@ X.509 Certificate Builder >>> from cryptography.hazmat.primitives.asymmetric import rsa >>> from cryptography.x509.oid import NameOID >>> import datetime - >>> import uuid >>> one_day = datetime.timedelta(1, 0, 0) >>> private_key = rsa.generate_private_key( ... public_exponent=65537, @@ -599,7 +598,7 @@ X.509 Certificate Builder ... ])) >>> builder = builder.not_valid_before(datetime.datetime.today() - one_day) >>> builder = builder.not_valid_after(datetime.datetime(2018, 8, 2)) - >>> builder = builder.serial_number(int(uuid.uuid4())) + >>> builder = builder.serial_number(x509.random_serial_number()) >>> builder = builder.public_key(public_key) >>> builder = builder.add_extension( ... x509.BasicConstraints(ca=False, path_length=None), critical=True, @@ -637,15 +636,17 @@ X.509 Certificate Builder .. method:: serial_number(serial_number) Sets the certificate's serial number (an integer). The CA's policy - determines how it attributes serial numbers to certificates. The only - requirement is that this number uniquely identify the certificate given - the issuer. + determines how it attributes serial numbers to certificates. This + number must uniquely identify the certificate given the issuer. + `CABForum Guidelines`_ require entropy in the serial number + to provide protection against hash collision attacks. For more + information on secure random number generation, see + :doc:`/random-numbers`. :param serial_number: Integer number that will be used by the CA to identify this certificate (most notably during certificate - revocation checking). Users are encouraged to use a method of - generating 20 bytes of entropy, e.g., UUID4. For more information - on secure random number generation, see :doc:`/random-numbers`. + revocation checking). Users should consider using + :func:`~cryptography.x509.random_serial_number` when possible. .. method:: not_valid_before(time) @@ -2542,6 +2543,17 @@ instances. The following common OIDs are available as constants. Corresponds to the dotted string ``"2.5.29.24"``. +Helper Functions +~~~~~~~~~~~~~~~~ +.. currentmodule:: cryptography.x509 + +.. function:: random_serial_number() + + .. versionadded:: 1.6 + + Generates a random serial number suitable for use when constructing + certificates. + Exceptions ~~~~~~~~~~ .. currentmodule:: cryptography.x509 @@ -2604,3 +2616,4 @@ Exceptions .. _`RFC 5280 section 4.2.1.1`: https://tools.ietf.org/html/rfc5280#section-4.2.1.1 .. _`RFC 5280 section 4.2.1.6`: https://tools.ietf.org/html/rfc5280#section-4.2.1.6 +.. _`CABForum Guidelines`: https://cabforum.org/baseline-requirements-documents/ diff --git a/src/cryptography/x509/__init__.py b/src/cryptography/x509/__init__.py index 968d29d0..feab4497 100644 --- a/src/cryptography/x509/__init__.py +++ b/src/cryptography/x509/__init__.py @@ -11,6 +11,7 @@ from cryptography.x509.base import ( InvalidVersion, RevokedCertificate, RevokedCertificateBuilder, Version, load_der_x509_certificate, load_der_x509_crl, load_der_x509_csr, load_pem_x509_certificate, load_pem_x509_crl, load_pem_x509_csr, + random_serial_number, ) from cryptography.x509.extensions import ( AccessDescription, AuthorityInformationAccess, @@ -113,6 +114,7 @@ __all__ = [ "load_der_x509_csr", "load_pem_x509_crl", "load_der_x509_crl", + "random_serial_number", "InvalidVersion", "DuplicateExtension", "UnsupportedExtension", diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py index 498ccbb9..ffa71916 100644 --- a/src/cryptography/x509/base.py +++ b/src/cryptography/x509/base.py @@ -6,6 +6,7 @@ from __future__ import absolute_import, division, print_function import abc import datetime +import os from enum import Enum import six @@ -723,3 +724,7 @@ class RevokedCertificateBuilder(object): ) return backend.create_x509_revoked_certificate(self) + + +def random_serial_number(): + return utils.int_from_bytes(os.urandom(20), "big") >> 1 diff --git a/tests/test_x509.py b/tests/test_x509.py index dcfbe4fd..468eb397 100644 --- a/tests/test_x509.py +++ b/tests/test_x509.py @@ -3724,3 +3724,20 @@ class TestName(object): def test_not_nameattribute(self): with pytest.raises(TypeError): x509.Name(["not-a-NameAttribute"]) + + +def test_random_serial_number(monkeypatch): + sample_data = os.urandom(20) + + def notrandom(size): + assert size == len(sample_data) + return sample_data + + monkeypatch.setattr(os, "urandom", notrandom) + + serial_number = x509.random_serial_number() + + assert ( + serial_number == utils.int_from_bytes(sample_data, "big") >> 1 + ) + assert utils.bit_length(serial_number) < 160 |