From 3fa0aa3664deee9b83f42b662436d7eb46ad8f3f Mon Sep 17 00:00:00 2001 From: Mia Kanashi Date: Fri, 1 May 2026 21:06:17 +0300 Subject: [PATCH] BUG/MINOR: acme: contact mail should be optional, don't pass ToS bool According to ACME RFC contact email is optional. Letsencrypt used it some long time ago, but not today. Currently HAProxy always sets the value of the contact mail to a string that is read from the config, but if that string is not specified, it sets %s in mailto:%s to null, which cases new account request to fail in pebble. Also HAProxy currently passes termsOfServiceAgreed bool to requests that contain onlyReturnExisting, that isn't needed according to the RFC and other ACME impls. This patch dynamically builds the account request JSON to address that. Can be backported to 3.2 --- src/acme.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/acme.c b/src/acme.c index 9f60e9073..46d5ca90a 100644 --- a/src/acme.c +++ b/src/acme.c @@ -2215,16 +2215,6 @@ int acme_req_account(struct task *task, struct acme_ctx *ctx, int newaccount, ch { IST("Content-Type"), IST("application/jose+json") }, { IST_NULL, IST_NULL } }; - char *accountreq = "{\n" - " \"termsOfServiceAgreed\": true,\n" - " \"onlyReturnExisting\": true\n" - "}\n"; - char *newaccountreq = "{\n" - " \"termsOfServiceAgreed\": true,\n" - " \"contact\": [\n" - " \"mailto:%s\"\n" - " ]\n" - "}\n"; int ret = 1; if ((req_in = alloc_trash_chunk()) == NULL) @@ -2232,10 +2222,14 @@ int acme_req_account(struct task *task, struct acme_ctx *ctx, int newaccount, ch if ((req_out = alloc_trash_chunk()) == NULL) goto error; - if (newaccount) - chunk_printf(req_in, newaccountreq, ctx->cfg->account.contact); - else - chunk_printf(req_in, "%s", accountreq); + if (newaccount) { + chunk_appendf(req_in, "{"); + if (ctx->cfg->account.contact != NULL) + chunk_appendf(req_in, "\"contact\": [ \"mailto:%s\" ],", ctx->cfg->account.contact); + chunk_appendf(req_in, "\"termsOfServiceAgreed\": true"); + chunk_appendf(req_in, "}"); + } else + chunk_appendf(req_in, "{ \"onlyReturnExisting\": true }"); TRACE_DATA("newAccount Decoded", ACME_EV_REQ, ctx, &ctx->resources.newAccount, req_in);