Hi Aaron and Q,

On the point that RFC 8555 allows multiple required challenges for an 
authorization object:

Section 7.1.6<https://datatracker.ietf.org/doc/html/rfc8555#section-7.1.6> says:

   Authorization objects are created in the "pending" state.  If one of
   the challenges listed in the authorization transitions to the "valid"
   state, then the authorization also changes to the "valid" state.

Although it is lacking a “MUST” in the last line, I think client implementers 
who followed the RFC would expect the authorization to become valid after 
completing one challenge. Allowing multiple required challenges per 
authorization would break the quoted text and won’t be backward-compatible.

Thank you,
Ruochen

From: Aaron Gable <[email protected]>
Sent: Tuesday, 22 July, 2025 20:43
To: IETF ACME <[email protected]>
Subject: [Acme] Review of draft-liu-acme-rats-01

In the wake of the rushed IETF 123 meeting, I wanted to start a conversation 
here about the ACME RATS draft. I have a few thoughts, some large, some small, 
presented below in no particular order.

---

The presentation said that the design team had come to the conclusion that the 
attestation evidence should be presented in the newOrder request, rather than 
as a traditional challenge. This design decision does not seem to be reflected 
in the current 
draft<https://www.ietf.org/archive/id/draft-liu-acme-rats-01.html>. nor in the 
main branch of the github 
repo<https://github.com/liuchunchi/draft-liu-acme-rats/blob/main/draft-liu-acme-rats.md>.
 Therefore I feel somewhat underprepared to discuss this design proposal in 
detail.

That said, my gut reaction is that it is a bad idea. The beauty of ACME, in my 
opinion, is that it has an infinitely extensible collection of identifier 
types, and an infinitely extensible collection of challenges to validate those 
identifiers. If the thing that is semantically happening is that the server is 
validating a claim that the client is making, that should almost certainly take 
place as part of the existing extensible identifier/authorization/challenge 
mechanism, not get bolted on elsewhere in the protocol.

I believe that the reason the design team has gone in this direction is because 
the rats identifier does not appear in the final issued certificate. Is that 
correct?

If yes, why does no corresponding identifier appear in the cert? If the CA is 
enforcing that certain policies be met, then can't that be represented by a 
Certificate Policies extension? And then you're in an even better place, since 
enterprise clients can enforce that the specific Certificate Policy OID be 
present before they trust a cert.

I'm imagining a world where the flow looks like this:
1. Enterprise client requests a new order for internal.tld
2. Enterprise CA says "sure, but only if you're up-to-date", and creates an 
order with two identifiers:
  a. {"type": "dns", "value": "internal.tld"}
  b. {"type": "policy", "value": "1.2.3.4.5"} (created by server policy, not 
because client requested it)
3. Enterprise CA creates a corresponding authorization object, too, with the 
same "policy"-type identifier, and two "rats-01" and "rats-02" challenges, 
representing different ways the client can prove that it complies with the 
policy.
4. The client fulfills one of the challenges, and the authorization gets marked 
as valid.
5. The CA issues the cert, and includes OID 1.2.3.4.5 in the Certificate 
Policies extension

---

Regarding Q Misell's statement that RFC 8555 technically allows a server to 
require multiple challenges for a single authorization: the exact quote from 
Section 7.1.4<https://datatracker.ietf.org/doc/html/rfc8555#section-7.1.4>, in 
the description of the `challenges` field, is:
      Each array entry is an
      object with parameters required to validate the challenge.  A
      client should attempt to fulfill one of these challenges, and a
      server should consider any one of the challenges sufficient to
      make the authorization valid.
There's a similar statement later in Section 
7.5.1<https://datatracker.ietf.org/doc/html/rfc8555#autoid-39>, which says
   The server is said to "finalize" the authorization when it has
   completed one of the validations.

So I at least partially agree that it's acceptable for a server to require two 
different challenges to be fulfilled on a single authorization before it 
considers that authorization valid. However, I think doing this in practice 
would break virtually every ACME client in existence. In particular, most 
clients have very simple heuristics for selecting which challenge to fulfill on 
an authorization. I expect that, if a server accepted a challenge validation 
attempt but didn't mark the corresponding authorization as valid, most clients 
would get stuck in an infinite loop either polling the authorization until it 
becomes valid, or retrying the same challenge type over and over again.

---

In Section 3, I think that bullet points 2 and 3 are unnecessary. This draft is 
defining a new identifier type and a new challenge type. The rest of the 
process -- i.e. how the server reflects that identifier within the Order and 
Authorization objects -- is identical to vanilla RFC 8555, and does not need to 
be repeated here.

---

In Section 3, the last code block shows a challenge of type "rats", but then 
Section 4 defines two different "device-attest-02" and "device-attest-03" 
challenges. Those are the strings which should appear in the challenge objects 
in Section 3. Also, the URLs for each challenge need to be different:

{

  "status": "pending",



  "identifier": {

    "type": "policy",

    "value": "1.2.3.4.5"

  },



  "challenges": [

    {

      "type": "rats-01",

      "url": "https://example.com/acme/chall/asdf";,

      "status": "pending",

      "token": "DGyRejmCefe7v4NfDGDKfA",

    },

    {
      "type": "rats-02",
      "url": "https://example.com/acme/chall/zxcv";,
      "status": "pending",
      "token": "DGyRejmCefe7v4NfDGDKfA",
    },

  ],

}

---

In Section 4.1, the "response sent to the url" is defined, but appears to be 
just a plain string (`token || '.' || cmw`). The object posted to a challenge 
URL is always a signed JSON blob; just a pair of empty curly braces for the 
original challenge types, but subsequent challenge types (such as 
onion-csr-01<https://www.rfc-editor.org/rfc/rfc9799.html#name-new-onion-csr-01-challenge>)
 have added custom fields to that object. This draft needs to describe the 
whole payload which should be POSTed to the challenge URL, not just a single 
string.

---

In Section 4.2, it's unclear what part of Section 4.1 is being replaced by the 
"Background Check Model". Is that just a different way of computing `cmw`? A 
little more verbiage here would be useful.

---

In both Sections 4.1 and 4.2, it's unclear what steps the ACME server is 
supposed to take to verify that the challenge has been completed successfully / 
that the client has POSTed the correct content.

---

I don't understand the purpose of Section 5. How are these hints presented to 
the client? I don't see any evidence of them in the authorization or challenge 
objects created by the server in Section 3.

---

Overall, I like this draft. It's another simple example of adding a new 
identifier type, and a couple new challenges that can be used to validate that 
identifier type. This is exactly the kind of extension that ACME is built for. 
I think it just needs a bit of work to clarify how rats identifiers are 
represented in certificates, how rats challenges are fulfilled, and how ACME 
servers validate the challenges.

Thanks,
Aaron
_______________________________________________
Acme mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to