diff --git a/acme/acme/crypto_util.py b/acme/acme/crypto_util.py index 73f7f8f62..2b2133475 100644 --- a/acme/acme/crypto_util.py +++ b/acme/acme/crypto_util.py @@ -1,4 +1,5 @@ """Crypto utilities.""" +import binascii import contextlib import logging import re @@ -203,7 +204,7 @@ def gen_ss_cert(key, domains, not_before=None, """ assert domains, "Must provide one or more hostnames for the cert." cert = OpenSSL.crypto.X509() - cert.set_serial_number(1337) + cert.set_serial_number(int(binascii.hexlify(OpenSSL.rand.bytes(16)), 16)) cert.set_version(2) extensions = [ diff --git a/acme/acme/crypto_util_test.py b/acme/acme/crypto_util_test.py index 147cd5a2a..75a908d4f 100644 --- a/acme/acme/crypto_util_test.py +++ b/acme/acme/crypto_util_test.py @@ -8,6 +8,8 @@ import unittest import six from six.moves import socketserver # pylint: disable=import-error +import OpenSSL + from acme import errors from acme import jose from acme import test_util @@ -126,5 +128,23 @@ class PyOpenSSLCertOrReqSANTest(unittest.TestCase): self._get_idn_names()) +class RandomSnTest(unittest.TestCase): + """Test for random certificate serial numbers.""" + + def setUp(self): + self.cert_count = 5 + self.serial_num = [] + self.key = OpenSSL.crypto.PKey() + self.key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048) + + def test_sn_collisions(self): + from acme.crypto_util import gen_ss_cert + + for _ in range(self.cert_count): + cert = gen_ss_cert(self.key, ['dummy'], force_san=True) + self.serial_num.append(cert.get_serial_number()) + self.assertTrue(len(set(self.serial_num)) > 1) + + if __name__ == '__main__': unittest.main() # pragma: no cover