summaryrefslogtreecommitdiffstats
path: root/modules/md/md_acme.h
diff options
context:
space:
mode:
Diffstat (limited to 'modules/md/md_acme.h')
-rw-r--r--modules/md/md_acme.h216
1 files changed, 133 insertions, 83 deletions
diff --git a/modules/md/md_acme.h b/modules/md/md_acme.h
index 2dcbee6..f28f2b6 100644
--- a/modules/md/md_acme.h
+++ b/modules/md/md_acme.h
@@ -26,14 +26,21 @@ struct md_json_t;
struct md_pkey_t;
struct md_t;
struct md_acme_acct_t;
-struct md_proto_t;
+struct md_acmev2_acct_t;
struct md_store_t;
+struct md_result_t;
#define MD_PROTO_ACME "ACME"
#define MD_AUTHZ_CHA_HTTP_01 "http-01"
#define MD_AUTHZ_CHA_SNI_01 "tls-sni-01"
+#define MD_ACME_VERSION_UNKNOWN 0x0
+#define MD_ACME_VERSION_1 0x010000
+#define MD_ACME_VERSION_2 0x020000
+
+#define MD_ACME_VERSION_MAJOR(i) (((i)&0xFF0000) >> 16)
+
typedef enum {
MD_ACME_S_UNKNOWN, /* MD has not been analysed yet */
MD_ACME_S_REGISTERED, /* MD is registered at CA, but not more */
@@ -46,30 +53,92 @@ typedef enum {
typedef struct md_acme_t md_acme_t;
+typedef struct md_acme_req_t md_acme_req_t;
+/**
+ * Request callback on a successful HTTP response (status 2xx).
+ */
+typedef apr_status_t md_acme_req_res_cb(md_acme_t *acme,
+ const struct md_http_response_t *res, void *baton);
+
+/**
+ * Request callback to initialize before sending. May be invoked more than once in
+ * case of retries.
+ */
+typedef apr_status_t md_acme_req_init_cb(md_acme_req_t *req, void *baton);
+
+/**
+ * Request callback on a successful response (HTTP response code 2xx) and content
+ * type matching application/.*json.
+ */
+typedef apr_status_t md_acme_req_json_cb(md_acme_t *acme, apr_pool_t *p,
+ const apr_table_t *headers,
+ struct md_json_t *jbody, void *baton);
+
+/**
+ * Request callback on detected errors.
+ */
+typedef apr_status_t md_acme_req_err_cb(md_acme_req_t *req,
+ const struct md_result_t *result, void *baton);
+
+
+typedef apr_status_t md_acme_new_nonce_fn(md_acme_t *acme);
+typedef apr_status_t md_acme_req_init_fn(md_acme_req_t *req, struct md_json_t *jpayload);
+
+typedef apr_status_t md_acme_post_fn(md_acme_t *acme,
+ md_acme_req_init_cb *on_init,
+ md_acme_req_json_cb *on_json,
+ md_acme_req_res_cb *on_res,
+ md_acme_req_err_cb *on_err,
+ void *baton);
+
struct md_acme_t {
const char *url; /* directory url of the ACME service */
const char *sname; /* short name for the service, not necessarily unique */
apr_pool_t *p;
const char *user_agent;
const char *proxy_url;
- struct md_acme_acct_t *acct;
- struct md_pkey_t *acct_key;
+ const char *ca_file;
- const char *new_authz;
- const char *new_cert;
- const char *new_reg;
- const char *revoke_cert;
+ const char *acct_id; /* local storage id account was loaded from or NULL */
+ struct md_acme_acct_t *acct; /* account at ACME server to use for requests */
+ struct md_pkey_t *acct_key; /* private RSA key belonging to account */
+
+ int version; /* as detected from the server */
+ union {
+ struct { /* obsolete */
+ const char *new_authz;
+ const char *new_cert;
+ const char *new_reg;
+ const char *revoke_cert;
+
+ } v1;
+ struct {
+ const char *new_account;
+ const char *new_order;
+ const char *key_change;
+ const char *revoke_cert;
+ const char *new_nonce;
+ } v2;
+ } api;
+ const char *ca_agreement;
+ const char *acct_name;
+ int eab_required;
+
+ md_acme_new_nonce_fn *new_nonce_fn;
+ md_acme_req_init_fn *req_init_fn;
+ md_acme_post_fn *post_new_account_fn;
struct md_http_t *http;
const char *nonce;
int max_retries;
+ struct md_result_t *last; /* result of last request */
};
/**
* Global init, call once at start up.
*/
-apr_status_t md_acme_init(apr_pool_t *pool, const char *base_version);
+apr_status_t md_acme_init(apr_pool_t *pool, const char *base_version, int init_ssl);
/**
* Create a new ACME server instance. If path is not NULL, will use that directory
@@ -82,39 +151,68 @@ apr_status_t md_acme_init(apr_pool_t *pool, const char *base_version);
* @param proxy_url optional url of a HTTP(S) proxy to use
*/
apr_status_t md_acme_create(md_acme_t **pacme, apr_pool_t *p, const char *url,
- const char *proxy_url);
+ const char *proxy_url, const char *ca_file);
/**
* Contact the ACME server and retrieve its directory information.
*
* @param acme the ACME server to contact
*/
-apr_status_t md_acme_setup(md_acme_t *acme);
+apr_status_t md_acme_setup(md_acme_t *acme, struct md_result_t *result);
+
+void md_acme_report_result(md_acme_t *acme, apr_status_t rv, struct md_result_t *result);
/**************************************************************************************************/
/* account handling */
-#define MD_ACME_ACCT_STAGED "staged"
+/**
+ * Clear any existing account data from acme instance.
+ */
+void md_acme_clear_acct(md_acme_t *acme);
+
+apr_status_t md_acme_POST_new_account(md_acme_t *acme,
+ md_acme_req_init_cb *on_init,
+ md_acme_req_json_cb *on_json,
+ md_acme_req_res_cb *on_res,
+ md_acme_req_err_cb *on_err,
+ void *baton);
-apr_status_t md_acme_acct_load(struct md_acme_acct_t **pacct, struct md_pkey_t **ppkey,
- struct md_store_t *store, md_store_group_t group,
- const char *name, apr_pool_t *p);
+/**
+ * Get the local name of the account currently used by the acme instance.
+ * Will be NULL if no account has been setup successfully.
+ */
+const char *md_acme_acct_id_get(md_acme_t *acme);
+const char *md_acme_acct_url_get(md_acme_t *acme);
/**
* Specify the account to use by name in local store. On success, the account
- * the "current" one used by the acme instance.
+ * is the "current" one used by the acme instance.
+ * @param acme the acme instance to set the account for
+ * @param store the store to load accounts from
+ * @param p pool for allocations
+ * @param acct_id name of the account to load
*/
apr_status_t md_acme_use_acct(md_acme_t *acme, struct md_store_t *store,
apr_pool_t *p, const char *acct_id);
-apr_status_t md_acme_use_acct_staged(md_acme_t *acme, struct md_store_t *store,
- md_t *md, apr_pool_t *p);
+/**
+ * Specify the account to use for a specific MD by name in local store.
+ * On success, the account is the "current" one used by the acme instance.
+ * @param acme the acme instance to set the account for
+ * @param store the store to load accounts from
+ * @param p pool for allocations
+ * @param acct_id name of the account to load
+ * @param md the MD the account shall be used for
+ */
+apr_status_t md_acme_use_acct_for_md(md_acme_t *acme, struct md_store_t *store,
+ apr_pool_t *p, const char *acct_id,
+ const md_t *md);
/**
* Get the local name of the account currently used by the acme instance.
* Will be NULL if no account has been setup successfully.
*/
-const char *md_acme_get_acct_id(md_acme_t *acme);
+const char *md_acme_acct_id_get(md_acme_t *acme);
/**
* Agree to the given Terms-of-Service url for the current account.
@@ -136,78 +234,23 @@ apr_status_t md_acme_agree(md_acme_t *acme, apr_pool_t *p, const char *tos);
apr_status_t md_acme_check_agreement(md_acme_t *acme, apr_pool_t *p,
const char *agreement, const char **prequired);
-/**
- * Get the ToS agreement for current account.
- */
-const char *md_acme_get_agreement(md_acme_t *acme);
-
-
-/**
- * Find an existing account in the local store. On APR_SUCCESS, the acme
- * instance will have a current, validated account to use.
- */
-apr_status_t md_acme_find_acct(md_acme_t *acme, struct md_store_t *store, apr_pool_t *p);
-
-/**
- * Create a new account at the ACME server. The
- * new account is the one used by the acme instance afterwards, on success.
- */
-apr_status_t md_acme_create_acct(md_acme_t *acme, apr_pool_t *p, apr_array_header_t *contacts,
- const char *agreement);
-
-apr_status_t md_acme_acct_save(struct md_store_t *store, apr_pool_t *p, md_acme_t *acme,
- struct md_acme_acct_t *acct, struct md_pkey_t *acct_key);
+apr_status_t md_acme_save_acct(md_acme_t *acme, apr_pool_t *p, struct md_store_t *store);
-apr_status_t md_acme_save(md_acme_t *acme, struct md_store_t *store, apr_pool_t *p);
-
-apr_status_t md_acme_acct_save_staged(md_acme_t *acme, struct md_store_t *store,
- md_t *md, apr_pool_t *p);
-
/**
- * Delete the current account at the ACME server and remove it from store.
+ * Deactivate the current account at the ACME server..
*/
-apr_status_t md_acme_delete_acct(md_acme_t *acme, struct md_store_t *store, apr_pool_t *p);
-
-/**
- * Delete the account from the local store without contacting the ACME server.
- */
-apr_status_t md_acme_unstore_acct(struct md_store_t *store, apr_pool_t *p, const char *acct_id);
+apr_status_t md_acme_acct_deactivate(md_acme_t *acme, apr_pool_t *p);
/**************************************************************************************************/
/* request handling */
-/**
- * Request callback on a successful HTTP response (status 2xx).
- */
-typedef apr_status_t md_acme_req_res_cb(md_acme_t *acme,
- const struct md_http_response_t *res, void *baton);
-
-/**
- * A request against an ACME server
- */
-typedef struct md_acme_req_t md_acme_req_t;
-
-/**
- * Request callback to initialize before sending. May be invoked more than once in
- * case of retries.
- */
-typedef apr_status_t md_acme_req_init_cb(md_acme_req_t *req, void *baton);
-
-/**
- * Request callback on a successful response (HTTP response code 2xx) and content
- * type matching application/.*json.
- */
-typedef apr_status_t md_acme_req_json_cb(md_acme_t *acme, apr_pool_t *p,
- const apr_table_t *headers,
- struct md_json_t *jbody, void *baton);
-
struct md_acme_req_t {
md_acme_t *acme; /* the ACME server to talk to */
apr_pool_t *p; /* pool for the request duration */
const char *url; /* url to POST the request to */
const char *method; /* HTTP method to use */
- apr_table_t *prot_hdrs; /* JWS headers needing protection (nonce) */
+ struct md_json_t *prot_fields; /* JWS protected fields */
struct md_json_t *req_json; /* JSON to be POSTed in request body */
apr_table_t *resp_hdrs; /* HTTP response headers */
@@ -218,14 +261,19 @@ struct md_acme_req_t {
md_acme_req_init_cb *on_init; /* callback to initialize the request before submit */
md_acme_req_json_cb *on_json; /* callback on successful JSON response */
md_acme_req_res_cb *on_res; /* callback on generic HTTP response */
+ md_acme_req_err_cb *on_err; /* callback on encountered error */
int max_retries; /* how often this might be retried */
void *baton; /* userdata for callbacks */
+ struct md_result_t *result; /* result of this request */
};
+apr_status_t md_acme_req_body_init(md_acme_req_t *req, struct md_json_t *payload);
+
apr_status_t md_acme_GET(md_acme_t *acme, const char *url,
md_acme_req_init_cb *on_init,
md_acme_req_json_cb *on_json,
md_acme_req_res_cb *on_res,
+ md_acme_req_err_cb *on_err,
void *baton);
/**
* Perform a POST against the ACME url. If a on_json callback is given and
@@ -245,14 +293,9 @@ apr_status_t md_acme_POST(md_acme_t *acme, const char *url,
md_acme_req_init_cb *on_init,
md_acme_req_json_cb *on_json,
md_acme_req_res_cb *on_res,
+ md_acme_req_err_cb *on_err,
void *baton);
-apr_status_t md_acme_GET(md_acme_t *acme, const char *url,
- md_acme_req_init_cb *on_init,
- md_acme_req_json_cb *on_json,
- md_acme_req_res_cb *on_res,
- void *baton);
-
/**
* Retrieve a JSON resource from the ACME server
*/
@@ -264,4 +307,11 @@ apr_status_t md_acme_req_body_init(md_acme_req_t *req, struct md_json_t *jpayloa
apr_status_t md_acme_protos_add(struct apr_hash_t *protos, apr_pool_t *p);
+/**
+ * Return != 0 iff the given problem identifier is an ACME error string
+ * indicating something is wrong with the input values, e.g. from our
+ * configuration.
+ */
+int md_acme_problem_is_input_related(const char *problem);
+
#endif /* md_acme_h */