mirror of https://git.kore.io/kore.git
Acme protocol updates.
- Adds POST-as-GET for all GET requests that would support it.
This commit is contained in:
parent
cb0f5a4137
commit
4cace25330
169
src/acme.c
169
src/acme.c
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 Joris Vink <joris@coders.se>
|
||||
* Copyright (c) 2019-2021 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -136,6 +136,7 @@ struct acme_sign_op {
|
|||
|
||||
struct acme_auth {
|
||||
char *url;
|
||||
struct acme_order *order;
|
||||
int status;
|
||||
struct acme_challenge *challenge;
|
||||
LIST_ENTRY(acme_auth) list;
|
||||
|
@ -143,6 +144,12 @@ struct acme_auth {
|
|||
|
||||
#define ACME_ORDER_STATE_RUNNING 1
|
||||
#define ACME_ORDER_STATE_ERROR 2
|
||||
#define ACME_ORDER_STATE_CANCELLED 3
|
||||
#define ACME_ORDER_STATE_UPDATE 4
|
||||
#define ACME_ORDER_STATE_UPDATE_AUTH 5
|
||||
#define ACME_ORDER_STATE_WAITING 6
|
||||
#define ACME_ORDER_STATE_FETCH_CERT 7
|
||||
#define ACME_ORDER_STATE_COMPLETE 8
|
||||
#define ACME_ORDER_TICK 1000
|
||||
#define ACME_ORDER_TIMEOUT 60000
|
||||
|
||||
|
@ -152,6 +159,7 @@ struct acme_order {
|
|||
int state;
|
||||
int status;
|
||||
int flags;
|
||||
int auths;
|
||||
u_int64_t start;
|
||||
char *id;
|
||||
char *final;
|
||||
|
@ -217,8 +225,12 @@ static void acme_account_reg_submit(struct acme_sign_op *,
|
|||
static void acme_order_retry(const char *);
|
||||
static void acme_order_process(void *, u_int64_t);
|
||||
static void acme_order_update(struct acme_order *);
|
||||
static void acme_order_update_submit(struct acme_sign_op *,
|
||||
struct kore_buf *);
|
||||
static void acme_order_request_csr(struct acme_order *);
|
||||
static int acme_order_fetch_certificate(struct acme_order *);
|
||||
static void acme_order_fetch_certificate(struct acme_order *);
|
||||
static void acme_order_fetch_certificate_submit(struct acme_sign_op *,
|
||||
struct kore_buf *);
|
||||
static void acme_order_create(struct kore_msg *, const void *);
|
||||
static void acme_order_remove(struct acme_order *, const char *);
|
||||
static void acme_order_csr_response(struct kore_msg *, const void *);
|
||||
|
@ -229,8 +241,10 @@ static void acme_order_auth_log_error(struct acme_order *);
|
|||
static void acme_order_auth_deactivate(struct acme_order *);
|
||||
static int acme_order_auth_process(struct acme_order *,
|
||||
struct acme_auth *);
|
||||
static int acme_order_auth_update(struct acme_order *,
|
||||
static void acme_order_auth_update(struct acme_order *,
|
||||
struct acme_auth *);
|
||||
static void acme_order_auth_update_submit(struct acme_sign_op *,
|
||||
struct kore_buf *);
|
||||
|
||||
static int acme_challenge_tls_alpn_01(struct acme_order *,
|
||||
struct acme_challenge *);
|
||||
|
@ -616,8 +630,8 @@ acme_order_create_submit(struct acme_sign_op *op, struct kore_buf *payload)
|
|||
struct kore_json json;
|
||||
int stval;
|
||||
const u_int8_t *body;
|
||||
struct acme_order *order;
|
||||
struct acme_auth *auth;
|
||||
struct acme_order *order;
|
||||
const char *header;
|
||||
const char *domain;
|
||||
struct kore_json_item *item, *array, *final, *status;
|
||||
|
@ -701,7 +715,7 @@ acme_order_create_submit(struct acme_sign_op *op, struct kore_buf *payload)
|
|||
order->start = kore_time_ms();
|
||||
order->id = kore_strdup(header);
|
||||
order->domain = kore_strdup(domain);
|
||||
order->state = ACME_ORDER_STATE_RUNNING;
|
||||
order->state = ACME_ORDER_STATE_UPDATE;
|
||||
order->final = kore_strdup(final->data.string);
|
||||
|
||||
kore_timer_add(acme_order_process, ACME_ORDER_TICK,
|
||||
|
@ -712,6 +726,7 @@ acme_order_create_submit(struct acme_sign_op *op, struct kore_buf *payload)
|
|||
continue;
|
||||
|
||||
auth = kore_calloc(1, sizeof(*auth));
|
||||
auth->order = order;
|
||||
auth->url = kore_strdup(item->data.string);
|
||||
LIST_INSERT_HEAD(&order->auth, auth, list);
|
||||
}
|
||||
|
@ -729,15 +744,26 @@ cleanup:
|
|||
|
||||
static void
|
||||
acme_order_update(struct acme_order *order)
|
||||
{
|
||||
acme_sign_submit(NULL, order->id, order, acme_order_update_submit);
|
||||
}
|
||||
|
||||
static void
|
||||
acme_order_update_submit(struct acme_sign_op *op, struct kore_buf *payload)
|
||||
{
|
||||
struct acme_request req;
|
||||
size_t len;
|
||||
struct kore_json json;
|
||||
struct acme_order *order;
|
||||
const u_int8_t *body;
|
||||
int stval, ret;
|
||||
struct kore_json_item *status, *cert;
|
||||
|
||||
acme_request_prepare(&req, HTTP_METHOD_GET, order->id, NULL, 0);
|
||||
order = op->udata;
|
||||
op->udata = NULL;
|
||||
|
||||
acme_request_prepare(&req, HTTP_METHOD_POST, order->id,
|
||||
payload->data, payload->offset);
|
||||
|
||||
if (!acme_request_run(&req)) {
|
||||
acme_request_cleanup(&req);
|
||||
|
@ -798,6 +824,8 @@ acme_order_update(struct acme_order *order)
|
|||
cleanup:
|
||||
if (ret == KORE_RESULT_ERROR)
|
||||
order->state = ACME_ORDER_STATE_ERROR;
|
||||
else
|
||||
order->state = ACME_ORDER_STATE_UPDATE_AUTH;
|
||||
|
||||
kore_json_cleanup(&json);
|
||||
acme_request_cleanup(&req);
|
||||
|
@ -821,21 +849,19 @@ acme_order_retry(const char *domain)
|
|||
KORE_ACME_ORDER_FAILED);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process an order, step by step.
|
||||
*
|
||||
* This callback is called every second to check on an active order.
|
||||
* It will first update the order if required, and updated any of its
|
||||
* active awuthoritizations to get the latest data.
|
||||
*/
|
||||
static void
|
||||
acme_order_process(void *udata, u_int64_t now)
|
||||
{
|
||||
struct acme_auth *auth;
|
||||
struct acme_order *order = udata;
|
||||
|
||||
acme_order_update(order);
|
||||
|
||||
LIST_FOREACH(auth, &order->auth, list) {
|
||||
if (!acme_order_auth_update(order, auth)) {
|
||||
acme_order_remove(order, "cancelled");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((now - order->start) >= ACME_ORDER_TIMEOUT) {
|
||||
acme_order_auth_deactivate(order);
|
||||
acme_order_remove(order, "order ran too long");
|
||||
|
@ -843,6 +869,32 @@ acme_order_process(void *udata, u_int64_t now)
|
|||
}
|
||||
|
||||
switch (order->state) {
|
||||
case ACME_ORDER_STATE_WAITING:
|
||||
break;
|
||||
case ACME_ORDER_STATE_UPDATE:
|
||||
acme_order_update(order);
|
||||
order->state = ACME_ORDER_STATE_WAITING;
|
||||
break;
|
||||
case ACME_ORDER_STATE_UPDATE_AUTH:
|
||||
order->auths = 0;
|
||||
LIST_FOREACH(auth, &order->auth, list) {
|
||||
acme_order_auth_update(order, auth);
|
||||
order->auths++;
|
||||
}
|
||||
order->state = ACME_ORDER_STATE_WAITING;
|
||||
break;
|
||||
case ACME_ORDER_STATE_CANCELLED:
|
||||
acme_order_remove(order, "cancelled");
|
||||
order = NULL;
|
||||
break;
|
||||
case ACME_ORDER_STATE_COMPLETE:
|
||||
acme_order_remove(order, "completed");
|
||||
order = NULL;
|
||||
break;
|
||||
case ACME_ORDER_STATE_FETCH_CERT:
|
||||
acme_order_fetch_certificate(order);
|
||||
order->state = ACME_ORDER_STATE_WAITING;
|
||||
break;
|
||||
case ACME_ORDER_STATE_RUNNING:
|
||||
switch (order->status) {
|
||||
case ACME_STATUS_PENDING:
|
||||
|
@ -862,13 +914,7 @@ acme_order_process(void *udata, u_int64_t now)
|
|||
case ACME_STATUS_VALID:
|
||||
kore_log(LOG_INFO, "[%s] certificate available",
|
||||
order->domain);
|
||||
if (!acme_order_fetch_certificate(order)) {
|
||||
acme_order_remove(order,
|
||||
"failed to fetch certificate");
|
||||
} else {
|
||||
acme_order_remove(order, "completed");
|
||||
}
|
||||
order = NULL;
|
||||
order->state = ACME_ORDER_STATE_FETCH_CERT;
|
||||
break;
|
||||
case ACME_STATUS_INVALID:
|
||||
kore_log(LOG_INFO, "[%s] order authorization failed",
|
||||
|
@ -894,6 +940,10 @@ acme_order_process(void *udata, u_int64_t now)
|
|||
}
|
||||
|
||||
if (order != NULL) {
|
||||
/* Do not go back to update if we are ready for the cert. */
|
||||
if (order->state != ACME_ORDER_STATE_FETCH_CERT)
|
||||
order->state = ACME_ORDER_STATE_UPDATE;
|
||||
|
||||
kore_timer_add(acme_order_process, ACME_ORDER_TICK,
|
||||
order, KORE_TIMER_ONESHOT);
|
||||
}
|
||||
|
@ -933,21 +983,32 @@ acme_order_remove(struct acme_order *order, const char *reason)
|
|||
kore_free(order);
|
||||
}
|
||||
|
||||
static int
|
||||
static void
|
||||
acme_order_fetch_certificate(struct acme_order *order)
|
||||
{
|
||||
acme_sign_submit(NULL, order->certloc, order,
|
||||
acme_order_fetch_certificate_submit);
|
||||
}
|
||||
|
||||
static void
|
||||
acme_order_fetch_certificate_submit(struct acme_sign_op *op,
|
||||
struct kore_buf *payload)
|
||||
{
|
||||
struct acme_request req;
|
||||
size_t len;
|
||||
const u_int8_t *body;
|
||||
struct acme_order *order;
|
||||
|
||||
if (order->certloc == NULL)
|
||||
return (KORE_RESULT_ERROR);
|
||||
order = op->udata;
|
||||
op->udata = NULL;
|
||||
|
||||
acme_request_prepare(&req, HTTP_METHOD_GET, order->certloc, NULL, 0);
|
||||
acme_request_prepare(&req, HTTP_METHOD_POST, order->certloc,
|
||||
payload->data, payload->offset);
|
||||
|
||||
if (!acme_request_run(&req)) {
|
||||
acme_request_cleanup(&req);
|
||||
return (KORE_RESULT_ERROR);
|
||||
order->state = ACME_ORDER_STATE_CANCELLED;
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.curl.http.status != HTTP_STATUS_OK) {
|
||||
|
@ -955,7 +1016,8 @@ acme_order_fetch_certificate(struct acme_order *order)
|
|||
"[%s] request to '%s' failed: got %ld - expected 200",
|
||||
order->domain, order->certloc, req.curl.http.status);
|
||||
acme_request_cleanup(&req);
|
||||
return (KORE_RESULT_ERROR);
|
||||
order->state = ACME_ORDER_STATE_CANCELLED;
|
||||
return;
|
||||
}
|
||||
|
||||
kore_curl_response_as_bytes(&req.curl, &body, &len);
|
||||
|
@ -964,8 +1026,7 @@ acme_order_fetch_certificate(struct acme_order *order)
|
|||
acme_keymgr_key_req(order->domain, body, len, KORE_ACME_INSTALL_CERT);
|
||||
|
||||
acme_request_cleanup(&req);
|
||||
|
||||
return (KORE_RESULT_OK);
|
||||
order->state = ACME_ORDER_STATE_COMPLETE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1097,33 +1158,46 @@ acme_order_auth_process(struct acme_order *order, struct acme_auth *auth)
|
|||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
static void
|
||||
acme_order_auth_update(struct acme_order *order, struct acme_auth *auth)
|
||||
{
|
||||
acme_sign_submit(NULL, auth->url, auth, acme_order_auth_update_submit);
|
||||
}
|
||||
|
||||
static void
|
||||
acme_order_auth_update_submit(struct acme_sign_op *op, struct kore_buf *payload)
|
||||
{
|
||||
const char *p;
|
||||
struct acme_request req;
|
||||
size_t len;
|
||||
struct kore_json json;
|
||||
const u_int8_t *body;
|
||||
int ret, stval;
|
||||
struct acme_auth *auth;
|
||||
struct acme_order *order;
|
||||
struct acme_challenge *challenge;
|
||||
int ret, stval;
|
||||
struct kore_json_item *status, *type, *url, *token;
|
||||
struct kore_json_item *array, *object, *err, *detail;
|
||||
|
||||
ret = KORE_RESULT_ERROR;
|
||||
acme_request_prepare(&req, HTTP_METHOD_GET, auth->url, NULL, 0);
|
||||
memset(&json, 0, sizeof(json));
|
||||
|
||||
if (!acme_request_run(&req)) {
|
||||
acme_request_cleanup(&req);
|
||||
return (ret);
|
||||
}
|
||||
auth = op->udata;
|
||||
order = auth->order;
|
||||
|
||||
op->udata = NULL;
|
||||
|
||||
acme_request_prepare(&req, HTTP_METHOD_POST, auth->url,
|
||||
payload->data, payload->offset);
|
||||
|
||||
if (!acme_request_run(&req))
|
||||
goto cleanup;
|
||||
|
||||
if (req.curl.http.status != HTTP_STATUS_OK) {
|
||||
kore_log(LOG_NOTICE,
|
||||
"[%s:auth] request to '%s' failed: got %ld - expected 200",
|
||||
order->domain, auth->url, req.curl.http.status);
|
||||
acme_request_cleanup(&req);
|
||||
return (ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
kore_curl_response_as_bytes(&req.curl, &body, &len);
|
||||
|
@ -1270,10 +1344,19 @@ acme_order_auth_update(struct acme_order *order, struct acme_auth *auth)
|
|||
ret = KORE_RESULT_OK;
|
||||
|
||||
cleanup:
|
||||
if (ret != KORE_RESULT_OK) {
|
||||
order->state = ACME_ORDER_STATE_CANCELLED;
|
||||
} else {
|
||||
order->auths--;
|
||||
if (order->auths == 0) {
|
||||
kore_log(LOG_NOTICE,
|
||||
"[%s:auth] authentications done", order->domain);
|
||||
order->state = ACME_ORDER_STATE_RUNNING;
|
||||
}
|
||||
}
|
||||
|
||||
kore_json_cleanup(&json);
|
||||
acme_request_cleanup(&req);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1500,7 +1583,9 @@ acme_sign_submit(struct kore_json_item *json, const char *url, void *udata,
|
|||
}
|
||||
|
||||
kore_buf_init(&buf, 1024);
|
||||
kore_json_item_tobuf(json, &buf);
|
||||
|
||||
if (json != NULL)
|
||||
kore_json_item_tobuf(json, &buf);
|
||||
|
||||
op = kore_calloc(1, sizeof(*op));
|
||||
LIST_INSERT_HEAD(&signops, op, list);
|
||||
|
|
Loading…
Reference in New Issue