Download raw body.
acme-client(1): handle badNonce
Found with pebble.
RFC 8555 6.5 has:
When a server rejects a request because its nonce value was
unacceptable (or not present), it MUST provide HTTP status code 400
(Bad Request), and indicate the ACME error type
"urn:ietf:params:acme:error:badNonce". An error response with the
"badNonce" error type MUST include a Replay-Nonce header field with a
fresh nonce that the server will accept in a retry of the original
query (and possibly in other requests, according to the server's
nonce scoping policy). On receiving such a response, a client SHOULD
retry the request using the new nonce.
[...]
However, when
retrying in response to a "badNonce" error, the client MUST use the
nonce provided in the error response.
OK?
diff --git netproc.c netproc.c
index 00f24b530ad..11f57ab7088 100644
--- netproc.c
+++ netproc.c
@@ -260,6 +260,7 @@ sreq(struct conn *c, const char *addr, int kid, const char *req, char **loc)
struct httphead *h;
ssize_t ssz;
long code;
+ int retry = 0;
if ((host = url2host(c->newnonce, &port, &path)) == NULL)
return -1;
@@ -288,6 +289,7 @@ sreq(struct conn *c, const char *addr, int kid, const char *req, char **loc)
}
http_get_free(g);
+ again:
/*
* Send the url, nonce and request payload to the acctproc.
* This will create the proper JSON object we need.
@@ -346,6 +348,48 @@ sreq(struct conn *c, const char *addr, int kid, const char *req, char **loc)
} else
memcpy(c->buf.buf, g->bodypart, c->buf.sz);
+ if (code == 400) {
+ struct jsmnn *j;
+ char *type;
+
+ j = json_parse(c->buf.buf, c->buf.sz);
+ if (j == NULL) {
+ code = -1;
+ goto out;
+ }
+
+ type = json_getstr(j, "type");
+ json_free(j);
+
+ if (type == NULL) {
+ code = -1;
+ goto out;
+ }
+
+ if (strcmp(type, "urn:ietf:params:acme:error:badNonce") != 0) {
+ free(type);
+ code = -1;
+ goto out;
+ }
+ free(type);
+
+ if (retry++ < RETRY_MAX) {
+ h = http_head_get("Replay-Nonce", g->head, g->headsz);
+ if (h == NULL) {
+ warnx("no replay nonce");
+ code = -1;
+ goto out;
+ } else if ((nonce = strdup(h->val)) == NULL) {
+ warn("strdup");
+ code = -1;
+ goto out;
+ }
+ http_get_free(g);
+ warnx("GOTO AGAIN");
+ goto again;
+ }
+ }
+ out:
if (loc != NULL) {
free(*loc);
*loc = NULL;
--
In my defence, I have been left unsupervised.
acme-client(1): handle badNonce