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
*/
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;
}
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;