RFC 9799
Automated Certificate Management Environment (ACME) Extensions for ".onion" Special-Use Domain Names
RFC 9799 ๐ Automated Certificate Management Environment (ACME) Extensions for ".onion" Special-Use Domain Names ๐ฆ
Okay bestie, so this one is an IETF doc by Q Misell, Ed. from AS207960 ๐ It came out in June 2025 as a Standards Track document, which means it's an actual Internet standard and not just a suggestion. Its ISSN is 2070-1721 โจ The header doesn't list any RFCs it obsoletes or updates, so it's coming in fresh ๐ธ
Abstract
This doc extends ACME so that certificates can be issued automatically for Tor Hidden Services, the ".onion" Special-Use Domain Names ๐ง
Status of This Memo
This is an Internet Standards Track document. ๐ฅ
It's a product of the Internet Engineering Task Force (IETF) and represents the consensus of the IETF community. It went through public review and was approved for publication by the Internet Engineering Steering Group (IESG). If you want more info on Internet Standards, check Section 2 of RFC 7841 ๐
Info about the doc's current status, any errata, and how to send feedback lives at https://www.rfc-editor.org/info/rfc9799 ๐
Copyright Notice
Copyright (c) 2025 IETF Trust and the persons identified as the document authors. All rights reserved. ๐ซถ
This doc is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info), as they stand on the publication date. Read them carefully, because they spell out your rights and restrictions for this doc. Any Code Components pulled out of this doc must include the Revised BSD License text described in Section 4.e of the Trust Legal Provisions, and they come with no warranty, as the Revised BSD License says ๐
Table of Contents
1. Introduction
1.1. Requirements Language
2. Identifier
3. Identifier Validation Challenges
3.1. Existing Challenges
3.1.1. Existing: "dns-01" Challenge
3.1.2. Existing: http-01 Challenge
3.1.3. Existing tls-alpn-01 Challenge
3.2. New onion-csr-01 Challenge
4. Client Authentication to Hidden Services
5. ACME over Hidden Services
6. Certification Authority Authorization (CAA)
6.1. Relevant Resource Record Set
6.2. When to Check CAA
6.3. Preventing Mis-Issuance by Unknown CAs
6.4. Alternative In-Band Presentation of CAA
6.4.1. ACME Servers Requiring In-Band CAA
6.4.2. Example In-Band CAA
7. IANA Considerations
7.1. Validation Methods
7.2. Error Types
7.3. Directory Metadata Fields
8. Security Considerations
8.1. Security of the onion-csr-01 Challenge
8.2. Use of the "dns" Identifier Type
8.2.1. http-01 Challenge
8.2.2. tls-alpn-01 Challenge
8.2.3. dns-01 Challenge
8.3. Key Authorization with onion-csr-01
8.4. Use of Tor for Domains That Are Not ".onion"
8.5. Redirects with http-01
8.6. Security of CAA Records
8.7. In-Band CAA
8.8. Access of the Tor Network
8.9. Anonymity of the ACME Client
8.9.1. Avoid Unnecessary Certificates
8.9.2. Obfuscate Subscriber Information
8.9.3. Separate ACME Account Keys
9. References
9.1. Normative References
9.2. Informative References
Appendix A. Discussion on the Use of the "dns" Identifier Type
Acknowledgements
Author's Address
1. Introduction โจ
The Tor network can host "Onion Services" [tor-spec], which are only reachable through Tor. These services use the ".onion" Special-Use Domain Name [RFC7686] to identify themselves. They can be used anywhere a regular domain name could be, but they aren't part of the DNS infrastructure ๐ง
ACME [RFC8555] defines challenges for proving control of DNS identifiers. A ".onion" name can look like a DNS name, but proving control of one takes special handling, so ACME needs extra work before it can be used for ".onion" names ๐
So this doc specifies challenges that can prove control of these Special-Use Domain Names, which lets ACME issue certificates for them. It also defines an alternative to the DNS Certification Authority Authorization (CAA) Resource Record [RFC8659] that works with ".onion" names ๐
1.1. Requirements Language
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. ๐
2. Identifier ๐
[RFC8555] defines the "dns" identifier type. This identifier type MUST be used when requesting a certificate for a ".onion" Special-Use Domain Name. The value of the identifier MUST be the textual representation defined in the "Special Hostnames in Tor - .onion" section of [tor-spec]. The value MAY include subdomain labels. Version 2 addresses [tor-rend-spec-v2] MUST NOT be used, since they're now considered insecure ๐ซ
Example identifiers (line breaks have been added for readability only):
{
"type": "dns",
"value": "bbcweb3hytmzhn5d532owbu6oqadra5z3ar726v
q5kgwwn6aucdccrad.onion"
}
{
"type": "dns",
"value": "www.bbcweb3hytmzhn5d532owbu6oqadra5z3ar726v
q5kgwwn6aucdccrad.onion"
}
3. Identifier Validation Challenges ๐
The CA/Browser Forum Baseline Requirements list the methods the CA industry accepts for validating ".onion" Special-Use Domain Names (see Appendix B.2 of [cabf-br]). This doc folds those methods into ACME challenges โจ
3.1. Existing Challenges
3.1.1. Existing: "dns-01" Challenge
The existing "dns-01" challenge MUST NOT be used to validate ".onion" Special-Use Domain Names, because those domains aren't part of the DNS ๐ โโ๏ธ
3.1.2. Existing: http-01 Challenge
The http-01 challenge, as defined in Section 8.3 of [RFC8555], MAY be used to validate a ".onion" Special-Use Domain Name, with the modifications in this doc, namely those described in Sections 4 and 6 ๐
The ACME server SHOULD follow redirects. Heads up that these redirects MAY point to services that aren't ".onion", and the server SHOULD honor them too. For example, clients might use redirects so the response can come from a centralized certificate management server. See Section 10.2 of [RFC8555] for the security considerations on why a server might not want to follow redirects ๐
3.1.3. Existing tls-alpn-01 Challenge
The tls-alpn-01 challenge, as defined in [RFC8737], MAY be used to validate a ".onion" Special-Use Domain Name, with the modifications in this doc, namely those described in Sections 4 and 6 ๐
3.2. New onion-csr-01 Challenge
Okay so the two ACME-defined methods that CA/BF allows, described in Sections 3.1.2 and 3.1.3 (http-01 and tls-alpn-01), do not allow wildcard certificates. That's a problem, because a ".onion" name can have subdomains just like any other DNS name, and a site operator would love one certificate covering all their virtual hosts ๐ญ This new validation method brings in the specially signed Certificate Signing Request (CSR) (defined in Appendix B.2.b of [cabf-br]) so ACME can issue wildcard certificates ๐ซถ
So this doc defines a new challenge called onion-csr-01, with these fields:
type(required, string): The stringonion-csr-01.nonce(required, string): A Base64-encoded nonce [RFC4648] with padding characters included. It MUST contain at least 64 bits of entropy. The ACME server MUST NOT accept a response generated with this nonce if the server generated the nonce more than 30 days earlier (as per Appendix B.2.b of [cabf-br]) โณauthKey(optional, object): The ACME server's Ed25519 public key, encoded as per [RFC8037]. This is further defined in Section 4 ๐
Here's what the challenge object looks like:
{
"type": "onion-csr-01",
"url": "https://acme-server.example.onion/acme/chall/bbc625c5",
"status": "pending",
"nonce": "bI6/MRqV4gw=",
"authKey": { ... }
}
An onion-csr-01 challenge MUST NOT be used to issue certificates for Special-Use Domain Names that are not ".onion" ๐จ
Clients prove they control the key for the ".onion" service by generating a Certificate Request (CSR) [RFC2986] with the following extra attributes, then signing it with the private key of the ".onion" Special-Use Domain Name ๐๏ธ
- A
caSigningNonceattribute containing the nonce from the challenge. This MUST be raw bytes, not the Base64-encoded value given in the challenge object. - An
applicantSigningNonceattribute containing a nonce the client generates. This MUST have at least 64 bits of entropy, and it MUST be raw bytes.
These extra attributes have the following format:
cabf OBJECT IDENTIFIER ::=
{ joint-iso-itu-t(2) international-organizations(23)
ca-browser-forum(140) }
cabf-caSigningNonce OBJECT IDENTIFIER ::= { cabf 41 }
caSigningNonce ATTRIBUTE ::= {
WITH SYNTAX OCTET STRING
EQUALITY MATCHING RULE octetStringMatch
SINGLE VALUE TRUE
ID { cabf-caSigningNonce }
}
cabf-applicantSigningNonce OBJECT IDENTIFIER ::= { cabf 42 }
applicantSigningNonce ATTRIBUTE ::= {
WITH SYNTAX OCTET STRING
EQUALITY MATCHING RULE octetStringMatch
SINGLE VALUE TRUE
ID { cabf-applicantSigningNonce }
}
The subject of the CSR doesn't need to mean anything, and CAs MUST NOT validate its contents. The public key in this CSR MUST be the public key corresponding to the ".onion" Special-Use Domain Name being validated. It MUST NOT be the same public key presented in the CSR used to finalize the order ๐ง
Clients respond with the following object to validate the challenge:
csr(required, string): The CSR in the base64url-encoded version of the DER format. (Note: because this field uses base64url and has no headers, it's different from Privacy Enhanced Mail (PEM) ๐ธ)
Here's what the response looks like:
POST /acme/chall/bbc625c5
Host: acme-server.example.onion
Content-Type: application/jose+json
{
"protected": base64url({
"alg": "ES256",
"kid":
"https://acme-server.example.onion/acme/acct/evOfKhNU60wg",
"nonce": "UQI1PoRi5OuXzxuX7V7wL0",
"url": "https://acme-server.example.onion/acme/chall/bbc625c5"
}),
"payload": base64url({
"csr": "MIIBPTCBxAIBADBFMQ...FS6aKdZeGsysoCo4H9P"
}),
"signature": "Q1bURgJoEslbD1c5...3pYdSMLio57mQNN4"
}
When the server gets the CSR, it checks it in this order:
- The CSR is a well formatted PKCS#10 request.
- The public key in the CSR corresponds to the ".onion" Special-Use Domain Name being validated.
- The signature over the CSR validates with the ".onion" Special-Use Domain Name public key.
- The
caSigningNonceattribute is present and its contents match the nonce given to the client. - The
applicantSigningNonceattribute is present and contains at least 64 bits of entropy.
If all of the above succeed, then validation succeeds. Otherwise, it has failed โ โ
4. Client Authentication to Hidden Services โจ
okay so some Hidden Services are like "not everyone gets to see me" ๐ , and they encrypt their Hidden Service Descriptor with the keys of the clients who are allowed in. ๐ The problem is that if the CA can't signal which key it's going to connect with, those services can't get a certificate with http-01 or tls-alpn-01, and they can't enforce CAA with any validation method either. ๐ญ
So to fix that, the challenge object gets one extra field ๐. It lets the ACME server advertise the Ed25519 public key it's going to use (see the "Authentication during the introduction phase" section of [tor-spec]) to authenticate itself when it retrieves the Hidden Service Descriptor.
authKey(optional, object): The ACME server's Ed25519 public key, encoded as per [RFC8037].
ACME servers MUST NOT use the same public key with multiple Hidden Services. ๐ โโ๏ธ They MAY reuse public keys to re-validate the same Hidden Service though, so that's giving flexibility ๐ฆ.
There's no way to tell the CA "hey, client auth is needed here" ๐. Instead, the ACME server MUST attempt to calculate its CLIENT-ID (see the "Client behavior" section of [tor-spec]). If no auth-client line in the First Layer Hidden Service Descriptor matches that computed client-id, then the server MUST assume the Hidden Service doesn't require client authentication and carry on accordingly. ๐โโ๏ธ
Now the tricky bit ๐ฅน. If the Ed25519 public key is new to the client, the client has to re-sign and republish its Hidden Service Descriptor. The server MUST wait some (indeterminate) amount of time for the new descriptor to propagate to the Tor Hidden Service directory servers before it responds to the challenge. This should take no more than a few minutes โณ. This specification doesn't pin down a fixed time, since changes to how the Tor network operates could change propagation time later on. ACME servers MUST NOT expire challenges before there's a reasonable window for the new descriptor to get published ๐ซถ. It is RECOMMENDED that the server allow at least 30 minutes, though honestly it's totally up to the operator's preference ๐.
5. ACME over Hidden Services ๐ง
A CA that offers certificates for ".onion" Special-Use Domain Names SHOULD make its ACME server available as a Tor Hidden Service ๐ธ. ACME clients SHOULD also support connecting to ACME servers over Tor, whether or not they support onion-csr-01 ๐ซ . Why? Because the existing http-01 and tls-alpn-01 implementations could already be used to get certificates for ".onion" Special-Use Domain Names, so it's already kind of possible ๐.
6. Certification Authority Authorization (CAA) ๐ก๏ธ
okay so ".onion" Special-Use Domain Names aren't part of the DNS ๐. That means we need a variation on CAA [RFC8659] if we want to put restrictions on certificate issuance.
To do that, a new field is added to the Second Layer Hidden Service Descriptor (see the "Second layer plaintext format" section of [tor-spec]). It has the following format, written with the notation from the "netdoc document meta-format" section of [tor-spec]:
"caa" SP flags SP tag SP value NL
[Any number of times]
This presentation format is only there so readers and implementors can follow along ๐ค. The canonical version is still the one defined in Section 4.1.1 of [RFC8659], or whatever future updates to it come out.
The contents of "flags", "tag", and "value" follow Section 4.1.1 of [RFC8659]. Multiple CAA records MAY be present, just like in the DNS ๐. CAA records in a Hidden Service Descriptor get treated by CAs the same way they'd be treated if they had been in the DNS for the ".onion" Special-Use Domain Name โจ.
A Hidden Service's Second Layer Descriptor using CAA could look something like this (line breaks were added so it's easier to read ๐):
create2-formats 2
single-onion-service
caa 128 issue "acmeforonions.example;validationmethods=onion-csr-01"
caa 0 iodef "mailto:security@example.com"
introduction-point AwAGsAk5nSMpAhRqhMHbTFCTSlfhP8f5PqUhe6DatgMgk7kSL3
KHCZUZ3C6tXDeRfM9SyNY0DlgbF8q+QSaGKCs=
...
6.1. Relevant Resource Record Set ๐ท
Here's the thing: ".onion" Special-Use Domain Names can't delegate subdomains the way the DNS can ๐ โโ๏ธ. So there's no need to search up the DNS tree for a relevant CAA record set, and honestly there's no method for it anyway ๐. It's also impossible to check CAA records on the "onion" Special-Use Top-Level Domain (TLD), since that thing doesn't exist in any form except as described in [RFC7686] ๐. So implementors MUST NOT look there either ๐ซ.
Instead, every subdomain under a ".onion" Special-Use Domain Name shares the same CAA record set ๐ . All of these share a CAA record set with "a.onion":
b.a.onionc.a.onione.d.a.onion
but these don't:
b.c.onionc.d.onione.c.d.oniona.b.onion
6.2. When to Check CAA ๐ฐ๏ธ
If the Hidden Service has client authentication turned on, then the ACME server can't decrypt the Second Layer Hidden Service Descriptor to read the CAA records until the ACME server's public key has been added to the First Layer Hidden Service Descriptor ๐ค. So an ACME server MUST wait until the client responds to an authorization, and it treats that response as the sign that the public key has been added and that it can now decrypt the Second Layer Hidden Service Descriptor ๐.
6.3. Preventing Mis-Issuance by Unknown CAs ๐จ
In the case of a Hidden Service that requires client authentication, the CA can't read the hidden service's CAA records without the Hidden Service trusting an ACME server's public key ๐. That's because the CAA records live in the Second Layer Hidden Service Descriptor. So we need a way to signal that CAA records are present, without revealing what they say, since in some situations that would leak info about the Hidden Service operator ๐ค.
So a new field is added to the First Layer Hidden Service Descriptor (see the "First layer plaintext format" section of [tor-spec]). It has the following format, written with the notation from the "netdoc document meta-format" section of [tor-spec]:
"caa-critical" NL
[At most once]
If an ACME server sees this flag, it MUST NOT proceed with issuance until it can decrypt and parse the CAA records from the Second Layer Hidden Service Descriptor ๐.
6.4. Alternative In-Band Presentation of CAA ๐จ
Some ACME servers might not be willing to run the infrastructure needed to fetch, decode, and verify Tor Hidden Service Descriptors just to check CAA records ๐ฉ. So there's a method defined for signaling CAA policies in-band over ACME instead ๐.
If a Hidden Service does use this method to give CAA records to an ACME server, it SHOULD still publish CAA records if its CAA record set includes "iodef", "contactemail", or "contactphone", so that this info stays publicly accessible ๐ข. On top of that, a Hidden Service operator MAY not wish to publish a CAA record set in its Hidden Service Descriptor, to avoid revealing info about the service operator ๐.
If an ACME server receives a validly signed CAA record set in the finalize request, it MAY proceed with issuance based only on the client-provided CAA record set, without checking the CAA set in the Hidden Service ๐ซ. Or, alternatively, an ACME server MAY ignore the client-provided record set and fetch the record set from the Hidden Service Descriptor. Either way, the server MAY fetch the record set from the Hidden Service Descriptor. If an ACME server receives a validly signed CAA record set in the finalize request, it doesn't need to check the CAA set in the Hidden Service Descriptor, and it can proceed with issuance based only on the client-provided CAA record set ๐. An ACME server MAY ignore the client-provided record set and is free to always fetch the record set from the Hidden Service Descriptor ๐ง .
A new field is defined in the ACME finalize endpoint to hold the Hidden Service's CAA record set for each ".onion" Special-Use Domain Name in the order ๐.
onionCAA(optional, dictionary of objects): The CAA record set for each ".onion" Special-Use Domain Name in the order. The key is the ".onion" Special-Use Domain Name, and the value is an object with the fields described below.
The contents of the values of the onionCAA object are as follows:
caa(required, string or null): The CAA record set as a string, encoded in the same way as if it were included in the Hidden Service Descriptor. If the Hidden Service does not have a CAA record set, then this MUST be null.expiry(required, integer): The Unix timestamp at which this CAA record set will expire. This SHOULD NOT be more than 8 hours in the future. ACME servers MUST process this as at least a 64-bit integer to make sure things keep working beyond 2038 ๐.signature(required, string): The Ed25519 signature of the CAA record set, made using the private key that corresponds to the ".onion" Special-Use Domain Name, encoded using base64url. The signature is defined below ๐๏ธ.
The data the signature is calculated over is the concatenation of the following, encoded in UTF-8 [RFC3629]:
"onion-caa|" || expiry || "|" || caa
Here "|" is the ASCII character 0x7C, and expiry is the expiry field written as a decimal string with no leading zeros. If the caa field is null, it's represented as an empty string in the signature calculation ๐งฎ.
6.4.1. ACME Servers Requiring In-Band CAA ๐ง
If an ACME server doesn't support fetching a service's CAA record set from its Hidden Service Descriptor, and the ACME client doesn't provide an "onionCAA" object in its finalize request, then the ACME server MUST respond with an "onionCAARequired" error to say so ๐ฌ.
To let the server signal that it supports fetching CAA record sets over Tor, a new field is defined in the directory "meta" object ๐.
inBandOnionCAARequired(optional, boolean): If true, the ACME server requires the client to provide the CAA record set in the finalize request. If false or absent, the ACME server does not require the client to provide the CAA record set in this manner.
A directory from a CA like this could look something like the following ๐ญ:
HTTP/1.1 200 OK
Content-Type: application/json
{
"newNonce": "https://acme-server.example.onion/acme/new-nonce",
"newAccount": "https://acme-server.example.onion/acme/new-account",
"newOrder": "https://acme-server.example.onion/acme/new-order",
"revokeCert": "https://acme-server.example.onion/acme/revoke-cert",
"keyChange": "https://acme-server.example.onion/acme/key-change",
"meta": {
"termsOfService":
"https://acme-server.example.onion/acme/terms/2023-10-13",
"website": "https://acmeforonions.example/",
"caaIdentities": ["acmeforonions.example"],
"inBandOnionCAARequired": true
}
}
6.4.2. Example In-Band CAA โจ
Okay bestie, here's an example CAA record set for 5anebu2glyc235wbbop3m2ukzlaptpkq333vdtdvcjpigyb7x2i2m2qd.onion (I added some line breaks so it's easier to read ๐
):
caa 128 issue "acmeforonions.example;
validationmethods=onion-csr-01"
caa 0 iodef "mailto:example@example.com"
Next up is what gets sent to the ACME server's finalize endpoint ๐ฎ (line breaks added again for readability):
POST /acme/order/TOlocE8rfgo/finalize
Host: acme-server.example.onion
Content-Type: application/jose+json
{
"protected": base64url({
"alg": "ES256",
"kid":
"https://acme-server.example.onion/acme/acct/evOfKhNU60wg",
"nonce": "MSF2j2nawWHPxxkE3ZJtKQ",
"url": "https://acme-server.example.onion/acme/order/
TOlocE8rfgo/finalize"
}),
"payload": base64url({
"csr": "MIIBPTCBxAIBADBFMQ...FS6aKdZeGsysoCo4H9P",
"onionCAA": {
"5anebu2glyc235wbbop3m2ukzlaptpkq333vdtdvcjpi
gyb7x2i2m2qd.onion": {
"caa": "caa 128 issue \"acmeforonions.example;
validationmethods=onion-csr-01\"\n
caa 0 iodef \"mailto:example@example.com\"",
"expiry": 1697210719,
"signature": "u_iP6JZ4JZBrzQUKH6lSrWejjRfeQmkTuehc0_FaaTNP
AV0RVxpUz9r44DRdy6kgy0ofnx18KIhMrP7N1wpxAA=="
}
}
}),
"signature": "uOrUfIIk5RyQ...nw62Ay1cl6AB"
}
7. IANA Considerations ๐
7.1. Validation Methods
One new entry has been added to the "ACME Validation Methods" registry that was defined in Section 9.7.8 of [RFC8555] (https://www.iana.org/assignments/acme). Slay ๐
+==============+=================+======+===========+
| Label | Identifier Type | ACME | Reference |
+==============+=================+======+===========+
| onion-csr-01 | dns | Y | RFC 9799 |
+--------------+-----------------+------+-----------+
Table 1: onion-csr-01 Validation Method
7.2. Error Types
One new entry has been added to the "ACME Error Types" registry that was defined in Section 9.7.4 of [RFC8555] (https://www.iana.org/assignments/acme). Another one, iykyk ๐
+==================+===============================+===========+
| Type | Description | Reference |
+==================+===============================+===========+
| onionCAARequired | The CA only supports checking | RFC 9799 |
| | the CAA for Hidden Services | |
| | in-band, but the client has | |
| | not provided an in-band CAA | |
+------------------+-------------------------------+-----------+
Table 2: onionCAARequired Error Type
7.3. Directory Metadata Fields
One new entry has been added to the "ACME Directory Metadata Fields" registry that was defined in Section 9.7.6 of [RFC8555] (https://www.iana.org/assignments/acme). ๐ธ
+==================+============+===========+
| Field name | Field type | Reference |
+==================+============+===========+
| onionCAARequired | boolean | RFC 9799 |
+------------------+------------+-----------+
Table 3: onionCAARequired Metadata Field
8. Security Considerations ๐
Okay this section is serious, so let's go ๐ซถ
8.1. Security of the onion-csr-01 Challenge
The security considerations of [cabf-br] apply to issuance using the Certificate Request method. Read those too, no skipping ๐ญ
8.2. Use of the "dns" Identifier Type
Reusing the "dns" identifier type for a Special-Use Domain Name that isn't actually in the DNS infrastructure raises questions about whether it's suitable. The reasons for going this route in the first place are covered in Appendix A. It is felt that there is little security concern in reusing the "dns" identifier type when it comes to mis-issuance by CAs that aren't aware of ".onion" Special-Use Domain Names, since those CAs wouldn't be able to resolve the identifier in the DNS. Lowkey clever, ngl โจ
8.2.1. http-01 Challenge
If a CA doesn't know about this document, it would follow the procedure in Section 8.3 of [RFC8555], which says the CA should "Dereference the URL using an HTTP GET request". Since ".onion" Special-Use Domain Names need special handling to dereference, this dereferencing will fail, and issuance gets disallowed ๐ซ
8.2.2. tls-alpn-01 Challenge
If a CA doesn't know about this document, it would follow the procedure in Section 3 of [RFC8737], which says the CA "resolves the domain name being validated and chooses one of the IP addresses returned for validation". Because ".onion" Special-Use Domain Names can't be resolved to IP addresses, this dereferencing will fail, and issuance gets disallowed ๐ซ
8.2.3. dns-01 Challenge
If a CA doesn't know about this document, it would follow the procedure in Section 8.4 of [RFC8555], which says the CA should "query for TXT records for the validation domain name". Since ".onion" Special-Use Domain Names aren't present in the DNS infrastructure, this query will fail, and issuance gets disallowed ๐ซ
8.3. Key Authorization with onion-csr-01
The onion-csr-01 challenge does not make use of the key authorization string defined in Section 8.1 of [RFC8555]. This does not weaken the integrity of authorizations.
The key authorization exists so that, even if an attacker is watching the validation channel and can see the correct validation response, they can't compromise the integrity of authorizations, because the response can only be used with the account key it was generated for. The validation channel for this challenge is ACME itself, and ACME already requires that the request be signed by the account, so the key authorization isn't necessary here ๐ง
8.4. Use of Tor for Domains That Are Not ".onion"
An ACME server MUST NOT utilize Tor for the validation of domains that are not ".onion", due to the risk of exit hijacking [spoiled-onions]. Big no-no ๐ โโ๏ธ
8.5. Redirects with http-01
A site MAY redirect to another site when completing validation using the http-01 challenge. This redirect MAY be to either another ".onion" Special-Use Domain Name or a domain in the public DNS. A site operator MUST consider the privacy implications of redirecting to a site that is not ".onion". Namely, the ACME server operator will then be able to learn information about the site they were redirected to that they would not have if accessed via a ".onion" Special-Use Domain Name, such as its IP address. If the site redirected to is on the same or an adjacent host to the ".onion" Special-Use Domain Name, this reveals information that the "Tor Rendezvous Specification - Version 3" section of [tor-spec] was otherwise designed to protect ๐
If an ACME server receives a redirect to a domain in the public DNS, it MUST NOT utilize Tor to make a connection to it due to the risk of exit hijacking.
8.6. Security of CAA Records
The Second Layer Hidden Service Descriptor is signed, encrypted, and encoded using a Message Authentication Code (MAC), in a way that only a party with access to the secret key of the Hidden Service could manipulate what is published there. For more information about this process, see the "Hidden service descriptors: encryption format" section of [tor-spec]. ๐
8.7. In-Band CAA
Tor directory servers are inherently untrusted entities. So there's no difference in the security model between accepting CAA records directly from the ACME client and fetching them over Tor, because the CAA records are verified using the same hidden service key in either case โ
8.8. Access of the Tor Network
The ACME server MUST make its own connection to the Hidden Service via the Tor network, and it MUST NOT outsource this to a third-party service, such as Tor2Web. No outsourcing the Tor part, bestie ๐ง
8.9. Anonymity of the ACME Client
ACME clients requesting certificates for ".onion" Special-Use Domain Names that aren't over the Tor network can accidentally expose the existence of a Hidden Service on the host requesting certificates to people who weren't meant to know. This is true even when features such as Encrypted ClientHello (ECH) [tls-esni] are used, because the IP addresses of ACME servers are generally well-known, static, and not used for any other purpose ๐ฌ
ACME clients SHOULD connect to ACME servers over the Tor network to alleviate this, preferring a Hidden Service endpoint if the CA provides one.
If an ACME client requests a publicly trusted WebPKI certificate, it will expose the existence of the Hidden Service publicly, because it gets included in Certificate Transparency logs [RFC9162]. Hidden Service operators MUST consider the privacy implications of this before requesting WebPKI certificates. ACME client developers SHOULD warn users about the risks of CT-logged certificates for Hidden Services. Main character energy means not getting doxxed by your own cert ๐
8.9.1. Avoid Unnecessary Certificates
Not every service needs a publicly trusted WebPKI certificate. For internal or non-public services, operators SHOULD consider using self-signed or privately trusted certificates that aren't logged to certificate transparency. ๐คซ
8.9.2. Obfuscate Subscriber Information
When an ACME client registers with an ACME server, it SHOULD provide minimal or obfuscated subscriber details to the CA, such as a pseudonymous email address, if at all possible. Keep it anonymous, periodt ๐ญ
8.9.3. Separate ACME Account Keys
If a Hidden Service operator doesn't want their different Hidden Services to be correlated by a CA, they MUST use separate ACME account keys for each Hidden Service. One key per service, no mixing ๐ฆ
9. References ๐
9.1. Normative References
Okay bestie, these are the references you absolutely cannot skip ๐๐
- [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997,
https://www.rfc-editor.org/info/rfc2119. ๐ - [RFC2986] Nystrom, M. and B. Kaliski, "PKCS #10: Certification Request Syntax Specification Version 1.7", RFC 2986, DOI 10.17487/RFC2986, November 2000,
https://www.rfc-editor.org/info/rfc2986. ๐ฆ - [RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006,
https://www.rfc-editor.org/info/rfc4648. ๐ - [RFC7686] Appelbaum, J. and A. Muffett, "The ".onion" Special-Use Domain Name", RFC 7686, DOI 10.17487/RFC7686, October 2015,
https://www.rfc-editor.org/info/rfc7686. ๐ง - [RFC8037] Liusvaara, I., "CFRG Elliptic Curve Diffie-Hellman (ECDH) and Signatures in JSON Object Signing and Encryption (JOSE)", RFC 8037, DOI 10.17487/RFC8037, January 2017,
https://www.rfc-editor.org/info/rfc8037. ๐ธ - [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017,
https://www.rfc-editor.org/info/rfc8174. ๐ - [RFC8555] Barnes, R., Hoffman-Andrews, J., McCarney, D., and J. Kasten, "Automatic Certificate Management Environment (ACME)", RFC 8555, DOI 10.17487/RFC8555, March 2019,
https://www.rfc-editor.org/info/rfc8555. ๐ - [RFC8659] Hallam-Baker, P., Stradling, R., and J. Hoffman-Andrews, "DNS Certification Authority Authorization (CAA) Resource Record", RFC 8659, DOI 10.17487/RFC8659, November 2019,
https://www.rfc-editor.org/info/rfc8659. โจ - [RFC8737] Shoemaker, R.B., "Automated Certificate Management Environment (ACME) TLS Application-Layer Protocol Negotiation (ALPN) Challenge Extension", RFC 8737, DOI 10.17487/RFC8737, February 2020,
https://www.rfc-editor.org/info/rfc8737. ๐ซง - [RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO 10646", STD 63, RFC 3629, DOI 10.17487/RFC3629, November 2003,
https://www.rfc-editor.org/info/rfc3629. ๐ - [tor-spec] The Tor Project, "Tor Specifications",
https://spec.torproject.org. ๐ง - [tor-rend-spec-v2] The Tor Project, "Tor Rendezvous Specification - Version 2", commit 2437d19c,
https://spec.torproject.org/rend-spec-v2. ๐ง - [cabf-br] CA/Browser Forum, "Baseline Requirements for the Issuance and Management of Publicly-Trusted TLS Server Certificates", Version 2.0.6, 5 August 2024,
https://cabforum.org/working-groups/server/baseline-requirements/documents/CA-Browser-Forum-TLS-BR-2.0.6.pdf. ๐
9.2. Informative References
Now the extra-credit reading, the stuff that's good to know but not strictly required ๐ค
- [onion-services-setup] The Tor Project, "Set Up Your Onion Service",
https://community.torproject.org/onion-services/setup/. ๐ง - [spoiled-onions] Winter, P., Kรถwer, R., Mulazzani, M., Huber, M., Schrittwieser, S., Lindskog, S., and E. Weippl, "Spoiled Onions: Exposing Malicious Tor Exit Relays", Privacy Enhancing Technologies (PETS 2014), Lecture Notes in Computer Science, vol. 8555, pp. 304-331, DOI 10.1007/978-3-319-08506-7_16, 2014,
https://doi.org/10.1007/978-3-319-08506-7_16. ๐ - [tls-esni] Rescorla, E., Oku, K., Sullivan, N., and C. A. Wood, "TLS Encrypted Client Hello", Work in Progress, Internet-Draft, draft-ietf-tls-esni-25, 14 June 2025,
https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-25. ๐ - [RFC9162] Laurie, B., Messeri, E., and R. Stradling, "Certificate Transparency Version 2.0", RFC 9162, DOI 10.17487/RFC9162, December 2021,
https://www.rfc-editor.org/info/rfc9162. ๐ช
Appendix A. Discussion on the Use of the "dns" Identifier Type โจ
Okay so you might be wondering why ACME uses the "dns" identifier type for ".onion" names instead of making a brand new identifier type just for them. Honestly, same, at first glance ๐ Like, ".onion" Special-Use Domain Names aren't part of the DNS infrastructure at all, so why would they use the "dns" type?? It's giving confusing, but there's a reason, and it's lowkey genius.
Here's the tea. [cabf-br] (specifically Appendix B.2.a.ii) defines the http-01 or tls-alpn-01 validation methods, and this document allows using them too, with some considerations ๐ . Picture a web server sitting behind a Tor-terminating proxy, which is the setup the Tor Project suggests in [onion-services-setup]. From the ACME tooling's point of view, nothing special is happening. It just gets an incoming TCP connection like it always does, the only difference being that the connection comes from the Tor-terminating proxy. So the existing tools are basically blind to the fact that a ".onion" Special-Use Domain Name is in play ๐ฆ
For example, Certbot can drop the ACME challenge response file into the webroot of an NGINX web server, and neither Certbot nor NGINX needs any changes to know about special ".onion" handling. Main character energy for the existing software, no notes ๐
Now, does this raise some security questions for existing implementations? It does, ngl ๐ฌ. But the authors think it's of little concern, as per Section 8.2. Iykyk.
Acknowledgements ๐ซถ
Huge thanks to the Open Technology Fund for funding the work that went into this document ๐ธ
The authors also wanted to thank these lovely people for their input on this document:
- Iain Learmonth ๐
- Jan-Frederik Rieckers ๐
Author's Address ๐
Q Misell (editor)
AS207960 Cyfyngedig
13 Pen-y-lan Terrace
Caerdydd
CF23 9EU
United Kingdom
Email: q@as207960.net, q@magicalcodewit.ch
URI: https://magicalcodewit.ch
๐ฆ where this page comes from
- ietf: rfc9799 2025-06
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms