| rfc9444v3.txt | rfc9444.txt | |||
|---|---|---|---|---|
| Internet Engineering Task Force (IETF) O. Friel | Internet Engineering Task Force (IETF) O. Friel | |||
| Request for Comments: 9444 R. Barnes | Request for Comments: 9444 R. Barnes | |||
| Category: Standards Track Cisco | Category: Standards Track Cisco | |||
| ISSN: 2070-1721 T. Hollebeek | ISSN: 2070-1721 T. Hollebeek | |||
| DigiCert | DigiCert | |||
| M. Richardson | M. Richardson | |||
| Sandelman Software Works | Sandelman Software Works | |||
| July 2023 | August 2023 | |||
| Automated Certificate Management Environment (ACME) for Subdomains | Automated Certificate Management Environment (ACME) for Subdomains | |||
| Abstract | Abstract | |||
| This document specifies how Automated Certificate Management | This document specifies how Automated Certificate Management | |||
| Environment (ACME) can be used by a client to obtain a certificate | Environment (ACME) can be used by a client to obtain a certificate | |||
| for a subdomain identifier from a certification authority. | for a subdomain identifier from a certification authority. | |||
| Additionally, this document specifies how a client can fulfill a | Additionally, this document specifies how a client can fulfill a | |||
| challenge against an ancestor domain but may not need to fulfill a | challenge against an ancestor domain but may not need to fulfill a | |||
| skipping to change at line 291 ¶ | skipping to change at line 291 ¶ | |||
| specified domain, as opposed to just requesting authorization for an | specified domain, as opposed to just requesting authorization for an | |||
| explicit domain identifier. Clients need a mechanism to do this in | explicit domain identifier. Clients need a mechanism to do this in | |||
| both newAuthz and newOrder requests. ACME servers need a mechanism | both newAuthz and newOrder requests. ACME servers need a mechanism | |||
| to indicate to clients that authorization objects are valid for all | to indicate to clients that authorization objects are valid for all | |||
| subdomains under the specified domain. These are described in this | subdomains under the specified domain. These are described in this | |||
| section. | section. | |||
| 4.1. Authorization Object | 4.1. Authorization Object | |||
| ACME ([RFC8555], Section 7.1.4) defines the authorization object. | ACME ([RFC8555], Section 7.1.4) defines the authorization object. | |||
| This document defines a new "subdomainAuthAllowed" field for the | This document defines a new subdomainAuthAllowed field for the | |||
| authorization object. When ACME server policy allows authorization | authorization object. When ACME server policy allows authorization | |||
| for subdomains subordinate to a domain, the server indicates this by | for subdomains subordinate to a domain, the server indicates this by | |||
| including the new "subdomainAuthAllowed" field in the authorization | including the new subdomainAuthAllowed field in the authorization | |||
| object for that domain identifier: | object for that domain identifier: | |||
| subdomainAuthAllowed (optional, boolean): If present, this field | subdomainAuthAllowed (optional, boolean): If present, this field | |||
| MUST be true for authorizations where ACME server policy allows | MUST be true for authorizations where ACME server policy allows | |||
| certificates to be issued for any subdomain subordinate to the | certificates to be issued for any subdomain subordinate to the | |||
| domain specified in the identifier field of the authorization | domain specified in the identifier field of the authorization | |||
| object. | object. | |||
| The following example shows an authorization object for the domain | The following example shows an authorization object for the domain | |||
| example.org, where the authorization covers the subdomains | example.org, where the authorization covers the subdomains | |||
| skipping to change at line 329 ¶ | skipping to change at line 329 ¶ | |||
| "type": "http-01", | "type": "http-01", | |||
| "status": "valid", | "status": "valid", | |||
| "token": "DGyRejmCefe7v4NfDGDKfA", | "token": "DGyRejmCefe7v4NfDGDKfA", | |||
| "validated": "2014-12-01T12:05:58.16Z" | "validated": "2014-12-01T12:05:58.16Z" | |||
| } | } | |||
| ], | ], | |||
| "subdomainAuthAllowed": true | "subdomainAuthAllowed": true | |||
| } | } | |||
| If the "subdomainAuthAllowed" field is not included, then the assumed | If the subdomainAuthAllowed field is not included, then the assumed | |||
| default value is false. | default value is false. | |||
| If ACME server policy allows issuance of certificates containing | If ACME server policy allows issuance of certificates containing | |||
| wildcard identifiers under that authorization object, then the server | wildcard identifiers under that authorization object, then the server | |||
| SHOULD include the "wildcard" field with a value of true, as per | SHOULD include the wildcard field with a value of true, as per | |||
| [RFC8555], Section 7.1.4. | [RFC8555], Section 7.1.4. | |||
| 4.2. Pre-authorization | 4.2. Pre-authorization | |||
| The basic ACME workflow has authorization objects created reactively | The basic ACME workflow has authorization objects created reactively | |||
| in response to a certificate order. ACME also allows for pre- | in response to a certificate order. ACME also allows for pre- | |||
| authorization, where clients obtain authorization for an identifier | authorization, where clients obtain authorization for an identifier | |||
| proactively, outside of the context of a specific issuance. With the | proactively, outside of the context of a specific issuance. With the | |||
| ACME pre-authorization flow, a client can pre-authorize for a domain | ACME pre-authorization flow, a client can pre-authorize for a domain | |||
| once and then issue multiple newOrder requests for certificates with | once and then issue multiple newOrder requests for certificates with | |||
| identifiers in the subdomains subordinate to that domain. | identifiers in the subdomains subordinate to that domain. | |||
| ACME ([RFC8555], Section 7.4.1) defines the identifier object for | ACME ([RFC8555], Section 7.4.1) defines the identifier object for | |||
| newAuthz requests. This document defines a new | newAuthz requests. This document defines a new subdomainAuthAllowed | |||
| "subdomainAuthAllowed" field for the identifier object: | field for the identifier object: | |||
| subdomainAuthAllowed (optional, boolean): An ACME client sets this | subdomainAuthAllowed (optional, boolean): An ACME client sets this | |||
| flag to indicate to the server that it is requesting an | flag to indicate to the server that it is requesting an | |||
| authorization for the subdomains subordinate to the specified | authorization for the subdomains subordinate to the specified | |||
| domain identifier value. | domain identifier value. | |||
| Clients include the new "subdomainAuthAllowed" field in the | Clients include the new subdomainAuthAllowed field in the identifier | |||
| identifier object of newAuthz requests to indicate that they are | object of newAuthz requests to indicate that they are requesting a | |||
| requesting a subdomain authorization. In the following example of a | subdomain authorization. In the following example of a newAuthz | |||
| newAuthz payload, the client is requesting pre-authorization for the | payload, the client is requesting pre-authorization for the | |||
| subdomains subordinate to example.org. | subdomains subordinate to example.org. | |||
| "payload": base64url({ | "payload": base64url({ | |||
| "identifier": { | "identifier": { | |||
| "type": "dns", | "type": "dns", | |||
| "value": "example.org", | "value": "example.org", | |||
| "subdomainAuthAllowed": true | "subdomainAuthAllowed": true | |||
| } | } | |||
| }) | }) | |||
| If the server is willing to allow a single authorization for the | If the server is willing to allow a single authorization for the | |||
| subdomains and there is not an existing authorization object for the | subdomains and there is not an existing authorization object for the | |||
| identifier, then it will create an authorization object and include | identifier, then it will create an authorization object and include | |||
| the "subdomainAuthAllowed" flag with a value of true. | the subdomainAuthAllowed flag with a value of true. | |||
| If the server policy does not allow creation of subdomain | If the server policy does not allow creation of subdomain | |||
| authorizations subordinate to that domain, the server can create an | authorizations subordinate to that domain, the server can create an | |||
| authorization object for the indicated identifier and MAY include the | authorization object for the indicated identifier and MAY include the | |||
| "subdomainAuthAllowed" flag with a value of false. If the server | subdomainAuthAllowed flag with a value of false. If the server | |||
| creates an authorization object and does not include the | creates an authorization object and does not include the | |||
| "subdomainAuthAllowed" flag, then the assumed value is false. | subdomainAuthAllowed flag, then the assumed value is false. | |||
| In both scenarios, handling of the pre-authorization follows the | In both scenarios, handling of the pre-authorization follows the | |||
| process documented in ACME [RFC8555], Section 7.4.1. | process documented in ACME [RFC8555], Section 7.4.1. | |||
| 4.3. New Orders | 4.3. New Orders | |||
| Clients need a mechanism to optionally indicate to servers whether or | Clients need a mechanism to optionally indicate to servers whether or | |||
| not they are authorized to fulfill challenges against an ancestor | not they are authorized to fulfill challenges against an ancestor | |||
| domain for a given identifier. For example, if a client places an | domain for a given identifier. For example, if a client places an | |||
| order for an identifier foo.bar.example.org and is authorized to | order for an identifier foo.bar.example.org and is authorized to | |||
| fulfill a challenge against the ancestor domains bar.example.org or | fulfill a challenge against the ancestor domains bar.example.org or | |||
| example.org, then the client needs a mechanism to indicate control | example.org, then the client needs a mechanism to indicate control | |||
| over the ancestor domains to the ACME server. | over the ancestor domains to the ACME server. | |||
| In order to accomplish this, this document defines a new | In order to accomplish this, this document defines a new | |||
| "ancestorDomain" field for the identifier that is included in order | ancestorDomain field for the identifier that is included in order | |||
| objects. | objects. | |||
| ancestorDomain (optional, string): This is an ancestor domain of the | ancestorDomain (optional, string): This is an ancestor domain of the | |||
| requested identifier. The client MUST be able to fulfill a | requested identifier. The client MUST be able to fulfill a | |||
| challenge against the ancestor domain. | challenge against the ancestor domain. | |||
| This field specifies an ancestor domain of the identifier that the | This field specifies an ancestor domain of the identifier that the | |||
| client has DNS control over and is capable of fulfilling challenges | client has DNS control over and is capable of fulfilling challenges | |||
| against. Based on server policy, the server can choose to issue a | against. Based on server policy, the server can choose to issue a | |||
| challenge against any ancestor domain of the identifier up to and | challenge against any ancestor domain of the identifier up to and | |||
| including the specified "ancestorDomain" and create a corresponding | including the specified ancestorDomain and create a corresponding | |||
| authorization object against the chosen identifier. | authorization object against the chosen identifier. | |||
| In the following example of a newOrder payload, the client requests a | In the following example of a newOrder payload, the client requests a | |||
| certificate for identifier foo.bar.example.org and indicates that it | certificate for identifier foo.bar.example.org and indicates that it | |||
| can fulfill a challenge against the ancestor domain bar.example.org. | can fulfill a challenge against the ancestor domain bar.example.org. | |||
| The server can then choose to issue a challenge against either | The server can then choose to issue a challenge against either | |||
| foo.bar.example.org or bar.example.org identifiers. | foo.bar.example.org or bar.example.org identifiers. | |||
| "payload": base64url({ | "payload": base64url({ | |||
| "identifiers": [ | "identifiers": [ | |||
| skipping to change at line 443 ¶ | skipping to change at line 443 ¶ | |||
| "identifiers": [ | "identifiers": [ | |||
| { "type": "dns", | { "type": "dns", | |||
| "value": "foo.bar.example.org", | "value": "foo.bar.example.org", | |||
| "ancestorDomain": "example.org" } | "ancestorDomain": "example.org" } | |||
| ], | ], | |||
| "notBefore": "2023-09-01T00:04:00+04:00", | "notBefore": "2023-09-01T00:04:00+04:00", | |||
| "notAfter": "2023-09-08T00:04:00+04:00" | "notAfter": "2023-09-08T00:04:00+04:00" | |||
| }) | }) | |||
| If the client is unable to fulfill authorizations against an ancestor | If the client is unable to fulfill authorizations against an ancestor | |||
| domain, the client should not include the "ancestorDomain" field. | domain, the client should not include the ancestorDomain field. | |||
| Server newOrder handling generally follows the process documented in | Server newOrder handling generally follows the process documented in | |||
| ACME (Section 7.4 of [RFC8555]). If the server is willing to allow | ACME (Section 7.4 of [RFC8555]). If the server is willing to allow | |||
| subdomain authorizations for the domain specified in | subdomain authorizations for the domain specified in ancestorDomain, | |||
| "ancestorDomain", then it creates an authorization object against | then it creates an authorization object against that ancestor domain | |||
| that ancestor domain and includes the "subdomainAuthAllowed" flag | and includes the subdomainAuthAllowed flag with a value of true. | |||
| with a value of true. | ||||
| If the server policy does not allow creation of subdomain | If the server policy does not allow creation of subdomain | |||
| authorizations against that ancestor domain, then it can create an | authorizations against that ancestor domain, then it can create an | |||
| authorization object for the indicated identifier value and SHOULD | authorization object for the indicated identifier value and SHOULD | |||
| NOT include the "subdomainAuthAllowed" flag. As the client requested | NOT include the subdomainAuthAllowed flag. As the client requested a | |||
| a subdomain authorization for the ancestor domain and not for the | subdomain authorization for the ancestor domain and not for the | |||
| indicated identifier, there is no need for the server to include the | indicated identifier, there is no need for the server to include the | |||
| "subdomainAuthAllowed" flag in the authorization object for the | subdomainAuthAllowed flag in the authorization object for the | |||
| indicated identifier. | indicated identifier. | |||
| 4.4. Directory Object Metadata | 4.4. Directory Object Metadata | |||
| This document defines a new "subdomainAuthAllowed" ACME directory | This document defines a new subdomainAuthAllowed ACME directory | |||
| metadata field. An ACME server can advertise support for | metadata field. An ACME server can advertise support for | |||
| authorization of subdomains by including the "subdomainAuthAllowed" | authorization of subdomains by including the subdomainAuthAllowed | |||
| boolean flag in its "ACME Directory Metadata Fields" registry: | boolean flag in its "ACME Directory Metadata Fields" registry: | |||
| subdomainAuthAllowed (optional, bool): Indicates if an ACME server | subdomainAuthAllowed (optional, bool): Indicates if an ACME server | |||
| supports authorization of subdomains. | supports authorization of subdomains. | |||
| If not specified, then the assumed default value is false. If an | If not specified, then the assumed default value is false. If an | |||
| ACME server supports authorization of subdomains, it can indicate | ACME server supports authorization of subdomains, it can indicate | |||
| this by including this field with a value of "true". | this by including this field with a value of "true". | |||
| 5. Illustrative Call Flow | 5. Illustrative Call Flow | |||
| skipping to change at line 557 ¶ | skipping to change at line 556 ¶ | |||
| | POST /certificate | | | | POST /certificate | | | |||
| |--------------------------->| | | |--------------------------->| | | |||
| | | | | | | | | |||
| | 200 OK | | | | 200 OK | | | |||
| | PEM SAN "sub2.example.org" | | | | PEM SAN "sub2.example.org" | | | |||
| |<---------------------------| | | |<---------------------------| | | |||
| * Step 1: Pre-authorization of ancestor domain. | * Step 1: Pre-authorization of ancestor domain. | |||
| The client sends a newAuthz request for the ancestor domain and | The client sends a newAuthz request for the ancestor domain and | |||
| includes the "subdomainAuthAllowed" flag in the identifier object. | includes the subdomainAuthAllowed flag in the identifier object. | |||
| POST /acme/new-authz HTTP/1.1 | POST /acme/new-authz HTTP/1.1 | |||
| Host: example.com | Host: example.com | |||
| Content-Type: application/jose+json | Content-Type: application/jose+json | |||
| { | { | |||
| "protected": base64url({ | "protected": base64url({ | |||
| "alg": "ES256", | "alg": "ES256", | |||
| "kid": "https://example.com/acme/acct/evOfKhNU60wg", | "kid": "https://example.com/acme/acct/evOfKhNU60wg", | |||
| "nonce": "uQpSjlRb4vQVCjVYAyyUWg", | "nonce": "uQpSjlRb4vQVCjVYAyyUWg", | |||
| skipping to change at line 581 ¶ | skipping to change at line 580 ¶ | |||
| "identifier": { | "identifier": { | |||
| "type": "dns", | "type": "dns", | |||
| "value": "example.org", | "value": "example.org", | |||
| "subdomainAuthAllowed": true | "subdomainAuthAllowed": true | |||
| } | } | |||
| }), | }), | |||
| "signature": "nuSDISbWG8mMgE7H...QyVUL68yzf3Zawps" | "signature": "nuSDISbWG8mMgE7H...QyVUL68yzf3Zawps" | |||
| } | } | |||
| The server creates and returns an authorization object for the | The server creates and returns an authorization object for the | |||
| identifier that includes the "subdomainAuthAllowed" flag. The | identifier that includes the subdomainAuthAllowed flag. The | |||
| object is initially in "pending" state. | object is initially in "pending" state. | |||
| { | { | |||
| "status": "pending", | "status": "pending", | |||
| "expires": "2023-09-01T14:09:07.99Z", | "expires": "2023-09-01T14:09:07.99Z", | |||
| "identifier": { | "identifier": { | |||
| "type": "dns", | "type": "dns", | |||
| "value": "example.org" | "value": "example.org" | |||
| }, | }, | |||
| skipping to change at line 629 ¶ | skipping to change at line 628 ¶ | |||
| the client's challenge immediately with a status of "processing" | the client's challenge immediately with a status of "processing" | |||
| and the client will then need to poll the authorization resource | and the client will then need to poll the authorization resource | |||
| to see when it is finalized. Refer to Section 7.5.1 of [RFC8555] | to see when it is finalized. Refer to Section 7.5.1 of [RFC8555] | |||
| for more details. | for more details. | |||
| * Step 2: The client places a newOrder for sub1.example.org. | * Step 2: The client places a newOrder for sub1.example.org. | |||
| The client sends a newOrder request to the server and includes the | The client sends a newOrder request to the server and includes the | |||
| subdomain identifier. Note that the identifier is a subdomain of | subdomain identifier. Note that the identifier is a subdomain of | |||
| the ancestor domain that has been pre-authorized in Step 1. The | the ancestor domain that has been pre-authorized in Step 1. The | |||
| client does not need to include the "subdomainAuthAllowed" field | client does not need to include the subdomainAuthAllowed field in | |||
| in the identifier object, as it has already pre-authorized the | the identifier object, as it has already pre-authorized the | |||
| ancestor domain. | ancestor domain. | |||
| POST /acme/new-order HTTP/1.1 | POST /acme/new-order HTTP/1.1 | |||
| Host: example.com | Host: example.com | |||
| Content-Type: application/jose+json | Content-Type: application/jose+json | |||
| { | { | |||
| "protected": base64url({ | "protected": base64url({ | |||
| "alg": "ES256", | "alg": "ES256", | |||
| "kid": "https://example.com/acme/acct/evOfKhNU60wg", | "kid": "https://example.com/acme/acct/evOfKhNU60wg", | |||
| skipping to change at line 690 ¶ | skipping to change at line 689 ¶ | |||
| The client can proceed to finalize the order by posting a CSR to | The client can proceed to finalize the order by posting a CSR to | |||
| the finalize resource. The client can then download the | the finalize resource. The client can then download the | |||
| certificate for sub1.example.org. | certificate for sub1.example.org. | |||
| * Step 3: The client places a newOrder for sub2.example.org. | * Step 3: The client places a newOrder for sub2.example.org. | |||
| The client sends a newOrder request to the server and includes the | The client sends a newOrder request to the server and includes the | |||
| subdomain identifier. Note that the identifier is a subdomain of | subdomain identifier. Note that the identifier is a subdomain of | |||
| the ancestor domain that has been pre-authorized in Step 1. The | the ancestor domain that has been pre-authorized in Step 1. The | |||
| client does not need to include the "subdomainAuthAllowed" field | client does not need to include the subdomainAuthAllowed field in | |||
| in the identifier object, as it has already pre-authorized the | the identifier object, as it has already pre-authorized the | |||
| ancestor domain. | ancestor domain. | |||
| POST /acme/new-order HTTP/1.1 | POST /acme/new-order HTTP/1.1 | |||
| Host: example.com | Host: example.com | |||
| Content-Type: application/jose+json | Content-Type: application/jose+json | |||
| { | { | |||
| "protected": base64url({ | "protected": base64url({ | |||
| "alg": "ES256", | "alg": "ES256", | |||
| "kid": "https://example.com/acme/acct/evOfKhNU60wg", | "kid": "https://example.com/acme/acct/evOfKhNU60wg", | |||
| End of changes. 22 change blocks. | ||||
| 32 lines changed or deleted | 31 lines changed or added | |||
This html diff was produced by rfcdiff 1.48. | ||||