aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.rst2
-rw-r--r--docs/x509/reference.rst29
-rw-r--r--src/cryptography/x509/__init__.py2
-rw-r--r--src/cryptography/x509/base.py5
-rw-r--r--tests/test_x509.py17
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