Random Certificate Serial Numbers v2 - dogtagpki/pki GitHub Wiki

Overview

Note
This proposal has not been implemented.

This proposal introduces a new mechanism for generating random certificate serial number.

Currently the random serial number consists of an entirely random number. Because of that it’s a bit difficult to sort and to manage among multiple replicas.

In the new mechanism the random serial number will consist of several components:

  • replica ID: this is a constant to uniquely identify a replica.

  • sequence number: this is a monotonically increasing number maintained by each replica.

  • random number: this is a secure random number for entropy.

The new mechanism offers some benefits:

  • The sequence number guarantees that the serial number is unique within a replica, so there is no need for collision detection.

  • The replica ID guarantees that the serial number is unique globally, so there is no need for a complex range assignment and switching mechanism.

  • The serial numbers can be grouped by replica and can be sorted per replica. The random number does not alter the order of the serial numbers. This may help partitioning pre-signed OCSP responses.

Serial Number Format

The components in the new serial number will be arranged as follows (from MSB to LSB):

<replica ID> <sequence number> <random number>

The length of each component can be configured as needed to support different requirements. The total length of the serial number must not exceed 20 bytes (160 bits) according to RFC 5280 Section 4.1.2.2:

The serial number MUST be a positive integer assigned by the CA to
each certificate.  It MUST be unique for each certificate issued by a
given CA (i.e., the issuer name and serial number identify a unique
certificate).  CAs MUST force the serialNumber to be a non-negative
integer.

Given the uniqueness requirements above, serial numbers can be
expected to contain long integers.  Certificate users MUST be able to
handle serialNumber values up to 20 octets.  Conforming CAs MUST NOT
use serialNumber values longer than 20 octets.

Note: Non-conforming CAs may issue certificates with serial numbers
that are negative or zero.  Certificate users SHOULD be prepared to
gracefully handle such certificates.

If 64-bit entropy is required (i.e. 8 bytes) it will still leave 12 bytes for replica ID and sequence number.

If the system contains only a single server (i.e. no replica), the replica ID can be omitted:

<sequence number> <random number>

If no random serial number is required, the random number can be removed:

<replica ID> <sequence number>

Note: make sure the configuration cannot generate duplicate serial numbers.

Random Number Generator

The random number can be generated by NSS/JSS through the SecureRandom class.

// prepare a big-endian byte array
byte[] bytes = new byte[length];

// insert 1-byte replica ID
bytes[0] = replicaID;

// insert 8-byte sequence number
byte[] sequenceNumber = ...

for (int i = 0; i <= 8; i++) {
    bytes[i + 1] = sequenceNumber[i];
}

// insert 8-byte random number
Provider jss = Security.getProvider("JSS");
SecureRandomSpi spi = jss.get("SecureRandom.pkcs11prng");
SecureRandom random = new SecureRandom(spi, jss);

byte[] randomNumber = new byte[8];
random.nextBytes(randomNumber);

for (int i = 0; i <= 8; i++) {
    bytes[i + 9] = randomNumber[i];
}

BigInteger serialNumber = new BigInteger(bytes);

Sorting

In general a serial number should be considered as an identifier instead of a number, so it should be sorted in lexicographical order instead of numeric order.

Sometimes it is necessary to sort certificates according to their creation order (see Pre-signed OCSP Responses section). With the current mechanism, however, the serial number is not a reliable mechanism for this since the serial number can be non-sequential (due to range allocation) or randomized. It would be better to sort by their creation times, assuming this information is available.

See the following example. With the current mechanism, if the certificates are ordered by the creation time, the list of certificates may look like the following (the certificate number indicates the creation order):

          serial
          --------------
cert #1:  83 27 39 13 a7
cert #2:  9c 45 ef 1a 20
cert #3:  02 73 a9 c7 s8
cert #4:  28 7a 0b d1 00

Since the serial number is completely random, a lookup operation to find a serial number in this list will be relatively slow. If the certificates are ordered by the serial number instead, it may look like the following:

          serial
          --------------
cert #3:  02 73 a9 c7 s8
cert #4:  28 7a 0b d1 00
cert #1:  83 27 39 13 a7
cert #2:  9c 45 ef 1a 20

The lookup will be faster, but the list will no longer show the creation order. Also, if a new certificate is added, it may appear anywhere in the list, shifting the position of existing certificates.

The new mechanism will help sorting the certificates into a consistent order.

See the following example. With the new mechanism, if the certificates are ordered globally by the creation time, the list may look like random:

          replica sequence random
          ------- -------- --------
cert #1:       02 00 25 37 78 a3 2f
cert #2:       08 00 0c 21 23 6b ab
cert #3:       08 00 0c 22 a6 28 0f
cert #4:       02 00 25 38 02 4c d3

However, if the certificates are grouped by replica, the list will be ordered by both serial number and creation time:

          replica sequence random
          ------- -------- --------
cert #1:       02 00 25 37 78 a3 2f
cert #4:       02 00 25 38 02 4c d3

          replica sequence random
          ------- -------- --------
cert #2:       08 00 0c 21 23 6b ab
cert #3:       08 00 0c 22 a6 28 0f

A lookup operation will be faster since the group can be determined by the replica ID in the serial number, and the sequence number is monotonically increasing.

If a new certificate is created, the new serial number will always be added at the bottom of the corresponding group, so the position of existing certificates are preserved.

Pre-signed OCSP Responses

In large deployment it may be necessary to use pre-signed OCSP responses. A signing server (i.e. keyed OCSP responder) can generate pre-signed OCSP responses which contain a set of certificate serial numbers and their statuses. These responses can be distributed to caching servers (i.e. keyless OCSP responders) or clients.

It’s unclear how exactly the pre-signed OCSP responses are generated/handled. This will require further investigation. Some OCSP systems might not work with random serial numbers, which means in this case the old mechanism cannot be used at all. However, since the new mechanism supports partial ordering, it might be possible to use the new mechanism assuming the OCSP system also supports it.

With the current mechanism the serial number will be completely random, so the ranges of the serial numbers in the OCSP response can be large or can overlap other responses. The lookup operation will be slow since it may need to go through a large list of serial numbers or multiple responses.

With the new mechanism, the certificates can be grouped by replica, and within each group the serial numbers will be sequential, so it’s possible to create OCSP responses with smaller ranges that do not overlap with other responses.

Replication

To avoid collision, with the current mechanism the serial number ranges need to be maintained among the replicas using some parameters in CS.cfg:

dbs.enableSerialManagement=true

dbs.beginSerialNumber=10000001
dbs.endSerialNumber=20000000

dbs.nextBeginSerialNumber=30000001
dbs.nextEndSerialNumber=40000000

dbs.serialIncrement=10000000
dbs.serialLowWaterMark=2000000

dbs.serialCloneTransferNumber=10000

With the new mechanism, the serial numbers are guaranteed to be unique globally since it contains the replica ID and a sequence number. There is no need to maintain the number ranges or a database of existing serial numbers.

See Also

⚠️ **GitHub.com Fallback** ⚠️