Discontinuing support for ACME clients using draft-ietf-acme-ari-01

In early April 2024, Let's Encrypt will phase out support for draft-ietf-acme-ari-01 of the ACME ARI protocol, transitioning to draft-ietf-acme-ari-03. This update brings several significant changes:

New ARI CertID format: We are updating the method for constructing the ARI CertID. The new format moves away from the OCSP CertID format and combines the base64url encoded bytes of the certificate's Authority Key Identifier (AKI) extension with its Serial Number, separated by a period. For example:

Suppose the keyIdentifier field of the certificate's Authority Key Identifier (AKI) extension has the hexadecimal bytes 69:88:5B:6B:87:46:40:41:E1:B3:7B:84:7B:A0:AE:2C:DE:01:C8:D4 as its ASN.1 Octet String value. The base64url encoding of these bytes is aYhba4dGQEHhs3uEe6CuLN4ByNQ=.

Furthermore, suppose the certificate's Serial Number, when represented in its ASN.1 DER encoding (excluding the tag and length bytes), has the hexadecimal bytes 00:87:65:43:21. The base64url encoding of these bytes is AIdlQyE=. (Note that this preserves the leading zero byte of the serial, which for this example serial was required by the DER encoding to ensure the serial is a positive integer.)

After stripping the trailing padding characters (“=”) from each encoded part and concatenating them with a period as a separator, the ARI CertID for this certificate becomes aYhba4dGQEHhs3uEe6CuLN4ByNQ.AIdlQyE.

The Go implementation for this is as follows:

// MakeARICertID constructs a certificate identifier as described in
// draft-ietf-acme-ari-03, section 4.1.
func MakeARICertID(leaf *x509.Certificate) (string, error) {
	if leaf == nil {
		return "", errors.New("leaf certificate is nil")
	}

	// Marshal the Serial Number into DER.
	der, err := asn1.Marshal(leaf.SerialNumber)
	if err != nil {
		return "", err
	}

	// Check if the DER encoded bytes are sufficient (at least 3 bytes: tag,
	// length, and value).
	if len(der) < 3 {
		return "", errors.New("invalid DER encoding of serial number")
	}

	// Extract only the integer bytes from the DER encoded Serial Number
	// Skipping the first 2 bytes (tag and length). The result is base64url
	// encoded without padding.
	serial := base64.RawURLEncoding.EncodeToString(der[2:])

	// Convert the Authority Key Identifier to base64url encoding without
	// padding.
	aki := base64.RawURLEncoding.EncodeToString(leaf.AuthorityKeyId)

	// Construct the final identifier by concatenating AKI and Serial Number.
	return fmt.Sprintf("%s.%s", aki, serial), nil
}

New “replaces” field in the Order object: We have extended the Order object to include a "replaces" field. This field identifies the certificate being replaced by a new order. Our goal is to use this field to exempt renewals within ARI suggested renewal windows from rate limits, thereby encouraging further ARI adoption. An example Order incorporating this field is as follows:

{
  "protected": base64url({
    "alg": "ES256",
    "kid": "https://example.com/acme/acct/evOfKhNU60wg",
    "nonce": "5XJ1L3lEkMG7tR6pA00clA",
    "url": "https://example.com/acme/new-order"
  }),
  "payload": base64url({
    "identifiers": [
      { "type": "dns", "value": "example.com" }
    ],
    "replaces": "aYhba4dGQEHhs3uEe6CuLN4ByNQ.AIdlQyE"
  }),
  "signature": "H6ZXtGjTZyUnPeKn...wEA4TklBdh3e454g"
}

Note: For a certificate to qualify as a “replacement,” it must share at least one domain name with its predecessor.

Deprecation of POST to renewalInfo endpoint: Clients will no longer POST to renewalInfo endpoint to indicate replacement. Instead, they will include the aforementioned CertID of the predecessor certificate in the “replaces” field when requesting a renewal.

These changes aim to simplify client implementation and improve the ARI protocol's efficiency. Developers are encouraged to familiarize themselves with these updates for a seamless transition. Stay tuned for an upcoming blog post in early April, which will provide a detailed ARI implementation guide and a special announcement regarding rate limit exemptions.

15 Likes

As promised, we've just published a new blog post detailing a six-step process for integrating draft-ietf-acme-ari-03 into your existing ACME client. Check it out here: An Engineer’s Guide to Integrating ARI into Existing ACME Clients.

11 Likes