RFC 9799

Automated Certificate Management Environment (ACME) Extensions for ".onion" Special-Use Domain Names

๐Ÿ“… published June 2025, from ietf

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 (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 string onion-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 caSigningNonce attribute containing the nonce from the challenge. This MUST be raw bytes, not the Base64-encoded value given in the challenge object.
  • An applicantSigningNonce attribute 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:

  1. The CSR is a well formatted PKCS#10 request.
  2. The public key in the CSR corresponds to the ".onion" Special-Use Domain Name being validated.
  3. The signature over the CSR validates with the ".onion" Special-Use Domain Name public key.
  4. The caSigningNonce attribute is present and its contents match the nonce given to the client.
  5. The applicantSigningNonce attribute 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.onion
  • c.a.onion
  • e.d.a.onion

but these don't:

  • b.c.onion
  • c.d.onion
  • e.c.d.onion
  • a.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 ๐Ÿ“š๐Ÿ’…

9.2. Informative References

Now the extra-credit reading, the stuff that's good to know but not strictly required ๐Ÿค“


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