From 27fff179fe5d378d021df2473e82e2637ff44049 Mon Sep 17 00:00:00 2001 From: William Lallemand Date: Fri, 11 Apr 2025 20:56:57 +0200 Subject: [PATCH] MINOR: acme: verify the order status once finalized This implements a call to the order status to check if the certificate is ready. --- include/haproxy/acme-t.h | 2 + src/acme.c | 86 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/include/haproxy/acme-t.h b/include/haproxy/acme-t.h index 3151d58cf..da437f157 100644 --- a/include/haproxy/acme-t.h +++ b/include/haproxy/acme-t.h @@ -39,6 +39,7 @@ enum acme_st { ACME_CHALLENGE, ACME_CHKCHALLENGE, ACME_FINALIZE, + ACME_CHKORDER, ACME_END }; @@ -74,5 +75,6 @@ struct acme_ctx { struct acme_auth *next_auth; X509_REQ *req; struct ist finalize; + struct ist certificate; }; #endif diff --git a/src/acme.c b/src/acme.c index 0b4174b23..36b6a61fd 100644 --- a/src/acme.c +++ b/src/acme.c @@ -578,6 +578,77 @@ error: return ret; } +int acme_res_chkorder(struct task *task, struct acme_ctx *ctx, char **errmsg) +{ + struct httpclient *hc; + struct http_hdr *hdrs, *hdr; + struct buffer *t1 = NULL, *t2 = NULL; + int ret = 1; + + hc = ctx->hc; + if (!hc) + goto error; + + if ((t1 = alloc_trash_chunk()) == NULL) + goto error; + if ((t2 = alloc_trash_chunk()) == NULL) + goto error; + + hdrs = hc->res.hdrs; + + for (hdr = hdrs; isttest(hdr->v); hdr++) { + if (isteqi(hdr->n, ist("Replay-Nonce"))) { + istfree(&ctx->nonce); + ctx->nonce = istdup(hdr->v); + } + } + + if (hc->res.status < 200 || hc->res.status >= 300) { + if ((ret = mjson_get_string(hc->res.buf.area, hc->res.buf.data, "$.detail", t1->area, t1->size)) > -1) + t1->data = ret; + if ((ret = mjson_get_string(hc->res.buf.area, hc->res.buf.data, "$.type", t2->area, t2->size)) > -1) + t2->data = ret; + + if (t2->data && t1->data) + memprintf(errmsg, "invalid HTTP status code %d when getting Order URL: \"%.*s\" (%.*s)", hc->res.status, (int)t1->data, t1->area, (int)t2->data, t2->area); + else + memprintf(errmsg, "invalid HTTP status code %d when getting Order URL", hc->res.status); + goto error; + } + ret = mjson_get_string(hc->res.buf.area, hc->res.buf.data, "$.certificate", trash.area, trash.size); + if (ret == -1) { + memprintf(errmsg, "couldn't get a the certificate URL"); + goto error; + } + trash.data = ret; + ctx->certificate = istdup(ist2(trash.area, trash.data)); + if (!isttest(ctx->certificate)) { + memprintf(errmsg, "out of memory"); + goto error; + } + ret = mjson_get_string(hc->res.buf.area, hc->res.buf.data, "$.status", trash.area, trash.size); + if (ret == -1) { + memprintf(errmsg, "couldn't get a the Order status"); + goto error; + } + trash.data = ret; + if (strncasecmp("valid", trash.area, trash.data) != 0) { + memprintf(errmsg, "order status: %.*s", (int)trash.data, trash.area); + goto error; + }; + +out: + ret = 0; + +error: + free_trash_chunk(t1); + free_trash_chunk(t2); + httpclient_destroy(hc); + ctx->hc = NULL; + + return ret; +} + /* Send the CSR over the Finalize URL */ int acme_req_finalize(struct task *task, struct acme_ctx *ctx, char **errmsg) { @@ -1431,6 +1502,21 @@ struct task *acme_process(struct task *task, void *context, unsigned int state) goto retry; } http_st = ACME_HTTP_REQ; + st = ACME_CHKORDER; + task_wakeup(task, TASK_WOKEN_MSG); + } + break; + case ACME_CHKORDER: + if (http_st == ACME_HTTP_REQ) { + if (acme_http_req(task, ctx, ctx->order, HTTP_METH_GET, NULL, IST_NULL) != 0) + goto retry; + } + if (http_st == ACME_HTTP_RES) { + if (acme_res_chkorder(task, ctx, &errmsg) != 0) { + http_st = ACME_HTTP_REQ; + goto retry; + } + http_st = ACME_HTTP_REQ; goto end; } break;