Subject: [Acme] Returning multiple errors

From: Jacob Hoffman-Andrews <[email-masked]>
Date: Wed, 15 Nov 2017 17:23:07 -0800

In previous versions of ACME, there was sometimes a need to return
multiple errors, broken out by domain name. For instance, when issuing a
certificate by making a new-cert request, the CA has to check CAA, which
may fail for multiple domains. Ideally, the client should not have to
guess which identifiers (domains) failed, or engage in string parsing.
So far, this hasn't been terrible because *most* errors occur during
new-authz or during validation, and so are implicitly associated with a
specific identifier.

However, in the latest spec, this problem is a lot worse. Since all
issuance starts with new-order, which can request multiple identifiers,
all attempts to issue for multiple identifiers will potentially fail for
one or more of those identifiers.

Fortunately, JSON problem details provide enough flexibility for this,
with problem-specific extensions
(https://tools.ietf.org/html/rfc7807#page-4). I propose we define a
field, "sub-problems", on all ACME problem types. This field would
contain a list of JSON problem details, each of which may contain an
identifier. So for instance, you might receive this response from a
new-order request:

{
  "type": "urn:ietf:params:acme:error:malformed",
  "detail": "Some of the identifiers requested were rejected",
  "sub-problems": [ {
    "identifier": { "value": "_example.com", "type": "dns" },
    "type": "urn:ietf:params:acme:error:malformed",
    "value": "Invalid underscore in DNS name \"_example.com\"",
  }, {
    "identifier": { "value": "example.net", "type": "dns" },
    "type": "urn:ietf:params:acme:error:malformed",
    "value": "\"example.net\" is considered a high-risk domain",
  } ]
}

That way, clients that issue for large numbers of domains may choose to
automatically retry new-order with the problem identifiers removed.

Thoughts?

---

From: Richard Barnes <[email-masked]>
Date: Thu, 16 Nov 2017 11:07:04 +0800

This sounds pretty inoffensive to me.  Want to send a PR?

Following Daniel's lead on looking for implementation: Is this something LE
would be implementing?

On Thu, Nov 16, 2017 at 9:23 AM, Jacob Hoffman-Andrews <[email-masked]> wrote:

> _______________________________________________
> Acme mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/acme
>

---

From: Jacob Hoffman-Andrews <[email-masked]>
Date: Wed, 15 Nov 2017 23:54:51 -0800

On 11/15/2017 07:07 PM, Richard Barnes wrote:
> Following Daniel's lead on looking for implementation: Is this
> something LE would be implementing?
Yep, we would definitely implement this. I'll send a PR.

---

From: Martin Thomson <[email-masked]>
Date: Thu, 16 Nov 2017 16:45:00 +0800

Have you considered json text sequences: https://tools.ietf.org/html/rfc7464 ?

I don't know what a random JSON parser would do with your stacked error codes.

---

From: Jacob Hoffman-Andrews <[email-masked]>
Date: Thu, 16 Nov 2017 00:47:06 -0800

> I don't know what a random JSON parser would do with your stacked error codes.
I don't understand. What I'm proposing is an array of JSON objects under
the sub-problems field, which should be supported by any JSON parser.

---

From: "Matthew A. Miller" <[email-masked]>
Date: Thu, 16 Nov 2017 16:49:28 +0800

> the sub-problems field, which should be supported by any JSON parser.

I don't think JSON text sequences is the right solution here, either.  A
JSON array seems perfectly appropriate to me.

- m&m

Matthew A. Miller

---

From: Martin Thomson <[email-masked]>
Date: Thu, 16 Nov 2017 16:53:14 +0800

Oh, my bad, my eyes turn out to be a terrible JSON parser.

---

From: Daniel McCarney <[email-masked]>
Date: Thu, 16 Nov 2017 08:22:23 -0500

I think this is a solid proposal addressing a real need. I'm +1 for
supporting it both in spec and in Boulder/Pebble.

Thanks Jacob,

---

From: Jacob Hoffman-Andrews <[email-masked]>
Date: Mon, 20 Nov 2017 15:19:57 -0800

I've submitted a PR adding this to the spec:

https://github.com/ietf-wg-acme/acme/pull/354

commit a6cc0aedf96067e8b3aaf37662785fcf8b38dd18
Author: Jacob Hoffman-Andrews <[email-masked]>
Date:   Mon Nov 20 15:14:29 2017 -0800

    Define sub-problems.

diff --git a/draft-ietf-acme-acme.md b/draft-ietf-acme-acme.md
index a2c11ab..a9e3535 100644
--- a/draft-ietf-acme-acme.md
+++ b/draft-ietf-acme-acme.md
@@ -521,6 +521,53 @@ set to a URI other than those defined above.
Servers MUST NOT use the ACME URN
 namespace for errors other than the standard types.  Clients SHOULD
display the
 "detail" field of all errors.

+### Sub-problems
+
+Sometimes a CA may need to return multiple errors to a single
+request. Additionally, the CA may need to attribute errors to specific
+identifiers.  For instance, a new-order request may contain multiple
+identifiers for which the CA cannot issue. In this situation, an ACME
+problem document MAY contain the "sub-problems" field, contains a JSON
+array of problem documents, each of which MAY contain an "identifier"
+field. If present, the "identifier" field MUST contain an ACME identifier
+({{iana-identifier}}). The "identifier" field MUST NOT be present at
+the top level in ACME problem documents. It can only be present in
sub-problems.
+Sub-problems need not all have the same type, and do not need to match
the top level type.
+
+ACME clients may choose to use the "identifier" field as a hint that
+an operation would succeed if certain identifiers were omitted. For
+instance, if an order contains ten DNS identifiers, and the new-order
+request returns a problem document with two sub-problems, referencing two
+of those identifiers, the ACME client may choose to submit another order
+containing only the eight identifiers not listed in the problem document.
+
+~~~~~
+HTTP/1.1 403 Forbidden
+Content-Type: application/problem+json
+
+{
+    "type": "urn:ietf:params:acme:error:malformed",
+    "detail": "Some of the identifiers requested were rejected",
+    "sub-problems": [
+        {
+            "type": "urn:ietf:params:acme:error:malformed",
+            "value": "Invalid underscore in DNS name \"_example.com\"",
+            "identifier": {
+                "type": "dns",
+                "value": "_example.com"
+            }
+        },
+        {
+            "type": "urn:ietf:params:acme:error:rejectedIdentifier",
+            "value": "This CA will not issue for \"example.net\"",
+            "identifier": {
+                "type": "dns",
+                "value": "example.net"
+            }
+        }
+    ]
+}
+~~~~~

 # Certificate Management

---

From: Martin Thomson <[email-masked]>
Date: Tue, 21 Nov 2017 15:24:32 +1100

Is this better cast as "sub" problems, or just "additional" problems?

---

From: Jacob Hoffman-Andrews <[email-masked]>
Date: Tue, 21 Nov 2017 10:55:54 -0800

> Is this better cast as "sub" problems, or just "additional" problems?

I think "additional" is the wrong semantic, because it implies that the
first error is hoisted to the top position, so a naive client would only
show the first error. Instead, there's a top-level generic error ("some
identifiers were rejected"), and then there are potentially multiple
errors that are part of it (_example.com, example.net).

---

From: Niklas Keller <[email-masked]>
Date: Tue, 21 Nov 2017 20:48:36 +0100

> errors that are part of it (_example.com, example.net).

How about "causes"?

Regards, Niklas

---

From: Jacob Hoffman-Andrews <[email-masked]>
Date: Tue, 21 Nov 2017 12:37:08 -0800

> How about "causes"?

I think this also implies more meaning than there really is. It also has
the unfortunate property of being both a plural noun and a transitive
verb, which could be confusing.

Is there a problem with sub-problems?

---

From: Martin Thomson <[email-masked]>
Date: Wed, 22 Nov 2017 11:06:13 +1100

> errors that are part of it (_example.com, example.net).

I ask because your example highlighted two types of problems.  That
they could be aggregated doesn't seem an necessary or innate property.

The difficulty with the sort of aggregation design you propose is that
you need to aggregate and I don't know what the logic would be in the
general case.  On the other hand, additional problems are easy to
accumulate and emit.  They are also easy to consume, either by just
doing the dumb thing and handling only the first, or by working
through a list.

The alternative is to provide a specific type (e.g.,
"urn:ietf:params:acme:error:multiple"), that says "there were multiple
problems", and list the real problems in the body.  The text for the
specific type could be more helpful - just as in your example - or
not.

"sub-problems" seems like the worst of these options.

---

From: Jacob Hoffman-Andrews <[email-masked]>
Date: Tue, 21 Nov 2017 16:20:11 -0800

> specific type could be more helpful - just as in your example - or

The current text allows the CA to choose whatever error type at the top
level it wants, including its own type. I think that flexibility is
fine. Is your main problem that this doesn't specify a top-level
"multiple" error type?

> list the real problems in the body

This is insufficient, because the goal is to allow clients to
programmatically remove identifiers from a request. So we need some
specific field in JSON.

We can't have a raw list, because identifiers are objects, not strings.
So we have a list of objects containing identifiers. It happens to be
handy to attach a type and a value to each.

>  additional problems are easy to accumulate and emit.

As an implementer, I find sub-problems easy and more natural than a list
of problems that gets appended to.