RFC 9115

An Automatic Certificate Management Environment (ACME) Profile for Generating Delegated Certificates

๐Ÿ“… published September 2021, from ietf

RFC 9115: An Automatic Certificate Management Environment (ACME) Profile for Generating Delegated Certificates ๐ŸŽ€

  • Who wrote it: Y. Sheffer (Intuit), D. Lรณpez (Telefonica I+D), A. Pastor Perales (Telefonica I+D), and T. Fossati (ARM) ๐Ÿ’œ
  • Published by: the Internet Engineering Task Force (IETF) ๐ŸŒธ
  • Category: Standards Track, so this is an official Internet standard ๐Ÿ‘‘
  • ISSN: 2070-1721
  • Date: September 2021 ๐Ÿ“
  • Obsoletes and Updates: the title block doesn't list either one, so this RFC doesn't name any other RFC as obsoleted or updated ๐Ÿงš

Abstract ๐Ÿฆ‹

Okay so this document defines a profile of the Automatic Certificate Management Environment (ACME) protocol โœจ It lets the holder of an identifier (like a domain name) let a third party get an X.509 certificate. The certificate's subject is the delegated identifier, but the public key inside it matches a private key that the third party controls ๐Ÿ”

The main use case is a Content Delivery Network (CDN), which is the third party, terminating TLS sessions for a content provider (the holder of the domain name). The big win is that the holder keeps control over the delegation and can revoke it at any time ๐Ÿ’… And importantly, this mechanism doesn't require any modification to the deployed TLS clients and servers ๐Ÿซถ

Status of This Memo ๐Ÿ“œ

This is an Internet Standards Track document. ๐ŸŒˆ

This document is a product of the Internet Engineering Task Force (IETF). It represents the consensus of the IETF community. It has received public review and has been approved for publication by the Internet Engineering Steering Group (IESG). Further information on Internet Standards is available in Section 2 of RFC 7841.

Information about the current status of this document, any errata, and how to provide feedback on it may be obtained at https://www.rfc-editor.org/info/rfc9115.

Copyright (c) 2021 IETF Trust and the persons identified as the document authors. All rights reserved.

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License.

Table of Contents ๐Ÿ“š

1.  Introduction
  1.1.  Terminology
  1.2.  Conventions Used in This Document
2.  Protocol Flow
  2.1.  Preconditions
  2.2.  Overview
  2.3.  Delegated Identity Profile
    2.3.1.  Delegation Configuration
    2.3.2.  Order Object Transmitted from NDC to IdO and to ACME
            Server (STAR)
    2.3.3.  Order Object Transmitted from NDC to IdO and to ACME
            Server (Non-STAR)
    2.3.4.  Capability Discovery
    2.3.5.  Negotiating an Unauthenticated GET
    2.3.6.  Terminating the Delegation
  2.4.  Proxy Behavior
3.  CA Behavior
4.  CSR Template
  4.1.  Template Syntax
  4.2.  Example
5.  Further Use Cases
  5.1.  CDN Interconnection (CDNI)
    5.1.1.  Multiple Parallel Delegates
    5.1.2.  Chained Delegation
  5.2.  Secure Telephone Identity Revisited (STIR)
6.  IANA Considerations
  6.1.  New Fields in the "meta" Object within a Directory Object
  6.2.  New Fields in the Order Object
  6.3.  New Fields in the Account Object
  6.4.  New Error Types
  6.5.  CSR Template Extensions
7.  Security Considerations
  7.1.  Trust Model
  7.2.  Delegation Security Goal
  7.3.  New ACME Channels
  7.4.  Restricting CDNs to the Delegation Mechanism
8.  References
  8.1.  Normative References
  8.2.  Informative References
Appendix A.  CSR Template: CDDL
Appendix B.  CSR Template: JSON Schema
Acknowledgements
Authors' Addresses

1. Introduction โœจ

Heads up bestie: this document is related to [RFC8739], because some important use cases need both documents implemented. To avoid repeating ourselves, we only give a bare-bones version of the motivation here. For the full story, check the introductory sections of [RFC8739] ๐Ÿ“–

An Identifier Owner (IdO) has agreements in place with one or more Name Delegation Consumers (NDCs) so they can use and attest its identity ๐Ÿซถ

In the primary use case, the IdO is a content provider, and a Content Delivery Network (CDN) provider has been contracted to serve the content over HTTPS ๐ŸŒ The CDN terminates the HTTPS connection at one of its edge cache servers. It has to show its clients (browsers, mobile apps, set-top boxes) a certificate whose name matches the domain name in the requested URL, which is the IdO's domain ๐Ÿ’– Honestly, some IdOs are going to balk at sharing their long-term private keys with another organization, and delegates would rather not be stuck handling other parties' long-term secrets ๐Ÿ™ˆ Other relevant use cases are covered in Section 5.

This document describes a profile of the ACME protocol [RFC8555]. It lets the NDC ask the IdO, acting as a profiled ACME server, for a certificate for a delegated identity, meaning one that belongs to the IdO ๐Ÿฆ‹ The IdO then uses the ACME protocol (with the extensions described in [RFC8739]) to request issuance of a Short-Term, Automatically Renewed (STAR) certificate for that same delegated identity โœจ The short-term certificate is automatically renewed by the ACME Certification Authority (CA), gets periodically fetched by the NDC, and is used to terminate HTTPS connections in place of the IdO. The IdO can end the delegation at any time by just telling the CA to stop the automatic renewal, and then the certificate expires shortly after ๐Ÿƒ

While the primary use case is delegating STAR certificates, this mechanism also works for long-lived certificates managed with the ACME protocol ๐Ÿ’œ The biggest difference between the two is how the delegation gets terminated. For long-lived certificates, the IdO uses the "revokeCert" URL exposed by the CA and waits for the explicit revocation, based on the Certificate Revocation List (CRL) and Online Certificate Status Protocol (OCSP), to propagate to the relying parties ๐Ÿ•ฐ๏ธ

If the delegated identity is a domain name, this document also gives the NDC a way to tell the IdO about the CNAME mappings that need to be installed in the IdO's DNS zone. That lets the aliasing of the delegated name happen, so the whole name delegation workflow can run through a single interface ๐ŸŽ€

We also note that other standardization efforts tackle certificate delegation for TLS connections, specifically [TLS-SUBCERTS] and [MGLT-LURK-TLS13]. The former extends the TLS certificate chain with a customer-owned signing certificate. The latter splits the server's private key off into a dedicated, more-secure component. Compared to those approaches, this document doesn't require changes to the TLS network stack of the client or the server, and it doesn't add any extra latency to the TLS connection ๐Ÿš€

1.1. Terminology ๐Ÿ“

  • IdO: Identifier Owner, the holder (current owner) of an identifier, like a domain name, that needs to be delegated. Depending on context, IdO can also refer to the (profiled) ACME server deployed by the Identifier Owner, or to the ACME client the Identifier Owner uses to interact with the CA.
  • NDC: Name Delegation Consumer, the entity that the domain name gets delegated to for a limited time. In the primary use case this is a CDN (readers may notice the two abbreviations look alike ๐Ÿ‘€). Depending on context, NDC can also refer to the (profiled) ACME client used by the Name Delegation Consumer.
  • CDN: Content Delivery Network, a widely distributed network that serves the domain's web content to a wide audience at high performance.
  • STAR: Short-Term, Automatically Renewed, as applied to X.509 certificates.
  • ACME: Automated Certificate Management Environment, a certificate management protocol [RFC8555].
  • CA: Certification Authority, specifically one that implements the ACME protocol. In this document, the term is synonymous with "ACME server deployed by the Certification Authority".
  • CSR: Certificate Signing Request, specifically a PKCS#10 [RFC2986] Certificate Signing Request, as supported by ACME.
  • FQDN: Fully Qualified Domain Name.

1.2. Conventions Used in This Document ๐ŸŒธ

Here's the important bit about how to read the requirement words ๐Ÿค“ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here. So if you see them in lowercase, they're just normal words, not requirements ๐Ÿ’…

2. Protocol Flow ๐ŸŒŠ

This section presents the protocol flow. For completeness, we include the ACME profile proposed in this document as well as the ACME STAR protocol described in [RFC8739] ๐Ÿงš

2.1. Preconditions ๐ŸŽ€

The protocol assumes the following preconditions are met:

  • The IdO exposes an ACME server interface to the NDC(s), including the account management interface.
  • The NDC has registered an ACME account with the IdO.
  • The NDC and IdO have agreed on a "CSR template" to use, including at a minimum: subject name (e.g., abc.ido.example), requested algorithms and key length, key usage, and extensions. The NDC will use this template for every CSR created under the same delegation.
  • The IdO has registered an ACME account with the Certification Authority (CA).
Note that even if the IdO implements the ACME server role, it is not acting as a CA. From the point of view of the certificate issuance process, the IdO only works as a "policing" forwarder of the NDC's key pair, and it's responsible for completing the identity verification process towards the CA ๐Ÿ•ต๏ธโ€โ™€๏ธ That's a lot of responsibility, but the IdO totally has it handled ๐Ÿ‘‘

2.2. Overview โœจ

okay so quick heads up, this overview is mostly about the main thing this protocol does: delegating STAR certificates ๐ŸŽ€ (the short-lived ones!). Non-STAR certificates work pretty similarly, and the differences get spelled out in the sections that follow ๐Ÿ’…

The NDC and the IdO talk through a profiled ACME workflow, which lives in Section 2.3 ๐Ÿฆ‹ The IdO and the CA are governed by ACME [RFC8555], ACME STAR [RFC8739], and any other ACME extension that applies (e.g., [TOKEN-TNAUTHLIST] for Secure Telephone Identity Revisited (STIR)) ๐Ÿ’œ

Here's the full combined STAR flow for the bullet-point version (Figure 1) ๐ŸŒธ:

  • NDC sends an Order1 for the delegated identifier to IdO.
  • IdO creates an Order1 resource in the ready state, with a finalize URL. โœจ
  • NDC immediately sends a finalize request (which includes the CSR) to the IdO.
  • IdO checks the CSR against the agreed upon CSR template.
  • If the CSR check fails, Order1 goes to invalid and everything stops ๐Ÿ’€
  • If the CSR check passes, IdO moves Order1 to processing and sends a brand new Order2 (using its own account) for the delegated identifier to the CA.
  • If the ACME STAR protocol fails, Order2 goes to invalid, and that same state gets mirrored in Order1 (aka the NDC Order).
  • If the ACME STAR run succeeds (so Order2 is valid), IdO copies the star-certificate URL from Order2 over to Order1 and flips Order1 to valid ๐Ÿ”ฅ

Once that's done, the NDC can grab the short-term certificate with the delegated name, install it, and use it ๐Ÿซถ The STAR certificate is good until it expires, and when it does, the NDC is guaranteed to have a fresh one waiting to be downloaded, installed, and used. This keeps going with each new certificate until either Order1 expires or the IdO decides to cancel the auto-renewal with the CA. Iconic cycle, honestly ๐Ÿ‘‘

Note that the interactive identifier authorization phase from Section 7.5 of [RFC8555] gets skipped on the NDC-IdO side ๐Ÿ™ˆ That's because the delegated identity in the CSR that the NDC hands to the IdO gets checked against the configured CSR template (Section 4.1). So the NDC sends its finalize request, CSR and all, to the IdO right after Order1 has been acknowledged. The IdO SHALL buffer a (valid) CSR until the Validation phase completes successfully.

Also, the unauthenticated GET from Section 3.4 of [RFC8739] needs to work out, because that's how the NDC gets to read the star-certificate URL on the CA. No GET, no cert, no vibes โœจ
 .------.            .---------------.            .------.
|  NDC   |          |       IdO       |          |  ACME  |
+--------+          +--------+--------+          +--------+
| Client |          | Server | Client |          | Server |
'---+----'          '----+---+---+----'          '----+---'
    |                    |       |                    |
    |   Order1           |       |                    |
    |   Signature        |       |                    |
    o------------------->|       |                    |
    |                    |       |                    |
    | [ No identity    ] |       |                    |
    | [ validation via ] |       |                    |
    | [ authorizations ] |       |                    |
    |                    |       |                    |
    |   CSR              |       |                    |
    |   Signature        |       |                    |
    o------------------->|       |                    |
    |   Acknowledgement  |       |   Order2           |
    |<-------------------o       |   Signature        |
    |                    |       o------------------->|
    |                    |       |         Required   |
    |                    |       |   Authorizations   |
    |                    |       |<-------------------o
    |                    |       |   Responses        |
    |                    |       |   Signature        |
    |                    |       o------------------->|
    |                    |       |                    |
    |                    |       |<~~~~Validation~~~~>|
    |                    |       |                    |
    |                    |       |   CSR              |
    |                    |       |   Signature        |
    |                    |       o------------------->|
    |                    |       |   Acknowledgement  |
    |                    |       |<-------------------o
    |                    |       |                    |
    |<~~Await issuance~->|       |<~~Await issuance~~>|
    |                                                 |
    |     (unauthenticated) GET STAR certificate      |
    o------------------------------------------------>|
    |                 Certificate #1                  |
    |<------------------------------------------------o
    |     (unauthenticated) GET STAR certificate      |
    o------------------------------------------------>|
    |                 Certificate #2                  |
    |<------------------------------------------------o
    |                     [...]                       |
    |     (unauthenticated) GET STAR certificate      |
    o------------------------------------------------>|
    |                 Certificate #n                  |
    |<------------------------------------------------o

              Figure 1: End-to-End STAR Delegation Flow

2.3. Delegated Identity Profile ๐Ÿ’–

This section defines a profile of the ACME protocol to be used between the NDC and IdO. It's the rulebook for their little chat ๐Ÿงš

2.3.1. Delegation Configuration ๐ŸŒˆ

The IdO must be preconfigured to recognize one or more NDCs and hand them the details about the certificate delegations that apply to each one ๐Ÿ’…

2.3.1.1. Account Object Extensions

An NDC shows up to the IdO as an ACME account. The IdO can delegate multiple names to a single NDC, and those setups get described through "delegation" objects hanging off that NDC's account object on the IdO ๐Ÿฆ‹

As Figure 2 shows, the ACME account resource on the IdO gets a new delegations attribute:

delegations (required, string): A URL where you can fetch a list of the delegations configured for this account (Section 2.3.1.3) using a POST-as-GET request.

{
  "status": "valid",
  "contact": [
    "mailto:delegation-admin@ido.example"
  ],
  "termsOfServiceAgreed": true,
  "orders": "https://example.com/acme/orders/saHpfB",
  "delegations": "https://acme.ido.example/acme/delegations/adFqoz"
}

Figure 2: Example Account Object with Delegations

2.3.1.2. Delegation Lists

Every account object has a delegations URL that gives you the list of delegation configs the IdO made, again through a POST-as-GET request. The response MUST be a JSON object where the delegations field is an array of URLs, and each URL points to a delegation configuration that's available to the NDC account (Section 2.3.1.3). The server MAY send back an incomplete list, and if it does, it'll include a Link header field with a next link relation that tells you where to find the rest ๐Ÿง 

HTTP/1.1 200 OK
Content-Type: application/json
Link: <https://acme.ido.example/acme/directory>;rel="index"
Link: <https://acme.ido.example/acme/delegations/adFqoz?/
      cursor=2>;rel="next"

{
  "delegations": [
    "https://acme.ido.example/acme/delegation/ogfr8EcolOT",
    "https://acme.ido.example/acme/delegation/wSi5Lbb61E4",
    /* more URLs not shown for example brevity */
    "https://acme.ido.example/acme/delegation/gm0wfLYHBen"
  ]
}

Quick note on that example: the second Link URL got split across two lines purely so it'd fit on the page ๐Ÿ™ˆ The actual URL is https://acme.ido.example/acme/delegations/adFqoz?cursor=2.

2.3.1.3. Delegation Objects

This profile adds a new read-only delegation object to the ACME resource model. It represents a delegation configuration that applies to a given NDC, and honestly it's giving main character energy ๐Ÿ‘‘

A delegation object holds the CSR template (see Section 4) that applies to that delegation and, if you want, any related CNAME mapping for the delegated identifiers. Here's how it's laid out:

csr-template (required, object): The CSR template, as defined in Section 4.

cname-map (optional, object): A map of FQDN pairs. In each pair, the name is the delegated identifier, and the value is the matching NDC name that gets aliased in the IdO's zone file so resolvers get redirected to the delegated entity. Both names and values MUST be FQDNs with a terminating '.'. This field only means something for identifiers of type "dns" ๐Ÿ“

Figure 3 has an example delegation object in JSON:

{
  "csr-template": {
    "keyTypes": [
      {
        "PublicKeyType": "id-ecPublicKey",
        "namedCurve": "secp256r1",
        "SignatureType": "ecdsa-with-SHA256"
      }
    ],
    "subject": {
      "country": "CA",
      "stateOrProvince": "**",
      "locality": "**"
    },
    "extensions": {
      "subjectAltName": {
        "DNS": [
          "abc.ido.example"
        ]
      },
      "keyUsage": [
        "digitalSignature"
      ],
      "extendedKeyUsage": [
        "serverAuth"
      ]
    }
  },
  "cname-map": {
    "abc.ido.example.": "abc.ndc.example."
  }
}

Figure 3: Example Delegation Configuration Object

Now, to say which delegation applies to a certificate request, the order object on the NDC-IdO side gets a new delegation attribute (see Figures 4 and 7) โœจ Its value is the URL of the delegation configuration object to use for that certificate request. If the delegation attribute in the order object has a URL that doesn't match a configuration the requesting ACME account can access, the IdO MUST return an error response with status code 403 (Forbidden), along with a problem document [RFC7807] whose type is urn:ietf:params:acme:error:unknownDelegation ๐Ÿฅบ

2.3.2. Order Object Transmitted from NDC to IdO and to ACME Server (STAR) ๐ŸŽ€

okay bestie, this is the STAR version, so the NDC has to build a request that's fully loaded for auto-renewal ๐Ÿ’… If the delegation is for a STAR certificate, the request object the NDC creates:

  • MUST have a "delegation" attribute pointing at the preconfigured delegation that applies to this Order ๐Ÿฆ‹
  • MUST have entries in the "identifiers" field for each delegated name present in the configuration ๐ŸŒธ
  • MUST NOT contain the "notBefore" and "notAfter" fields ๐Ÿ™ˆ
  • MUST contain an "auto-renewal" object, and inside it the fields listed in Section 3.1.1 of [RFC8739]. In particular, the "allow-certificate-get" attribute MUST be present and set to true โœจ

Here's what that looks like on the wire ๐Ÿ‘€

POST /acme/new-order HTTP/1.1
Host: acme.ido.example
Content-Type: application/jose+json

{
  "protected": base64url({
    "alg": "ES256",
    "kid": "https://acme.ido.example/acme/acct/evOfKhNU60wg",
    "nonce": "Alc00Ap6Rt7GMkEl3L1JX5",
    "url": "https://acme.ido.example/acme/new-order"
  }),
  "payload": base64url({
    "identifiers": [
      {
        "type": "dns",
        "value": "abc.ido.example"
      }
    ],
    "auto-renewal": {
      "end-date": "2021-04-20T00:00:00Z",
      "lifetime": 345600,          // 4 days
      "allow-certificate-get": true
    },
    "delegation":
      "https://acme.ido.example/acme/delegation/gm0wfLYHBen"
  }),
  "signature": "g454e3hdBlkT4AEw...nKePnUyZTjGtXZ6H"
}

Figure 4: New STAR Order from NDC

Now the IdO makes its own order object, and it's giving very specific energy ๐Ÿ’– The order object that is created on the IdO:

  • MUST start in the "ready" state ๐Ÿ“
  • MUST contain an "authorizations" array with zero elements ๐Ÿงš
  • MUST contain the indicated "delegation" configuration ๐Ÿ’œ
  • MUST contain the indicated "auto-renewal" settings โญ
  • MUST NOT contain the "notBefore" and "notAfter" fields ๐Ÿ’€
{
  "status": "ready",
  "expires": "2021-05-01T00:00:00Z",

  "identifiers": [
   {
     "type": "dns",
     "value": "abc.ido.example"
   }
  ],

  "auto-renewal": {
    "end-date": "2021-04-20T00:00:00Z",
    "lifetime": 345600,
    "allow-certificate-get": true
  },

  "delegation":
    "https://acme.ido.example/acme/delegation/gm0wfLYHBen",

  "authorizations": [],

  "finalize": "https://acme.ido.example/acme/order/TO8rfgo/finalize"
}

Figure 5: STAR Order Resource Created on IdO

Next up, the NDC finalizes the Order by sending over the CSR with the delegated identifiers ๐Ÿซถ The IdO checks that CSR against the template in the "delegation" object that applies to this request, as described in Section 4.1. If the CSR fails validation for any of the identifiers, the IdO MUST return an error response with status code 403 (Forbidden) and an appropriate type, e.g., "rejectedIdentifier" or "badCSR". The error response SHOULD contain subproblems (Section 6.7.1 of [RFC8555]) for each failed identifier ๐Ÿ”ฅ If the CSR passes, the order status moves to "processing" and the twin ACME protocol instance kicks off on the IdO-CA side โœจ

The request object the IdO creates (the one heading to the CA) is also a little picky ๐Ÿ’… The request object created by the IdO:

  • MUST copy the identifiers sent by the NDC ๐ŸŒˆ
  • MUST strip the "delegation" attribute ๐Ÿ™ˆ
  • MUST carry a copy of the "auto-renewal" object sent by the NDC ๐ŸŽ€

Once the identifiers' authorization is done and the CA has issued the certificate, the IdO does two things. When the identifiers' authorization has been successfully completed and the certificate has been issued by the CA, the IdO:

  • MUST move its Order resource status to "valid" and
  • MUST copy the "star-certificate" field from the STAR Order returned by the CA into its Order resource. When dereferenced, the "star-certificate" URL includes (via the "Cert-Not-Before" and "Cert-Not-After" HTTP header fields) the renewal timers needed by the NDC to inform its certificate reload logic ๐Ÿฆ‹
{
  "status": "valid",
  "expires": "2021-05-01T00:00:00Z",

  "identifiers": [
   {
     "type": "dns",
     "value": "abc.ido.example"
   }
  ],

  "auto-renewal": {
    "end-date": "2021-04-20T00:00:00Z",
    "lifetime": 345600,
    "allow-certificate-get": true
  },

  "delegation":
    "https://acme.ido.example/acme/delegation/gm0wfLYHBen",

  "authorizations": [],

  "finalize": "https://acme.ido.example/acme/order/TO8rfgo/finalize",

  "star-certificate": "https://acme.ca.example/acme/order/yTr23sSDg9"
}

Figure 6: STAR Order Resource Updated on IdO

Now for the big catch ๐Ÿ™ˆ This whole delegation thing only works if the NDC can grab certificates on a schedule with an unauthenticated HTTP GET. The NDC usually doesn't have an account on the CA, so it can't send the usual POST-as-GET ACME request. That means the IdO SHOULD check the CA's directory object (as per Section 3.4 of [RFC8739]) to confirm the selected CA supports unauthenticated GET before it forwards the Order request. If the CA doesn't support unauthenticated GET of STAR certificates, the IdO MUST NOT forward the Order request. Instead, it MUST move the Order status to "invalid" and set "allow-certificate-get" in the "auto-renewal" object to "false". Same deal if the Order gets forwarded but the CA doesn't reflect the "allow-certificate-get" setting in its Order resource ๐Ÿ’€ The combo of "invalid" status plus denied "allow-certificate-get" at the IdO is a clear, unambiguous (asynchronous) signal to the NDC about why it failed โœจ

2.3.2.1. CNAME Installation ๐ŸŒธ

If one of the objects in the "identifiers" list is of type "dns", the IdO can add the CNAME records specified in the "delegation" object to its zone. For example:

abc.ido.example. CNAME abc.ndc.example.

2.3.3. Order Object Transmitted from NDC to IdO and to ACME Server (Non-STAR) ๐Ÿงš

Now the non-STAR version, which is the simpler sibling ๐Ÿ’– If the delegation is for a non-STAR certificate, the request object the NDC creates:

  • MUST have a "delegation" attribute pointing at the preconfigured delegation that applies to this Order ๐Ÿฆ‹
  • MUST have entries in the "identifiers" field for each delegated name present in the configuration; and
  • MUST have the "allow-certificate-get" attribute set to true ๐Ÿ“
POST /acme/new-order HTTP/1.1
Host: acme.ido.example
Content-Type: application/jose+json

{
  "protected": base64url({
    "alg": "ES256",
    "kid": "https://acme.ido.example/acme/acct/evOfKhNU60wg",
    "nonce": "IYBkoQfaCS80UcCn9qH8Gt",
    "url": "https://acme.ido.example/acme/new-order"
  }),
  "payload": base64url({
    "identifiers": [
      {
        "type": "dns",
        "value": "abc.ido.example"
      }
    ],
    "delegation":
      "https://acme.ido.example/acme/delegation/gm0wfLYHBen",
    "allow-certificate-get": true
  }),
  "signature": "j9JBUvMigi4zodud...acYkEKaa8gqWyZ6H"
}

Figure 7: New Non-STAR Order from NDC

The order object the IdO creates for this one:

  • MUST start in the "ready" state ๐ŸŒˆ
  • MUST contain an "authorizations" array with zero elements ๐ŸŽ€
  • MUST contain the indicated "delegation" configuration; and
  • MUST contain the indicated "allow-certificate-get" setting ๐Ÿ’œ
{
  "status": "ready",
  "expires": "2021-05-01T00:00:00Z",

  "identifiers": [
   {
     "type": "dns",
     "value": "abc.ido.example"
   }
  ],

  "delegation":
    "https://acme.ido.example/acme/delegation/gm0wfLYHBen",

  "allow-certificate-get": true,

  "authorizations": [],

  "finalize": "https://acme.ido.example/acme/order/3ZDlhYy/finalize"
}

Figure 8: Non-STAR Order Resource Created on IdO

Finalization by the NDC and the CSR validation by the IdO go exactly like the STAR case ๐Ÿซถ If the CSR passes, the order status moves to "processing" and the twin ACME protocol instance starts on the IdO-CA side.

The request object the IdO creates:

  • MUST copy the identifiers sent by the NDC โœจ
  • MUST strip the "delegation" attribute ๐Ÿ’…
  • MUST copy the "allow-certificate-get" attribute ๐Ÿฆ‹

When the identifiers' authorization is done and the CA issues the certificate, the IdO:

  • MUST move its Order resource status to "valid" and
  • MUST copy the "certificate" field from the Order returned by the CA into its Order resource, as well as "notBefore" and "notAfter" if these fields exist ๐ŸŒธ
{
  "status": "valid",
  "expires": "2021-05-01T00:00:00Z",

  "identifiers": [
   {
     "type": "dns",
     "value": "abc.ido.example"
   }
  ],

  "delegation":
    "https://acme.ido.example/acme/delegation/gm0wfLYHBen",

  "allow-certificate-get": true,

  "authorizations": [],

  "finalize": "https://acme.ido.example/acme/order/3ZDlhYy/finalize",

  "certificate": "https://acme.ca.example/acme/order/YtR23SsdG9"
}

Figure 9: Non-STAR Order Resource Updated on IdO

At this point in the flow, the same considerations as in Section 2.3.2.1 apply ๐ŸŽ€

Before the IdO forwards the Order request to the CA, it SHOULD confirm that the selected CA supports unauthenticated GET. It does this by checking the relevant settings in the CA's directory object, as per Section 2.3.5. If the CA doesn't support unauthenticated GET of certificate resources, the IdO MUST NOT forward the Order request. Instead, it MUST move the Order status to "invalid" and set the "allow-certificate-get" attribute to "false". The same thing happens if the Order request does get forwarded and the CA doesn't reflect the "allow-certificate-get" setting in its Order resource. The combo of "invalid" status and denied "allow-certificate-get" in the Order resource at the IdO is an unambiguous (asynchronous) signal to the NDC about the failure reason ๐Ÿ”ฅ

2.3.4. Capability Discovery ๐Ÿ”

To help a client find out whether this profile is supported, the directory object of an ACME server (usually one the IdO deploys) includes the following attribute in the "meta" field:

delegation-enabled (optional, boolean): Boolean flag indicating support for the profile specified in this memo. An ACME server that supports this delegation profile MUST include this key and MUST set it to true ๐Ÿ’–

The IdO MUST declare its support for delegation using "delegation-enabled", no matter whether it supports delegation of STAR certificates, non-STAR certificates, or both ๐ŸŒˆ

And to help a client discover support for certificate fetching with unauthenticated HTTP GET, the directory object of an ACME server (usually one the CA deploys) includes the following attribute in the "meta" field:

allow-certificate-get (optional, boolean): See Section 2.3.5. ๐Ÿงš

2.3.5. Negotiating an Unauthenticated GET ๐Ÿ”“โœจ

okay so bestie, this part is about letting non-STAR certificates be delegated too ๐Ÿ’…. The trick is a little handshake where the server says "yep, I'll let anyone GET my cert" and the client says "cool, I want that for this Order" ๐Ÿซถ. It's giving trust, but make it per-Order ๐Ÿฆ‹.

Heads up, this is basically the same vibe as Section 3.4 of [RFC8739] for STAR, same names and same meanings ๐ŸŒธ. The only difference is the cert lives on the certificate resource, not the star-certificate resource. ALSO the placement is different. Instead of hiding everything inside an "auto-renewal" subobject like STAR does, these attributes just chill at the top level ๐Ÿ’œ.

The server flags that it's down to grant unauthenticated access by setting "allow-certificate-get" to "true" in the "meta" field of the directory object ๐Ÿ“:

allow-certificate-get (optional, boolean):  If this field is present
   and set to "true", the server allows GET (and HEAD) requests to
   certificate URLs.

Then the client says it wants that same access by adding an "allow-certificate-get" attribute to its newOrder payload and setting it to "true" ๐Ÿงš:

allow-certificate-get (optional, boolean):  If this field is present
   and set to "true", the client requests the server to allow
   unauthenticated GET (and HEAD) to the certificate associated with
   this Order.

If the server accepts, it MUST reflect the attribute setting in the resulting order object ๐Ÿ“. That's the non-negotiable part, periodt ๐Ÿ’€.

Also, even when unauthenticated GET has been agreed on, the server MUST also allow POST-as-GET requests to the certificate resource ๐Ÿ”ฅ. So the unauthenticated lane doesn't replace the authenticated one, it just sits next to it ๐Ÿ‘‘.

2.3.6. Terminating the Delegation ๐Ÿฅ€

okay, the ending of a delegation is different depending on whether it's a STAR certificate or not ๐ŸŒˆ. Let's break it down โœจ.

2.3.6.1. By Cancellation (STAR) ๐Ÿ›‘

The IdO can end the delegation of a STAR certificate by asking for its cancellation (see Section 3.1.2 of [RFC8739]) ๐Ÿ’–.

Cancellation of the ACME STAR certificate is the IdO's main character move ๐Ÿ‘‘. The NDC doesn't own the relevant account key on the CA, so it can't send a cancellation request for the STAR cert ๐Ÿ™ˆ. It could technically ask to revoke a single STAR cert, since it holds that cert's private key ๐Ÿ˜ญ. BUT STAR explicitly disables the revokeCert interface, so, not meโ€ฆ ๐Ÿ’….

Once the IdO stops the automatic renewal, the last issued STAR cert expires shortly after and the delegation is over ๐Ÿฆ‹.

2.3.6.2. By Revocation (Non-STAR) ๐Ÿงจ

For non-STAR certs, the IdO can end the delegation by asking for the cert to be revoked using the "revokeCert" URL exposed by the CA ๐Ÿ’œ.

According to Section 7.6 of [RFC8555], the revocation endpoint can be used with either the account key pair or the certificate key pair ๐Ÿ”‘. So an NDC that finds the CA's "revokeCert" URL (it's publicly available in the CA's directory object) could revoke the cert using the associated private key ๐Ÿ‘€. BUT, given the trust relationship between the NDC and IdO that the delegation trust model expects (Section 7.1), plus the lack of incentive for the NDC to end the delegation early, this isn't a significant security risk ๐Ÿซถโœจ.


2.4. Proxy Behavior ๐Ÿ”€

There are cases where the ACME Delegation flow should be proxied, like the use case in Section 5.1.2 ๐ŸŒธ. This section explains how those proxies behave ๐Ÿงš.

An entity playing the IdO server role (an "ACME Delegation server") may, per identity, either act as a proxy into another ACME Delegation server or act as an IdO and get a cert directly ๐Ÿฆ‹. The deciding factor is whether it can get successfully authorized by the next-hop ACME server for the identity tied to the cert request ๐Ÿ”ฅ.

The identities each server supports, and the disposition for each one, are preconfigured ๐Ÿ“.

Here's what the proxy does for each message in the ACME Delegation process ๐Ÿ’…:

New-order request:

  • The complete "identifiers" attribute MUST be copied as is ๐Ÿ’–.
  • Similarly, the "auto-renewal" object MUST be copied as is ๐ŸŒˆ.

New-order response:

  • The "status", "expires", "authorizations", "identifiers", and "auto-renewal" attributes/objects MUST be copied as is ๐Ÿซถ.
  • The "finalize" URL is rewritten so the "finalize" request goes to the proxy ๐Ÿ”.
  • Similarly, the "Location" header MUST be rewritten to point to an order object on the proxy ๐Ÿ“.
  • Any "Link" relations MUST be rewritten to point to the proxy ๐Ÿ”—.

Get Order response:

  • The "status", "expires", "authorizations", "identifiers", and "auto-renewal" attributes/objects MUST be copied as is โœจ.
  • Similarly, the "star-certificate" URL (or the "certificate" URL for non-STAR requests) MUST be copied as is ๐ŸŽ€.
  • The "finalize" URL is rewritten so the "finalize" request goes to the proxy ๐Ÿ”.
  • The "Location" header MUST be rewritten to point to an order object on the proxy ๐Ÿ“.
  • Any "Link" relations MUST be rewritten to point to the proxy ๐Ÿ”—.

"finalize" request:

  • The CSR MUST be copied as is ๐Ÿ“œ.

"finalize" response:

  • The "Location" header, "Link" relations, and the "finalize" URLs are rewritten as for Get Order ๐Ÿฆ‹.

We should note that all the above messages are authenticated, so each proxy must be able to authenticate any subordinate server ๐Ÿ”. Trust chains, bestie ๐Ÿซถ.


3. CA Behavior ๐Ÿ›๏ธ

okay so, this document (especially Section 2) is mostly about the protocol between the NDC and IdO ๐Ÿ’œ. BUT the protocol also affects the ACME server running in the CA ๐Ÿงš.

A CA that wants to support certificate delegation MUST also support unauthenticated certificate fetching ๐Ÿ”“. It declares that using "allow-certificate-get" (Section 2.3.5, Paragraph 3) ๐Ÿ“ฃ. No CA left behind ๐Ÿ’….


4. CSR Template ๐Ÿ“œ๐Ÿ’–

The CSR template is how the shape of the CSR the NDC uses to request the certificate gets expressed and constrained ๐ŸŽ€. The same CSR is used for every certificate created under the same delegation ๐Ÿ”. Its validation by the IdO is a critical piece of the security of the whole delegation mechanism ๐Ÿ”, so no slacking ๐Ÿ˜ค.

Instead of defining every possible CSR attribute, this document keeps it minimalist ๐ŸŒธ. It only declares the minimum attribute set and leaves registering more specific attributes to future documents ๐Ÿฆ‹.

4.1. Template Syntax โœ๏ธ

The template is a JSON document ๐Ÿงพ. Each field (except "keyTypes", which we'll get to) means one of these three things ๐Ÿ’…:

  • A mandatory field where the template gives the literal value of that field. This is shown as a literal string, like "abc.ido.example" ๐Ÿ“.
  • A mandatory field where the client defines the content. This is shown as "**" ๐Ÿซถ.
  • An optional field where the client decides whether the field is included in the CSR and, if so, what its value is. This is shown as "*" ๐ŸŽ€.

The NDC MUST NOT include any fields in the CSR, including any extensions, unless they're specified in the template ๐Ÿšซ. Strict, but that's the vibe ๐Ÿ’€.

The structure of the template object is defined by the Concise Data Definition Language (CDDL) [RFC8610] document in Appendix A ๐Ÿ“š. There's also an alternative, nonnormative JSON Schema syntax in Appendix B ๐Ÿงฉ. The CSR template has to follow the syntax defined here, but neither the IdO nor the NDC is expected to validate it at runtime ๐Ÿ™ƒ.

The "subject" field and its subfields get mapped into the "subject" field of the CSR, as per Section 4.1.2.6 of [RFC5280] ๐Ÿ—บ๏ธ. Other extension fields of the CSR template get mapped into the CSR according to the table in Section 6.5 ๐Ÿ“Š.

The "subjectAltName" field is currently defined for these identifiers: DNS names, email addresses, and URIs ๐ŸŒ. New identifier types may be added later by documents that extend this spec ๐Ÿ”ฎ. Each new identifier type SHALL have an associated identifier validation challenge that the CA can use to get proof of the requester's control over it ๐Ÿ”‘. That's a must-have, bestie.

The "keyTypes" property isn't copied into the CSR ๐Ÿ™…. Instead, it constrains the "SubjectPublicKeyInfo" field of the CSR, which MUST have the type/size defined by one of the array members of the "keyTypes" property ๐Ÿ”‘โœจ.

When the IdO receives the CSR, it MUST verify that the CSR is consistent with the template in the "delegation" object referenced in the Order ๐Ÿ•ต๏ธโ€โ™€๏ธ. The IdO MAY enforce additional constraints, like restricting field lengths ๐Ÿ“. Also, a "subjectAltName" of type "DNS" can use wildcard notation, which means the NDC can be required ("**") or offered the option ("*") to define the delegated domain name itself ๐ŸŒธ. If that's the case, the IdO MUST apply application-specific checks on top of the control rules the CSR template already provides, so the requested domain name is legit under its local policy ๐Ÿ”ฅ๐Ÿ‘‘.

4.2. Example ๐ŸŽ€

The CSR template in Figure 10 is one possible CSR template governing the delegation exchanges in the rest of this document ๐Ÿ’–.

{
  "keyTypes": [
    {
      "PublicKeyType": "rsaEncryption",
      "PublicKeyLength": 2048,
      "SignatureType": "sha256WithRSAEncryption"
    },
    {
      "PublicKeyType": "id-ecPublicKey",
      "namedCurve": "secp256r1",
      "SignatureType": "ecdsa-with-SHA256"
    }
  ],
  "subject": {
    "country": "CA",
    "stateOrProvince": "**",
    "locality": "**"
  },
  "extensions": {
    "subjectAltName": {
      "DNS": [
        "abc.ido.example"
      ]
    },
    "keyUsage": [
      "digitalSignature"
    ],
    "extendedKeyUsage": [
      "serverAuth",
      "clientAuth"
    ]
  }
}

Figure 10: Example CSR Template ๐Ÿงพ


5. Further Use Cases ๐ŸŒˆ

This nonnormative section covers more use cases that implement STAR certificate delegation in nontrivial ways ๐Ÿงฉ.

5.1. CDN Interconnection (CDNI) ๐ŸŒ

[HTTPS-DELEGATION] talks through several solutions for different delegation requirements in the CDN Interconnection (CDNI) environment ๐Ÿ“–. This section covers two of those requirements in the context of the STAR delegation workflow โœจ.

This section uses CDNI terminology, like Upstream CDN (uCDN) and Downstream (dCDN), as defined in [RFC7336] ๐Ÿ’œ.

5.1.1. Multiple Parallel Delegates ๐Ÿ‘ฏโ€โ™€๏ธ

Sometimes the content owner (IdO) wants to delegate authority over a website to multiple NDCs (CDNs) ๐Ÿ“. This could happen if the IdO has agreements with different regional CDNs for different geographic regions, or if a "backup" CDN handles overflow traffic by temporarily changing some of the CNAME mappings in place ๐Ÿ”. The STAR delegation flow makes this use case work naturally ๐Ÿฆ‹, since each CDN can authenticate separately to the IdO (through its own separate account), specify its CSR, and the IdO is free to allow or deny each certificate request according to its own policy ๐Ÿ‘‘๐Ÿ’….

5.1.2. Chained Delegation ๐Ÿ”—โœจ

okay so bestie, this one is a whole vibe ๐Ÿ’… a content owner (IdO) delegates some domains to a big CDN (uCDN), and that big CDN turns around and delegates to a smaller regional CDN (dCDN) ๐ŸŒธ the IdO has a contract with uCDN, and uCDN has a similar contract with dCDN, but the IdO may not even know dCDN exists ๐Ÿ™ˆ the way that works, lowkey messy but iconic ๐Ÿ‘‘

if it's needed, the STAR protocol can be chained to make this work ๐Ÿฆ‹ uCDN could forward requests from dCDN over to IdO and then forward the responses back down to dCDN ๐ŸŽ€ whether that kind of proxying is allowed is totally up to policy and the contracts between everyone ๐Ÿ“œ

there also has to be a mechanism at the uCDN-to-dCDN interface ๐Ÿ’œ so uCDN can advertise:

  • the names that dCDN is allowed to use, and
  • the policy for making the key material (allowed algorithms, minimum key lengths, key usage, etc.) that dCDN has to meet ๐Ÿ”

and ngl, the CSR template is the thing that provides that mechanism ๐Ÿ’–

5.1.2.1. Two-Level Delegation in CDNI ๐ŸŒˆ

okay picture this ๐Ÿงš a User Agent (UA), like a browser or a set-top box, wants to fetch the video at https://video.cp.example/movie. the redirection between the content provider (CP) and the upstream and downstream CDNs is set up as a CNAME-based aliasing chain, shown in Figure 11 ๐Ÿฆ‹

                                                    .------------.
                            video.cp.example ?     | .-----.      |
                 .---------------------------------->|     |      |
                |                  (a)             | | DNS |  CP  |
                |    .-------------------------------+     |      |
                |   |   CNAME video.ucdn.example   | '-----'      |
                |   |                               '------------'
                |   |
                |   |
    .-----------|---v--.                            .------------.
   |    .-----.-+-----. |   video.ucdn.example ?   | .-----.      |
   |    |     |       +----------------------------->|     |      |
   | UA | TLS |  DNS  | |          (b)             | | DNS | uCDN |
   |    |     |       |<-----------------------------+     |      |
   |    '--+--'-----+-' | CNAME video.dcdn.example | '-----'      |
    '------|----^---|--'                            '------------'
           |    |   |
           |    |   |
           |    |   |                               .------------.
           |    |   |      video.dcdn.example ?    | .-----.      |
           |    |    '------------------------------>|     |      |
           |    |                  (c)             | | DNS |      |
           |     '-----------------------------------+     |      |
           |                   A 192.0.2.1         | +-----+ dCDN |
           |                                       | |     |      |
            '--------------------------------------->| TLS |      |
                        SNI: video.cp.example      | |     |      |
                                                   | '-----'      |
                                                    '------------'

                         Figure 11: DNS Redirection

so here's the spicy part ๐ŸŒถ๏ธ with HTTP-based redirection, the original URL gets swapped out for whatever is in the "Location" header of the 302 response. but DNS redirection is totally transparent to the User Agent ๐Ÿซฅ which means the TLS connection to the dCDN edge uses a Server Name Indication (SNI) equal to the "host" in the original URI. in this example, that's "video.cp.example" ๐Ÿ˜ญ so to actually finish the handshake, the landing dCDN node has to be configured with a certificate whose "subjectAltName" field matches "video.cp.example", which is a content provider's name ๐Ÿ’€

Figure 12 shows the cascaded delegation flow that lets dCDN get a STAR certificate with a name belonging to the content provider, while the private key is only known to dCDN ๐Ÿ”‘โœจ slay ๐Ÿ‘‘

           .--------------------.
          |      .------.------. |
          |      | STAR | ACME |<-------------.
          |  CP  | dele | STAR | |             |
          |      | srv  | cli  +-----.         |
          |      '---+--'------' |    |        6
           '---------|------^---'     5        |
                     |      |         |     .--|-------.
                     |      |         |    | .-+----.   |
                     7      |          '---->| ACME |   |
                     |      |              | | STAR | C |
                     |      4              | +------| A |
                     |      |              | | HTTP |   |
                     |      |              | '----+-'   |
                     |   .-'                '--^--|----'
      .--------------v--|--.                   |  |
     |      .------.----+-. |                  |  10
     |      |      | STAR | |                  |  |
     | uCDN | CDNI | dele | |                  |  |
     |      |      | fwd  | |                  |  |
     |      '----+-'-+----' |                  |  |
      '-------^--|---|--^--'                   |  |
              |  |   |  |                      |  |
              |  2   8  |                      |  |
              1  |   |  3                      |  |
              |  |   |  |                      9  |
      .-------|--v---v--|---------.            |  |
     |      .-+----.----+-.------. |           |  |
     |      |      | STAR |      +------------'   |
     | dCDN | CDNI | dele | HTTP | |              |
     |      |      | cli  |      |<--------------'
     |      '------'------'------' |
      '---------------------------'

               Figure 12: Two-Level Delegation in CDNI

the setup here is that uCDN is configured to delegate to dCDN, and CP is configured to delegate to uCDN, both as defined in Section 2.3.1 ๐ŸŽ€ and then the flow goes like this:

  1. dCDN requests CDNI path metadata from uCDN ๐Ÿ“จ
  2. uCDN replies with, among other CDNI metadata, the STAR delegation configuration, which includes the delegated content provider's name ๐Ÿ—‚๏ธ
  3. dCDN creates a key pair and the CSR with the delegated name, then places an order for that name with uCDN ๐Ÿ”
  4. uCDN forwards the received order to the content provider (CP) ๐Ÿš€
  5. CP creates an order for a STAR certificate and sends it to the CA. the order also asks for unauthenticated access to the certificate resource ๐Ÿ™Œ
  6. once all the authorizations finish successfully, the STAR certificate gets issued ๐ŸŽ‰
  7. CP lets uCDN know the STAR certificate is ready at the order's "star-certificate" URL ๐Ÿ“ฃ
  8. uCDN passes that info along to dCDN, and at this point the ACME signaling is complete โœ…
  9. dCDN grabs the STAR certificate with an unauthenticated GET from the CA ๐Ÿƒโ€โ™€๏ธ
  10. the CA sends back the certificate, and now dCDN is fully set up to handle HTTPS traffic in place of the content provider ๐Ÿ’–

note that steps 9 and 10 keep repeating until the delegation expires or gets terminated ๐Ÿ”โณ

5.2. Secure Telephone Identity Revisited (STIR) ๐Ÿ“ž

okay second use case, and this one is about delegating credentials in the STIR ecosystem [RFC9060] ๐Ÿ’…

this section uses STIR terminology. the Personal Assertion Token (PASSporT) is defined in [RFC8225], and "TNAuthList" is defined in [RFC8226] ๐ŸŽ€

so in STIR delegated mode, a service provider SP2 (the NDC) needs to sign PASSporTs [RFC8225] for telephone numbers (e.g., TN=+123) that belong to another service provider, SP1 (the IdO) ๐Ÿ“ฑ to pull that off, SP2 needs a STIR certificate and a private key that includes TN=+123 in the TNAuthList [RFC8226] certificate extension ๐Ÿ”‘

here's the step-by-step (Figure 13) ๐Ÿฆ‹

  1. SP1 and SP2 agree on the configuration of the delegation, especially the CSR template that applies ๐Ÿค
  2. SP2 generates a private/public key pair and sends a CSR to SP1. it requests a certificate with an SP1 name, an SP2 public key, and a TNAuthList extension listing the TNs that SP1 delegates to SP2 ๐Ÿ“ (heads up: the CSR SP2 sends to SP1 needs to be validated against the CSR template agreed on in step 1.)
  3. SP1 sends an order for the CSR to the CA. the order also asks for unauthenticated access to the certificate resource ๐Ÿ“ฌ
  4. after the required TNAuthList authorizations succeed, the CA moves the order to a "valid" state, and at the same time the star-certificate endpoint gets populated ๐ŸŽŠ
  5. the contents of the order get forwarded from SP1 to SP2 through the paired "delegation" order ๐Ÿ”
  6. SP2 dereferences the "star-certificate" URL in the order to fetch the rolling STAR certificate with the delegated identifiers ๐Ÿƒโ€โ™€๏ธ
  7. the STAR certificate is returned to SP2 ๐ŸŽ
     .-------------------.
    |     .------.------. |
    |     | STAR | STAR |<--------------.
.-->| SP1 | dele | dele | |              |
|   |     | srv  | cli  +-----.          |
|   |     '----+-'------' |    |         4
|    '------^--|---------'     3         |
|    |            |  |               |    .----|-----.
|    |            |  5               |   | .---+--.   |
|    |            |  |                '--->| ACME |   |
|    |            |  |                   | | STAR | C |
1    |            |  |                   | +------| A |
|    |            2  |               |   | | HTTP |   |
|    |            |  |               |   | '---+--'   |
|    |     .------|--v---------.     6   '----|-----'
|    |    |     .-+----.------. |    |         7
|    |    |     | STAR |      +-----'          |
 '-->| SP2 | dele | HTTP | |              |
    |     | cli  |      |<--------------'
    |     '----+-'-+----' |
     '-------------------'

                   Figure 13: Delegation in STIR

so the STAR delegation profile in this document applies straightforwardly ๐ŸŒŸ the only extra requirement is being able to tell the NDC which TNAuthList values are allowed, and that can be done with a simple extension to the CSR template ๐Ÿ’œ

6. IANA Considerations ๐ŸŒธ

6.1. New Fields in the "meta" Object within a Directory Object ๐Ÿง

this document adds the following entries to the "ACME Directory Metadata Fields" registry ๐Ÿ“‹

+=======================+============+===========+
| Field Name            | Field Type | Reference |
+=======================+============+===========+
| delegation-enabled    | boolean    | RFC 9115  |
+-----------------------+------------+-----------+
| allow-certificate-get | boolean    | RFC 9115  |
+-----------------------+------------+-----------+

                     Table 1

6.2. New Fields in the Order Object ๐ŸŽ€

this document adds the following entries to the "ACME Order Object Fields" registry ๐Ÿ“‹โœจ

  +=======================+============+==============+===========+
  | Field Name            | Field Type | Configurable | Reference |
  +=======================+============+==============+===========+
  | allow-certificate-get | boolean    | true         | RFC 9115  |
  +-----------------------+------------+--------------+-----------+
  | delegation            | string     | true         | RFC 9115  |
  +-----------------------+------------+--------------+-----------+

                      Table 2

6.3. New Fields in the Account Object ๐Ÿ’…

Okay bestie, this section adds one new entry to the "ACME Account Object Fields" registry ๐Ÿฆ‹ Here's the table, and yes it's giving formal, but the info is so good โœจ

            +=============+============+==========+===========+
            | Field Name  | Field Type | Requests | Reference |
            +=============+============+==========+===========+
            | delegations | string     | none     | RFC 9115  |
            +-------------+------------+----------+-----------+

                                  Table 3

Lowkey the important bit is that the delegations field only gets reported by ACME servers that have delegation-enabled set to true in their meta Object ๐Ÿซถ

6.4. New Error Types ๐Ÿšจ

This one adds entries to the "ACME Error Types" registry, and the new error is literally called unknownDelegation ๐Ÿ’€ It shows up when an unknown configuration is listed in the "delegation" attribute of the order request. Here's the table:

    +===================+================================+===========+
    | Type              | Description                    | Reference |
    +===================+================================+===========+
    | unknownDelegation | An unknown configuration is    | RFC 9115  |
    |                   | listed in the "delegation"     |           |
    |                   | attribute of the order request |           |
    +-------------------+--------------------------------+-----------+

                                 Table 4

6.5. CSR Template Extensions ๐ŸŽ€

IANA set up a brand new registry called "STAR Delegation CSR Template Extensions", and the registration procedure is "Specification Required". Main character energy for sure ๐Ÿ‘‘

Every extension that gets registered has to spell out three things:

  • an extension name,
  • an extension syntax, as a reference to a CDDL document that defines this extension, and
  • the extension's mapping into an X.509 certificate extension.

The starting contents of this registry are the extensions defined by the CDDL in Appendix A. Check out the table, it's so organized ๐ŸŒธ

  +==================+===========+===============================+
  | Extension Name   | Extension | Mapping to X.509 Certificate  |
  |                  | Syntax    | Extension                     |
  +==================+===========+===============================+
  | keyUsage         | See       | [RFC5280], Section 4.2.1.3    |
  |                  | Appendix  |                               |
  |                  | A         |                               |
  +------------------+-----------+-------------------------------+
  | extendedKeyUsage | See       | [RFC5280], Section 4.2.1.12   |
  |                  | Appendix  |                               |
  |                  | A         |                               |
  +------------------+-----------+-------------------------------+
  | subjectAltName   | See       | [RFC5280], Section 4.2.1.6    |
  |                  | Appendix  | (note that only specific name |
  |                  | A         | formats are allowed: URI, DNS |
  |                  |           | name, email address)          |
  +------------------+-----------+-------------------------------+

                                 Table 5

When the designated expert is checking a request for something in this registry, they should follow this guidance:

  • The definition must include a full CDDL definition, which the expert will validate.
  • The definition must include both positive and negative test cases.
  • Additional requirements that are not captured by the CDDL definition are allowed but must be explicitly specified.

7. Security Considerations ๐Ÿ”

Okay this part is SERIOUS, so read it slowly bestie ๐Ÿ™ˆ The security stuff is the whole reason delegation has to be done carefully.

7.1. Trust Model ๐Ÿค

The ACME trust model needs to be extended to cover the trust relationship between NDC and IdO. Once that trust link is set up, it can potentially turn recursive ๐ŸŒ€ That means there has to be a trust relationship between every node in the delegation chain. For example, with cascading CDNs, this is contractually defined.

When you're using standard [RFC6125] identity verification, the IdO has no mechanisms to restrict use of the delegated name once it's been handed over to the first NDC. So contractual measures are expected to be in place to get some assurance that redelegation isn't happening. Scary but important ๐Ÿ˜ญ

7.2. Delegation Security Goal ๐ŸŽฏ

Delegation brings in a new security goal: only an NDC that has been authorized by the IdO, either directly or transitively, can get a certificate with an IdO identity. Iconic goal honestly ๐Ÿ’œ

From a security point of view, the delegation process has five separate parts:

  1. enabling a specific third party (the intended NDC) to submit requests for delegated certificates
  2. making sure that any request for a delegated certificate matches the intended "shape" in terms of delegated identities as well as any other certificate metadata, e.g., key length, x.509 extensions, etc.
  3. serving the certificate back to the NDC
  4. handling revocation of the delegation
  5. handling revocation of the certificate itself

The first part is covered by the NDC's ACME account, which the IdO administers. Its security relies on the correct handling of the associated key pair ๐Ÿ”‘ When a compromise of the private key is detected, the delegate MUST use the account deactivation procedures defined in Section 7.3.6 of [RFC8555]. Non-negotiable, periodt ๐Ÿ’…

The second part is covered by checking an NDC's certificate request against the intended CSR template. Shaping the CSR template correctly, picking the right CSR template to check against the presented CSR, and making sure the presented CSR matches the selected CSR template are all security relevant ๐Ÿงš

The third part builds on the trust relationship between NDC and IdO, which is responsible for correctly forwarding the certificate URL from the Order returned by the CA ๐Ÿฆ‹

The fourth part is about the IdO's ability to unilaterally remove the "delegation" object tied to the revoked identity. That blocks any further NDC requests for that identity ๐Ÿšซ Note that in more extreme circumstances, the IdO might decide to disable the NDC account, which blocks all further interaction.

The fifth part is covered by two different mechanisms, depending on the kind of certificate. For STAR, the IdO shall use the cancellation interface defined in Section 2.3 of [RFC8739]. For non-STAR, the certificate revocation interface defined in Section 7.6 of [RFC8555]) is used.

The ACME account tied to the delegation plays a crucial role in the overall security of the protocol ๐Ÿ‘‘ That means that, in delegation scenarios, the security requirements and verification for an ACME account may be more stringent than in base ACME deployments. The reason is that out-of-band configuration of the delegations an account is allowed to use (combined with account authentication) takes the place of the normal ACME authorization challenge procedures. So the IdO MUST ensure that each account is associated with the exact policies (via their matching "delegation" objects) that define which domain names can be delegated to the account and how. The IdO is expected to use out-of-band means to preregister each NDC to the corresponding account ๐Ÿซถ

7.3. New ACME Channels ๐Ÿ“ก

Using the model established in Section 10.1 of [RFC8555], we can break down the interactions of the basic delegation workflow, as shown in Figure 14. Picture time ๐ŸŽ€

   .-----. ACME Channel .--------.
   | NDC +------------->| IdO    |
   '--+--'              | server |
      |                 '--o-----'
      |                    |
      |                    |         ACME Channel
      |                    |  .------------>-------------.
      |                    |  |                          |
      |                 .--o--+--.                    .--+---.
      |                 | IdO    |                    |  CA  |
      |                 | client |                    '--+-+-'
      |                 '-----+--'                       | |
      |                       '-----------<--------------' |
      |                            Validation Channel      |
      '-------------------->-------------------------------'
                (subset of) ACME Channel [1]

   [1] Unauthenticated certificate fetch and non-STAR certificate
       revocation.

                  Figure 14: Delegation Channels Topology

The security considerations for the ACME Channel and Validation Channel from [RFC8555] apply verbatim to the IdO-CA leg. The same goes for the ACME Channel on the NDC-IdO leg. The ACME Channel between the NDC and CA is a bit different, since it's a subset of the ACME interface with two API endpoints: unauthenticated certificate retrieval and, potentially, non-STAR revocation via certificate private key. No specific security considerations apply to the former, but the privacy considerations in Section 6.3 of [RFC8739] do. For the latter, there's currently no way for an IdO to disable authorizing revocation based on certificate private keys. So, in theory, an NDC could use the revocation API directly with the CA, bypassing the IdO ๐Ÿ˜ฌ The NDC SHOULD NOT directly use the revocation interface exposed by the CA unless failing to do so would compromise the overall security. For example, that would be the case if the certificate private key is compromised and the IdO is not currently reachable.

All other security considerations from [RFC8555] and [RFC8739] apply as is to the delegation topology โœจ

7.4. Restricting CDNs to the Delegation Mechanism ๐Ÿ›ก๏ธ

When a website is delegated to a CDN, the CDN can in principle modify the website at will, e.g., create and remove pages. That means a malicious or breached CDN can pass the ACME (as well as common non-ACME) HTTPS-based validation challenges and generate a certificate for the site ๐Ÿ’€ This is true whether or not the CNAME mechanisms defined in the current document are used.

In some cases this is the desired behavior, because the domain holder trusts the CDN to have full control of the cryptographic credentials for the site. But this document assumes a scenario where the domain holder only wants to delegate restricted control, and wants to keep the ability to cancel the CDN's credentials at short notice ๐Ÿฆ‹

Here's a possible mitigation for when the IdO wants to make sure a rogue CDN can't issue unauthorized certificates:

  • The domain holder makes sure that the CDN cannot modify the DNS records for the domain. The domain holder should ensure it is the only entity authorized to modify the DNS zone. Typically, it establishes a CNAME resource record from a subdomain into a CDN-managed domain.
  • The domain holder uses a Certification Authority Authorization (CAA) record [RFC8659] to restrict certificate issuance for the domain to specific CAs that comply with ACME and are known to implement [RFC8657].
  • The domain holder uses the ACME-specific CAA mechanism [RFC8657] to restrict issuance to a specific CA account that is controlled by it, and MUST require dns-01 as the sole validation method.

We should note that the solution above may need tweaking depending on the exact capabilities and authorization flows the selected CA supports. Also, this mitigation may be bypassed if a malicious or misconfigured CA doesn't comply with CAA restrictions ๐Ÿ™ƒ


8. References ๐Ÿ“š

8.1. Normative References ๐Ÿ“š

Okay bestie, these are the normative references, which means the stuff you actually need to have read to get the spec. ๐Ÿ’…

8.2. Informative References ๐Ÿฆ‹

These ones are the extra-credit reading, the bonus content that gives you more context but isn't required to build the thing. ๐Ÿงš

Appendix A. CSR Template: CDDL โœจ

Here's the official CDDL definition of the CSR template [RFC8610], so this is the source of truth, no cap ๐Ÿ’– The CSR template MUST be a valid JSON document that is compliant with the syntax defined here.

Some constraints just can't be written in CDDL, so they're a separate vibe check. These MUST be validated by the recipient, including:

  • the value of each "subjectAltName" entry is compatible with its type and
  • the parameters in each "keyTypes" entry form an acceptable combination.
csr-template-schema = {
  keyTypes: [ + $keyType ]
  ? subject: non-empty<distinguishedName>
  extensions: extensions
}

non-empty<M> = (M) .and ({ + any => any })

mandatory-wildcard = "**"
optional-wildcard = "*"
wildcard = mandatory-wildcard / optional-wildcard

; regtext matches all text strings but "*" and "**"
regtext = text .regexp "([^\*].*)|([\*][^\*].*)|([\*][\*].+)"

regtext-or-wildcard = regtext / wildcard

distinguishedName = {
  ? country: regtext-or-wildcard
  ? stateOrProvince: regtext-or-wildcard
  ? locality: regtext-or-wildcard
  ? organization: regtext-or-wildcard
  ? organizationalUnit: regtext-or-wildcard
  ? emailAddress: regtext-or-wildcard
  ? commonName: regtext-or-wildcard
}

$keyType /= rsaKeyType
$keyType /= ecdsaKeyType

rsaKeyType = {
  PublicKeyType: "rsaEncryption" ; OID: 1.2.840.113549.1.1.1
  PublicKeyLength: rsaKeySize
  SignatureType: $rsaSignatureType
}

rsaKeySize = uint

; RSASSA-PKCS1-v1_5 with SHA-256
$rsaSignatureType /= "sha256WithRSAEncryption"
; RSASSA-PCKS1-v1_5 with SHA-384
$rsaSignatureType /= "sha384WithRSAEncryption"
; RSASSA-PCKS1-v1_5 with SHA-512
$rsaSignatureType /= "sha512WithRSAEncryption"
; RSASSA-PSS with SHA-256, MGF-1 with SHA-256, and a 32 byte salt
$rsaSignatureType /= "sha256WithRSAandMGF1"
; RSASSA-PSS with SHA-384, MGF-1 with SHA-384, and a 48 byte salt
$rsaSignatureType /= "sha384WithRSAandMGF1"
; RSASSA-PSS with SHA-512, MGF-1 with SHA-512, and a 64 byte salt
$rsaSignatureType /= "sha512WithRSAandMGF1"

ecdsaKeyType = {
  PublicKeyType: "id-ecPublicKey" ; OID: 1.2.840.10045.2.1
  namedCurve: $ecdsaCurve
  SignatureType: $ecdsaSignatureType
}

$ecdsaCurve /= "secp256r1" ; OID: 1.2.840.10045.3.1.7
$ecdsaCurve /= "secp384r1" ; OID: 1.3.132.0.34
$ecdsaCurve /= "secp521r1" ; OID: 1.3.132.0.3

$ecdsaSignatureType /= "ecdsa-with-SHA256" ; paired with secp256r1
$ecdsaSignatureType /= "ecdsa-with-SHA384" ; paired with secp384r1
$ecdsaSignatureType /= "ecdsa-with-SHA512" ; paired with secp521r1

subjectaltname = {
  ? DNS: [ + regtext-or-wildcard ]
  ? Email: [ + regtext ]
  ? URI: [ + regtext ]
  * $$subjectaltname-extension
}

extensions = {
  ? keyUsage: [ + keyUsageType ]
  ? extendedKeyUsage: [ + extendedKeyUsageType ]
  subjectAltName: non-empty<subjectaltname>
}

keyUsageType /= "digitalSignature"
keyUsageType /= "nonRepudiation"
keyUsageType /= "keyEncipherment"
keyUsageType /= "dataEncipherment"
keyUsageType /= "keyAgreement"
keyUsageType /= "keyCertSign"
keyUsageType /= "cRLSign"
keyUsageType /= "encipherOnly"
keyUsageType /= "decipherOnly"

extendedKeyUsageType /= "serverAuth"
extendedKeyUsageType /= "clientAuth"
extendedKeyUsageType /= "codeSigning"
extendedKeyUsageType /= "emailProtection"
extendedKeyUsageType /= "timeStamping"
extendedKeyUsageType /= "OCSPSigning"
extendedKeyUsageType /= oid

oid = text .regexp "([0-2])((\.0)|(\.[1-9][0-9]*))*"

Appendix B. CSR Template: JSON Schema ๐ŸŽ€

Okay so this appendix is a bonus, an alternative way to write down the CSR template as a JSON Schema ๐Ÿงš It's nonnormative, which means it's a helpful reference and not the official rulebook. The schema is written in draft 7 of JSON Schema, documented in [json-schema-07]. Heads up: later drafts of this (now-expired) version describe later versions of the JSON Schema syntax. At the time of writing, there isn't a stable reference for this syntax yet, so the team went with the draft version, which tool implementations support best ๐Ÿ’…

The same considerations about additional constraints checking that we covered in Appendix A apply here too, so don't skip that bit bestie ๐Ÿ™ˆ

{
  "title": "JSON Schema for the STAR Delegation CSR template",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "http://ietf.org/acme/drafts/star-delegation/csr-template",
  "$defs": {
    "distinguished-name": {
      "$id": "#distinguished-name",
      "type": "object",
      "minProperties": 1,
      "properties": {
        "country": {
          "type": "string"
        },
        "stateOrProvince": {
          "type": "string"
        },
        "locality": {
          "type": "string"
        },
        "organization": {
          "type": "string"
        },
        "organizationalUnit": {
          "type": "string"
        },
        "emailAddress": {
          "type": "string"
        },
        "commonName": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "rsaKeyType": {
      "$id": "#rsaKeyType",
      "type": "object",
      "properties": {
        "PublicKeyType": {
          "type": "string",
          "const": "rsaEncryption"
        },
        "PublicKeyLength": {
          "type": "integer"
        },
        "SignatureType": {
          "type": "string",
          "enum": [
            "sha256WithRSAEncryption",
            "sha384WithRSAEncryption",
            "sha512WithRSAEncryption",
            "sha256WithRSAandMGF1",
            "sha384WithRSAandMGF1",
            "sha512WithRSAandMGF1"
          ]
        }
      },
      "required": [
        "PublicKeyType",
        "PublicKeyLength",
        "SignatureType"
      ],
      "additionalProperties": false
    },
    "ecdsaKeyType": {
      "$id": "#ecdsaKeyType",
      "type": "object",
      "properties": {
        "PublicKeyType": {
          "type": "string",
          "const": "id-ecPublicKey"
        },
        "namedCurve": {
          "type": "string",
          "enum": [
            "secp256r1",
            "secp384r1",
            "secp521r1"
          ]
        },
        "SignatureType": {
          "type": "string",
          "enum": [
            "ecdsa-with-SHA256",
            "ecdsa-with-SHA384",
            "ecdsa-with-SHA512"
          ]
        }
      },
      "required": [
        "PublicKeyType",
        "namedCurve",
        "SignatureType"
      ],
      "additionalProperties": false
    }
  },
  "type": "object",
  "properties": {
    "keyTypes": {
      "type": "array",
      "minItems": 1,
      "items": {
        "anyOf": [
          {
            "$ref": "#rsaKeyType"
          },
          {
            "$ref": "#ecdsaKeyType"
          }
        ]
      }
    },
    "subject": {
      "$ref": "#distinguished-name"
    },
    "extensions": {
      "type": "object",
      "properties": {
        "keyUsage": {
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "string",
            "enum": [
              "digitalSignature",
              "nonRepudiation",
              "keyEncipherment",
              "dataEncipherment",
              "keyAgreement",
              "keyCertSign",
              "cRLSign",
              "encipherOnly",
              "decipherOnly"
            ]
          }
        },
        "extendedKeyUsage": {
          "type": "array",
          "minItems": 1,
          "items": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "serverAuth",
                  "clientAuth",
                  "codeSigning",
                  "emailProtection",
                  "timeStamping",
                  "OCSPSigning"
                ]
              },
              {
                "type": "string",
                "pattern": "^([0-2])((\\.0)|(\\.[1-9][0-9]*))*$",
                "description": "Used for OID values"
              }
            ]
          }
        },
        "subjectAltName": {
          "type": "object",
          "minProperties": 1,
          "properties": {
            "DNS": {
              "type": "array",
              "minItems": 1,
              "items": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": [
                      "*",
                      "**"
                    ]
                  },
                  {
                    "type": "string",
                    "format": "hostname"
                  }
                ]
              }
            },
            "Email": {
              "type": "array",
              "minItems": 1,
              "items": {
                "type": "string",
                "format": "email"
              }
            },
            "URI": {
              "type": "array",
              "minItems": 1,
              "items": {
                "type": "string",
                "format": "uri"
              }
            }
          },
          "additionalProperties": false
        }
      },
      "required": [
        "subjectAltName"
      ],
      "additionalProperties": false
    }
  },
  "required": [
    "extensions",
    "keyTypes"
  ],
  "additionalProperties": false
}

Acknowledgements ๐Ÿ’–

Huge thank you to the people who helped make this document shine โœจ with their review comments and design proposals: Richard Barnes, Carsten Bormann, Roman Danyliw, Lars Eggert, Frรฉdรฉric Fieau, Russ Housley, Ben Kaduk, Eric Kline, Sanjay Mishra, Francesca Palombini, Jon Peterson, Ryan Sleevi, Emile Stephan, and ร‰ric Vyncke. You all are literally the best ๐Ÿซถ

This work was partially supported by the European Commission under Horizon 2020 grant agreement no. 688421 Measurement and Architecture for a Middleboxed Internet (MAMI). Quick reminder that this support does not imply endorsement ๐ŸŒˆ


Authors' Addresses ๐Ÿฆ‹

Yaron Sheffer Intuit

Email: yaronf.ietf@gmail.com

Diego Lรณpez Telefonica I+D

Email: diego.r.lopez@telefonica.com

Antonio Agustรญn Pastor Perales Telefonica I+D

Email: antonio.pastorperales@telefonica.com

Thomas Fossati ARM

Email: thomas.fossati@arm.com

๐Ÿ“ฆ where this page comes from