MINOR: acme: finalize by sending the CSR
This patch does the finalize step of the ACME task. This encodes the CSR into base64 format and send it to the finalize URL. https://www.rfc-editor.org/rfc/rfc8555#section-7.4
This commit is contained in:
parent
de5dc31a0d
commit
680222b382
@ -38,6 +38,7 @@ enum acme_st {
|
||||
ACME_AUTH,
|
||||
ACME_CHALLENGE,
|
||||
ACME_CHKCHALLENGE,
|
||||
ACME_FINALIZE,
|
||||
ACME_END
|
||||
};
|
||||
|
||||
@ -72,5 +73,6 @@ struct acme_ctx {
|
||||
struct acme_auth *auths;
|
||||
struct acme_auth *next_auth;
|
||||
X509_REQ *req;
|
||||
struct ist finalize;
|
||||
};
|
||||
#endif
|
||||
|
133
src/acme.c
133
src/acme.c
@ -578,6 +578,109 @@ error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Send the CSR over the Finalize URL */
|
||||
int acme_req_finalize(struct task *task, struct acme_ctx *ctx, char **errmsg)
|
||||
{
|
||||
X509_REQ *req = ctx->req;
|
||||
struct buffer *csr = NULL;
|
||||
struct buffer *req_in = NULL;
|
||||
struct buffer *req_out = NULL;
|
||||
const struct http_hdr hdrs[] = {
|
||||
{ IST("Content-Type"), IST("application/jose+json") },
|
||||
{ IST_NULL, IST_NULL }
|
||||
};
|
||||
int ret = 1;
|
||||
size_t len = 0;
|
||||
unsigned char *data = NULL;
|
||||
|
||||
if ((csr = alloc_trash_chunk()) == NULL)
|
||||
goto error;
|
||||
if ((req_in = alloc_trash_chunk()) == NULL)
|
||||
goto error;
|
||||
if ((req_out = alloc_trash_chunk()) == NULL)
|
||||
goto error;
|
||||
|
||||
len = i2d_X509_REQ(req, &data);
|
||||
if (len <= 0)
|
||||
goto error;
|
||||
|
||||
ret = a2base64url((char *)data, len, csr->area, csr->size);
|
||||
if (ret <= 0)
|
||||
goto error;
|
||||
csr->data = ret;
|
||||
|
||||
chunk_printf(req_in, "{ \"csr\": \"%.*s\" }", (int)csr->data, csr->area);
|
||||
free(data);
|
||||
|
||||
|
||||
if (acme_jws_payload(req_in, ctx->nonce, ctx->finalize, ctx->cfg->account.pkey, ctx->kid, req_out, errmsg) != 0)
|
||||
goto error;
|
||||
|
||||
if (acme_http_req(task, ctx, ctx->finalize, HTTP_METH_POST, hdrs, ist2(req_out->area, req_out->data)))
|
||||
goto error;
|
||||
|
||||
|
||||
ret = 0;
|
||||
error:
|
||||
memprintf(errmsg, "couldn't request the finalize URL");
|
||||
|
||||
free_trash_chunk(req_in);
|
||||
free_trash_chunk(req_out);
|
||||
free_trash_chunk(csr);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int acme_res_finalize(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 Finalize 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 Finalize URL", hc->res.status);
|
||||
goto error;
|
||||
}
|
||||
out:
|
||||
ret = 0;
|
||||
|
||||
error:
|
||||
free_trash_chunk(t1);
|
||||
free_trash_chunk(t2);
|
||||
httpclient_destroy(hc);
|
||||
ctx->hc = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send the READY request for the challenge
|
||||
*/
|
||||
@ -932,6 +1035,18 @@ int acme_res_neworder(struct task *task, struct acme_ctx *ctx, char **errmsg)
|
||||
ctx->next_auth = auth;
|
||||
}
|
||||
|
||||
if ((ret = mjson_get_string(hc->res.buf.area, hc->res.buf.data, "$.finalize", trash.area, trash.size)) <= 0) {
|
||||
memprintf(errmsg, "couldn't find the finalize URL");
|
||||
goto error;
|
||||
}
|
||||
trash.data = ret;
|
||||
istfree(&ctx->finalize);
|
||||
ctx->finalize = istdup(ist2(trash.area, trash.data));
|
||||
if (!isttest(ctx->finalize)) {
|
||||
memprintf(errmsg, "out of memory");
|
||||
goto error;
|
||||
}
|
||||
|
||||
out:
|
||||
ret = 0;
|
||||
|
||||
@ -1299,12 +1414,26 @@ struct task *acme_process(struct task *task, void *context, unsigned int state)
|
||||
}
|
||||
http_st = ACME_HTTP_REQ;
|
||||
if ((ctx->next_auth = ctx->next_auth->next) == NULL)
|
||||
goto end;
|
||||
st = ACME_FINALIZE;
|
||||
|
||||
/* call with next auth or do the challenge step */
|
||||
/* do it with the next auth or finalize */
|
||||
task_wakeup(task, TASK_WOKEN_MSG);
|
||||
}
|
||||
break;
|
||||
case ACME_FINALIZE:
|
||||
if (http_st == ACME_HTTP_REQ) {
|
||||
if (acme_req_finalize(task, ctx, &errmsg) != 0)
|
||||
goto retry;
|
||||
}
|
||||
if (http_st == ACME_HTTP_RES) {
|
||||
if (acme_res_finalize(task, ctx, &errmsg) != 0) {
|
||||
http_st = ACME_HTTP_REQ;
|
||||
goto retry;
|
||||
}
|
||||
http_st = ACME_HTTP_REQ;
|
||||
goto end;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
Loading…
x
Reference in New Issue
Block a user