Apache HTTPD
md_acme_acct.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <assert.h>
18#include <stdio.h>
19
20#include <apr_lib.h>
21#include <apr_file_info.h>
22#include <apr_file_io.h>
23#include <apr_fnmatch.h>
24#include <apr_hash.h>
25#include <apr_strings.h>
26#include <apr_tables.h>
27
28#include "md.h"
29#include "md_crypt.h"
30#include "md_json.h"
31#include "md_jws.h"
32#include "md_log.h"
33#include "md_result.h"
34#include "md_store.h"
35#include "md_util.h"
36#include "md_version.h"
37
38#include "md_acme.h"
39#include "md_acme_acct.h"
40
42 const char *ca_url, apr_array_header_t *contacts)
43{
44 md_acme_acct_t *acct;
45
46 acct = apr_pcalloc(p, sizeof(*acct));
47 acct->ca_url = ca_url;
48 if (!contacts || apr_is_empty_array(contacts)) {
49 acct->contacts = apr_array_make(p, 5, sizeof(const char *));
50 }
51 else {
52 acct->contacts = apr_array_copy(p, contacts);
53 }
54
55 *pacct = acct;
56 return APR_SUCCESS;
57}
58
59
60static const char *mk_acct_id(apr_pool_t *p, md_acme_t *acme, int i)
61{
62 return apr_psprintf(p, "ACME-%s-%04d", acme->sname, i);
63}
64
65static const char *mk_acct_pattern(apr_pool_t *p, md_acme_t *acme)
66{
67 return apr_psprintf(p, "ACME-%s-*", acme->sname);
68}
69
70/**************************************************************************************************/
71/* json load/save */
72
74{
75 if (s) {
76 if (!strcmp("valid", s)) {
78 }
79 else if (!strcmp("deactivated", s)) {
81 }
82 else if (!strcmp("revoked", s)) {
84 }
85 }
87}
88
90{
92 const char *s;
93
94 assert(acct);
96 switch (acct->status) {
98 s = "valid";
99 break;
101 s = "deactivated";
102 break;
104 s = "revoked";
105 break;
106 default:
107 s = NULL;
108 break;
109 }
111 if (acct->url) md_json_sets(acct->url, jacct, MD_KEY_URL, NULL);
112 if (acct->ca_url) md_json_sets(acct->ca_url, jacct, MD_KEY_CA_URL, NULL);
116 if (acct->orders) md_json_sets(acct->orders, jacct, MD_KEY_ORDERS, NULL);
119
120 return jacct;
121}
122
124{
126 md_acme_acct_t *acct;
128 const char *ca_url, *url;
129 apr_array_header_t *contacts;
130
131 if (md_json_has_key(json, MD_KEY_STATUS, NULL)) {
133 }
134
136 if (!url) {
137 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, p, "account has no url");
138 goto leave;
139 }
140
141 ca_url = md_json_gets(json, MD_KEY_CA_URL, NULL);
142 if (!ca_url) {
143 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, p, "account has no CA url: %s", url);
144 goto leave;
145 }
146
147 contacts = apr_array_make(p, 5, sizeof(const char *));
148 if (md_json_has_key(json, MD_KEY_CONTACT, NULL)) {
149 md_json_getsa(contacts, json, MD_KEY_CONTACT, NULL);
150 }
151 else {
153 }
154 rv = acct_make(&acct, p, ca_url, contacts);
155 if (APR_SUCCESS != rv) goto leave;
156
157 acct->status = status;
158 acct->url = url;
160 if (!acct->agreement) {
161 /* backward compatible check */
162 acct->agreement = md_json_gets(json, "terms-of-service", NULL);
163 }
164 acct->orders = md_json_gets(json, MD_KEY_ORDERS, NULL);
169 }
170
171leave:
172 *pacct = (APR_SUCCESS == rv)? acct : NULL;
173 return rv;
174}
175
177 const char **pid, md_acme_acct_t *acct, md_pkey_t *acct_key)
178{
180 apr_status_t rv;
181 int i;
182 const char *id = pid? *pid : NULL;
183
185 if (id) {
187 }
188 else {
189 rv = APR_EAGAIN;
190 for (i = 0; i < 1000 && APR_SUCCESS != rv; ++i) {
191 id = mk_acct_id(p, acme, i);
193 }
194 }
195 if (APR_SUCCESS == rv) {
196 if (pid) *pid = id;
197 rv = md_store_save(store, p, MD_SG_ACCOUNTS, id, MD_FN_ACCT_KEY, MD_SV_PKEY, acct_key, 0);
198 }
199 return rv;
200}
201
203 md_store_t *store, md_store_group_t group,
204 const char *name, apr_pool_t *p)
205{
206 md_json_t *json;
207 apr_status_t rv;
208
209 rv = md_store_load_json(store, group, name, MD_FN_ACCOUNT, &json, p);
210 if (APR_STATUS_IS_ENOENT(rv)) {
211 goto out;
212 }
213 if (APR_SUCCESS != rv) {
214 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "error reading account: %s", name);
215 goto out;
216 }
217
218 rv = md_acme_acct_from_json(pacct, json, p);
219 if (APR_SUCCESS == rv) {
220 rv = md_store_load(store, group, name, MD_FN_ACCT_KEY, MD_SV_PKEY, (void**)ppkey, p);
221 if (APR_SUCCESS != rv) {
222 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "loading key: %s", name);
223 goto out;
224 }
225 }
226out:
227 if (APR_SUCCESS != rv) {
228 *pacct = NULL;
229 *ppkey = NULL;
230 }
231 return rv;
232}
233
234/**************************************************************************************************/
235/* Lookup */
236
238{
239 /* The ACME url must match exactly */
240 if (!url || !acct->ca_url || strcmp(acct->ca_url, url)) return 0;
241 return 1;
242}
243
245{
246 if (!md_acme_acct_matches_url(acct, md->ca_effective)) return 0;
247 /* if eab values are not mentioned, we match an account regardless
248 * if it was registered with eab or not */
249 if (!md->ca_eab_kid || !md->ca_eab_hmac) {
250 /* No eab only acceptable when no eab is asked for.
251 * This prevents someone that has no external account binding
252 * to re-use an account from another MDomain that was created
253 * with a binding. */
254 return !acct->eab_kid || !acct->eab_hmac;
255 }
256 /* But of eab is asked for, we need an acct that matches exactly.
257 * When someone configures a new EAB and we need
258 * to created a new account for it. */
259 if (!acct->eab_kid || !acct->eab_hmac) return 0;
260 return !strcmp(acct->eab_kid, md->ca_eab_kid)
261 && !strcmp(acct->eab_hmac, md->ca_eab_hmac);
262}
263
264typedef struct {
266 const md_t *md;
267 const char *id;
268} find_ctx;
269
270static int find_acct(void *baton, const char *name, const char *aspect,
271 md_store_vtype_t vtype, void *value, apr_pool_t *ptemp)
272{
273 find_ctx *ctx = baton;
274 md_acme_acct_t *acct;
275 apr_status_t rv;
276
277 (void)aspect;
278 (void)ptemp;
279 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, ctx->p, "account candidate %s/%s", name, aspect);
280 if (MD_SV_JSON == vtype) {
281 rv = md_acme_acct_from_json(&acct, (md_json_t*)value, ptemp);
282 if (APR_SUCCESS != rv) goto cleanup;
283
284 if (MD_ACME_ACCT_ST_VALID == acct->status
285 && (!ctx->md || md_acme_acct_matches_md(acct, ctx->md))) {
287 "found account %s for %s: %s, status=%d",
288 acct->id, ctx->md->ca_effective, aspect, acct->status);
289 ctx->id = apr_pstrdup(ctx->p, name);
290 return 0;
291 }
292 }
293cleanup:
294 return 1;
295}
296
298 md_store_t *store, md_store_group_t group,
299 const char *name_pattern,
300 const md_t *md, apr_pool_t *p)
301{
302 apr_status_t rv;
304
305 memset(&ctx, 0, sizeof(ctx));
306 ctx.p = p;
307 ctx.md = md;
308
310 if (ctx.id) {
311 *pid = ctx.id;
312 rv = md_acme_acct_load(pacct, ppkey, store, group, ctx.id, p);
313 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "acct_find: got account %s", ctx.id);
314 }
315 else {
316 *pacct = NULL;
317 rv = APR_ENOENT;
318 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, p, "acct_find: none found");
319 }
320 return rv;
321}
322
324 const char *name_pattern,
325 md_acme_t *acme, const md_t *md,
326 apr_pool_t *p)
327{
328 md_acme_acct_t *acct;
330 const char *id;
331 apr_status_t rv;
332
333 rv = acct_find(&id, &acct, &pkey, store, group, name_pattern, md, p);
334 if (APR_SUCCESS == rv) {
335 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, p, "acct_find_and_verify: found %s",
336 id);
337 acme->acct_id = (MD_SG_STAGING == group)? NULL : id;
338 acme->acct = acct;
339 acme->acct_key = pkey;
340 rv = md_acme_acct_validate(acme, (MD_SG_STAGING == group)? NULL : store, p);
341 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, rv, p, "acct_find_and_verify: verified %s",
342 id);
343
344 if (APR_SUCCESS != rv) {
345 acme->acct_id = NULL;
346 acme->acct = NULL;
347 acme->acct_key = NULL;
348 if (APR_STATUS_IS_ENOENT(rv)) {
349 /* verification failed and account has been disabled.
350 Indicate to caller that he may try again. */
351 rv = APR_EAGAIN;
352 }
353 }
354 }
355 return rv;
356}
357
359{
360 apr_status_t rv;
361
362 while (APR_EAGAIN == (rv = acct_find_and_verify(store, MD_SG_ACCOUNTS,
363 mk_acct_pattern(acme->p, acme),
364 acme, md, acme->p))) {
365 /* nop */
366 }
367
368 if (APR_STATUS_IS_ENOENT(rv)) {
369 /* No suitable account found in MD_SG_ACCOUNTS. Maybe a new account
370 * can already be found in MD_SG_STAGING? */
372 "no account found, looking in STAGING");
373 rv = acct_find_and_verify(store, MD_SG_STAGING, "*", acme, md, acme->p);
374 if (APR_EAGAIN == rv) {
375 rv = APR_ENOENT;
376 }
377 }
378 return rv;
379}
380
382 md_store_group_t group, const md_t *md,
383 apr_pool_t *p)
384{
385 apr_status_t rv;
387
388 memset(&ctx, 0, sizeof(ctx));
389 ctx.p = p;
390 ctx.md = md;
391
392 rv = md_store_iter(find_acct, &ctx, store, p, group, "*", MD_FN_ACCOUNT, MD_SV_JSON);
393 if (ctx.id) {
394 *pid = ctx.id;
395 rv = APR_SUCCESS;
396 }
397 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "acct_id_for_md %s -> %s", md->name, *pid);
398 return rv;
399}
400
401/**************************************************************************************************/
402/* acct operation context */
403typedef struct {
406 const char *agreement;
407 const char *eab_kid;
408 const char *eab_hmac;
409} acct_ctx_t;
410
411/**************************************************************************************************/
412/* acct update */
413
415{
416 (void)baton;
417 return md_acme_req_body_init(req, NULL);
418}
419
421 const apr_table_t *hdrs, md_json_t *body, void *baton)
422{
425 md_acme_acct_t *acct = acme->acct;
426
428 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE2, 0, acme->p, "acct update response: %s",
430 }
431
432 if (!acct->url) {
433 const char *location = apr_table_get(hdrs, "location");
434 if (!location) {
435 md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, APR_EINVAL, p, "new acct without location");
436 return APR_EINVAL;
437 }
438 acct->url = apr_pstrdup(ctx->p, location);
439 }
440
442 md_json_dupsa(acct->contacts, acme->p, body, MD_KEY_CONTACT, NULL);
443 if (md_json_has_key(body, MD_KEY_STATUS, NULL)) {
445 }
447 acct->agreement = md_json_dups(acme->p, body, MD_KEY_AGREEMENT, NULL);
448 }
449 if (md_json_has_key(body, MD_KEY_ORDERS, NULL)) {
450 acct->orders = md_json_dups(acme->p, body, MD_KEY_ORDERS, NULL);
451 }
452 if (ctx->eab_kid && ctx->eab_hmac) {
453 acct->eab_kid = ctx->eab_kid;
454 acct->eab_hmac = ctx->eab_hmac;
455 }
456 acct->registration = md_json_clone(ctx->p, body);
457
458 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "updated acct %s", acct->url);
459 return rv;
460}
461
463{
465
466 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, acme->p, "acct update");
467 if (!acme->acct) {
468 return APR_EINVAL;
469 }
470 memset(&ctx, 0, sizeof(ctx));
471 ctx.acme = acme;
472 ctx.p = acme->p;
473 return md_acme_POST(acme, acme->acct->url, on_init_acct_upd, acct_upd, NULL, NULL, &ctx);
474}
475
477{
478 apr_status_t rv;
479
480 if (APR_SUCCESS != (rv = md_acme_acct_update(acme))) {
482 "acct update failed for %s", acme->acct->url);
483 if (APR_EINVAL == rv && (acme->acct->agreement || !acme->ca_agreement)) {
484 /* Sadly, some proprietary ACME servers choke on empty POSTs
485 * on accounts. Try a faked ToS agreement. */
487 "trying acct update via ToS agreement");
488 rv = md_acme_agree(acme, p, "accepted");
489 }
490 if (acme->acct && (APR_ENOENT == rv || APR_EACCES == rv || APR_EINVAL == rv)) {
491 if (MD_ACME_ACCT_ST_VALID == acme->acct->status) {
493 if (store) {
494 md_acme_acct_save(store, p, acme, &acme->acct_id, acme->acct, acme->acct_key);
495 }
496 }
497 acme->acct = NULL;
498 acme->acct_key = NULL;
499 rv = APR_ENOENT;
500 }
501 }
502 return rv;
503}
504
505/**************************************************************************************************/
506/* Register a new account */
507
509 const char *hmac64, md_pkey_t *account_key,
510 const char *url)
511{
512 md_json_t *eab, *prot_fields, *jwk;
514 apr_status_t rv;
515
516 prot_fields = md_json_create(req->p);
517 md_json_sets(url, prot_fields, "url", NULL);
518 md_json_sets(kid, prot_fields, "kid", NULL);
519
520 rv = md_jws_get_jwk(&jwk, req->p, account_key);
521 if (APR_SUCCESS != rv) goto cleanup;
522
525 if (!payload.data) {
526 rv = APR_EINVAL;
527 goto cleanup;
528 }
529 payload.len = strlen(payload.data);
530
532 if (!hmac_key.len) {
533 rv = APR_EINVAL;
534 md_result_problem_set(req->result, rv, "apache:eab-hmac-invalid",
535 "external account binding HMAC value is not valid base64", NULL);
536 goto cleanup;
537 }
538
539 rv = md_jws_hmac(&eab, req->p, &payload, prot_fields, &hmac_key);
540 if (APR_SUCCESS != rv) {
541 md_result_problem_set(req->result, rv, "apache:eab-hmac-fail",
542 "external account binding MAC could not be computed", NULL);
543 }
544
545cleanup:
546 *peab = (APR_SUCCESS == rv)? eab : NULL;
547 return rv;
548}
549
551{
554 apr_status_t rv;
555
556 jpayload = md_json_create(req->p);
557 md_json_setsa(ctx->acme->acct->contacts, jpayload, MD_KEY_CONTACT, NULL);
558 if (ctx->agreement) {
559 md_json_setb(1, jpayload, "termsOfServiceAgreed", NULL);
560 }
561 if (ctx->eab_kid && ctx->eab_hmac) {
562 rv = get_eab(&jeab, req, ctx->eab_kid, ctx->eab_hmac,
563 req->acme->acct_key, req->url);
564 if (APR_SUCCESS != rv) goto cleanup;
565 md_json_setj(jeab, jpayload, "externalAccountBinding", NULL);
566 }
568
569cleanup:
570 return rv;
571}
572
574 const md_t *md, apr_pool_t *p)
575{
576 apr_status_t rv;
578 const char *err = NULL, *uri;
579 md_pkey_spec_t spec;
580 int i;
582
583 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, p, "create new account");
584
585 memset(&ctx, 0, sizeof(ctx));
586 ctx.acme = acme;
587 ctx.p = p;
588 /* The agreement URL is submitted when the ACME server announces Terms-of-Service
589 * in its directory meta data. The magic value "accepted" will always use the
590 * advertised URL. */
591 ctx.agreement = NULL;
592 if (acme->ca_agreement && md->ca_agreement) {
593 ctx.agreement = !strcmp("accepted", md->ca_agreement)?
594 acme->ca_agreement : md->ca_agreement;
595 }
596
597 if (ctx.agreement) {
598 if (APR_SUCCESS != (rv = md_util_abs_uri_check(acme->p, ctx.agreement, &err))) {
600 "invalid agreement uri (%s): %s", err, ctx.agreement);
601 goto out;
602 }
603 }
604 ctx.eab_kid = md->ca_eab_kid;
605 ctx.eab_hmac = md->ca_eab_hmac;
606
607 for (i = 0; i < md->contacts->nelts; ++i) {
608 uri = APR_ARRAY_IDX(md->contacts, i, const char *);
609 if (APR_SUCCESS != (rv = md_util_abs_uri_check(acme->p, uri, &err))) {
611 "invalid contact uri (%s): %s", err, uri);
612 goto out;
613 }
614 }
615
616 /* If there is no key selected yet, try to find an existing one for the same host.
617 * Let's Encrypt identifies accounts by their key for their ACMEv1 and v2 services.
618 * Although the account appears on both services with different urls, it is
619 * internally the same one.
620 * I think this is beneficial if someone migrates from ACMEv1 to v2 and not a leak
621 * of identifying information.
622 */
623 if (!acme->acct_key) {
624 find_ctx fctx;
625
626 memset(&fctx, 0, sizeof(fctx));
627 fctx.p = p;
628 fctx.md = md;
629
630 md_store_iter(find_acct, &fctx, store, p, MD_SG_ACCOUNTS,
632 if (fctx.id) {
634 (void**)&acme->acct_key, p);
635 if (APR_SUCCESS == rv) {
637 "reusing key from account %s", fctx.id);
638 }
639 else {
640 acme->acct_key = NULL;
641 }
642 }
643 }
644
645 /* If we still have no key, generate a new one */
646 if (!acme->acct_key) {
647 spec.type = MD_PKEY_TYPE_RSA;
649
650 if (APR_SUCCESS != (rv = md_pkey_gen(&pkey, acme->p, &spec))) goto out;
651 acme->acct_key = pkey;
652 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "created new account key");
653 }
654
655 if (APR_SUCCESS != (rv = acct_make(&acme->acct, p, acme->url, md->contacts))) goto out;
657 if (APR_SUCCESS == rv) {
659 "registered new account %s", acme->acct->url);
660 }
661
662out:
663 if (APR_SUCCESS != rv && acme->acct) {
664 acme->acct = NULL;
665 }
666 return rv;
667}
668
669/**************************************************************************************************/
670/* Deactivate the account */
671
673{
675
676 (void)baton;
677 jpayload = md_json_create(req->p);
678 md_json_sets("deactivated", jpayload, MD_KEY_STATUS, NULL);
679 return md_acme_req_body_init(req, jpayload);
680}
681
683{
684 md_acme_acct_t *acct = acme->acct;
686
687 (void)p;
688 if (!acct) {
689 return APR_EINVAL;
690 }
691 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, acme->p, "delete account %s from %s",
692 acct->url, acct->ca_url);
693 memset(&ctx, 0, sizeof(ctx));
694 ctx.acme = acme;
695 ctx.p = p;
696 return md_acme_POST(acme, acct->url, on_init_acct_del, acct_upd, NULL, NULL, &ctx);
697}
698
699/**************************************************************************************************/
700/* terms-of-service */
701
703{
706
707 jpayload = md_json_create(req->p);
708 if (ctx->acme->acct->agreement) {
709 md_json_setb(1, jpayload, "termsOfServiceAgreed", NULL);
710 }
711 return md_acme_req_body_init(req, jpayload);
712}
713
714apr_status_t md_acme_agree(md_acme_t *acme, apr_pool_t *p, const char *agreement)
715{
717
718 acme->acct->agreement = agreement;
719 if (!strcmp("accepted", agreement) && acme->ca_agreement) {
720 acme->acct->agreement = acme->ca_agreement;
721 }
722
723 memset(&ctx, 0, sizeof(ctx));
724 ctx.acme = acme;
725 ctx.p = p;
726 return md_acme_POST(acme, acme->acct->url, on_init_agree_tos, acct_upd, NULL, NULL, &ctx);
727}
728
730 const char *agreement, const char **prequired)
731{
733
734 /* We used to really check if the account agreement and the one indicated in meta
735 * are the very same. However, LE is happy if the account has agreed to a ToS in
736 * the past and does not require a renewed acceptance.
737 */
738 *prequired = NULL;
739 if (!acme->acct->agreement && acme->ca_agreement) {
740 if (agreement) {
741 rv = md_acme_agree(acme, p, acme->ca_agreement);
742 }
743 else {
744 *prequired = acme->ca_agreement;
745 rv = APR_INCOMPLETE;
746 }
747 }
748 return rv;
749}
APR File Information.
APR File I/O Handling.
APR FNMatch Functions.
APR Hash Tables.
APR general purpose library routines.
APR Strings library.
APR Table library.
ap_vhost_iterate_conn_cb void * baton
Definition http_vhost.h:87
#define APR_EAGAIN
Definition apr_errno.h:730
#define APR_EACCES
Definition apr_errno.h:641
#define APR_INCOMPLETE
Definition apr_errno.h:452
#define APR_ENOENT
Definition apr_errno.h:662
#define APR_EINVAL
Definition apr_errno.h:711
#define APR_STATUS_IS_ENOENT(s)
Definition apr_errno.h:1246
apr_brigade_flush void * ctx
apr_datum_t * pkey
Definition apr_dbm.h:158
const char * url
Definition apr_escape.h:120
const char * uri
Definition apr_uri.h:159
apr_size_t size
const char * value
Definition apr_env.h:51
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
void const char apr_status_t(* cleanup)(void *))
const char apr_uint32_t * id
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const char * s
Definition apr_strings.h:95
#define APR_ARRAY_IDX(ary, i, type)
Definition apr_tables.h:141
apr_int32_t apr_int32_t apr_int32_t err
int int status
#define MD_KEY_HMAC
Definition md.h:152
#define MD_KEY_URL
Definition md.h:207
#define MD_KEY_ORDERS
Definition md.h:173
#define MD_KEY_STATUS
Definition md.h:196
#define MD_KEY_KID
Definition md.h:158
#define MD_KEY_EAB
Definition md.h:141
#define MD_KEY_AGREEMENT
Definition md.h:119
#define MD_KEY_CA_URL
Definition md.h:123
#define MD_KEY_REGISTRATION
Definition md.h:180
#define MD_KEY_CONTACT
Definition md.h:132
apr_status_t md_acme_req_body_init(md_acme_req_t *req, md_json_t *payload)
Definition md_acme.c:250
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)
Definition md_acme.c:607
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)
Definition md_acme.c:432
static apr_status_t get_eab(md_json_t **peab, md_acme_req_t *req, const char *kid, const char *hmac64, md_pkey_t *account_key, const char *url)
apr_status_t md_acme_acct_save(md_store_t *store, apr_pool_t *p, md_acme_t *acme, const char **pid, md_acme_acct_t *acct, md_pkey_t *acct_key)
static apr_status_t on_init_agree_tos(md_acme_req_t *req, void *baton)
static const char * mk_acct_pattern(apr_pool_t *p, md_acme_t *acme)
static md_acme_acct_st acct_st_from_str(const char *s)
int md_acme_acct_matches_md(md_acme_acct_t *acct, const md_t *md)
apr_status_t md_acme_acct_load(md_acme_acct_t **pacct, md_pkey_t **ppkey, md_store_t *store, md_store_group_t group, const char *name, apr_pool_t *p)
static apr_status_t on_init_acct_del(md_acme_req_t *req, void *baton)
int md_acme_acct_matches_url(md_acme_acct_t *acct, const char *url)
apr_status_t md_acme_acct_from_json(md_acme_acct_t **pacct, md_json_t *json, apr_pool_t *p)
apr_status_t md_acme_acct_validate(md_acme_t *acme, md_store_t *store, apr_pool_t *p)
apr_status_t md_acme_acct_deactivate(md_acme_t *acme, apr_pool_t *p)
static apr_status_t acct_make(md_acme_acct_t **pacct, apr_pool_t *p, const char *ca_url, apr_array_header_t *contacts)
apr_status_t md_acme_acct_id_for_md(const char **pid, md_store_t *store, md_store_group_t group, const md_t *md, apr_pool_t *p)
static apr_status_t acct_find(const char **pid, md_acme_acct_t **pacct, md_pkey_t **ppkey, md_store_t *store, md_store_group_t group, const char *name_pattern, const md_t *md, apr_pool_t *p)
md_json_t * md_acme_acct_to_json(md_acme_acct_t *acct, apr_pool_t *p)
apr_status_t md_acme_agree(md_acme_t *acme, apr_pool_t *p, const char *agreement)
static apr_status_t acct_upd(md_acme_t *acme, apr_pool_t *p, const apr_table_t *hdrs, md_json_t *body, void *baton)
static const char * mk_acct_id(apr_pool_t *p, md_acme_t *acme, int i)
apr_status_t md_acme_check_agreement(md_acme_t *acme, apr_pool_t *p, const char *agreement, const char **prequired)
apr_status_t md_acme_find_acct_for_md(md_acme_t *acme, md_store_t *store, const md_t *md)
apr_status_t md_acme_acct_register(md_acme_t *acme, md_store_t *store, const md_t *md, apr_pool_t *p)
apr_status_t md_acme_acct_update(md_acme_t *acme)
static apr_status_t acct_find_and_verify(md_store_t *store, md_store_group_t group, const char *name_pattern, md_acme_t *acme, const md_t *md, apr_pool_t *p)
static int find_acct(void *baton, const char *name, const char *aspect, md_store_vtype_t vtype, void *value, apr_pool_t *ptemp)
static apr_status_t on_init_acct_new(md_acme_req_t *req, void *baton)
static apr_status_t on_init_acct_upd(md_acme_req_t *req, void *baton)
#define MD_ACME_ACCT_PKEY_BITS
md_acme_acct_st
@ MD_ACME_ACCT_ST_DEACTIVATED
@ MD_ACME_ACCT_ST_REVOKED
@ MD_ACME_ACCT_ST_UNKNOWN
@ MD_ACME_ACCT_ST_VALID
#define MD_FN_ACCT_KEY
#define MD_FN_ACCOUNT
apr_status_t md_pkey_gen(md_pkey_t **ppkey, apr_pool_t *p, md_pkey_spec_t *spec)
Definition md_crypt.c:933
@ MD_PKEY_TYPE_RSA
Definition md_crypt.h:51
apr_pool_t * p
Definition md_event.c:32
md_json_t * md_json_create(apr_pool_t *pool)
Definition md_json.c:92
apr_status_t md_json_getsa(apr_array_header_t *a, const md_json_t *json,...)
Definition md_json.c:864
apr_status_t md_json_sets(const char *value, md_json_t *json,...)
Definition md_json.c:430
const char * md_json_gets(const md_json_t *json,...)
Definition md_json.c:406
md_json_t * md_json_clone(apr_pool_t *pool, const md_json_t *json)
Definition md_json.c:116
apr_status_t md_json_dupsa(apr_array_header_t *a, apr_pool_t *p, md_json_t *json,...)
Definition md_json.c:887
apr_status_t md_json_setj(const md_json_t *value, md_json_t *json,...)
Definition md_json.c:527
int md_json_has_key(const md_json_t *json,...)
Definition md_json.c:279
apr_status_t md_json_setb(int value, md_json_t *json,...)
Definition md_json.c:342
const char * md_json_dups(apr_pool_t *p, const md_json_t *json,...)
Definition md_json.c:418
apr_status_t md_json_setsa(apr_array_header_t *a, md_json_t *json,...)
Definition md_json.c:911
const char * md_json_writep(const md_json_t *json, apr_pool_t *p, md_json_fmt_t fmt)
Definition md_json.c:992
@ MD_JSON_FMT_COMPACT
Definition md_json.h:43
apr_status_t md_jws_hmac(md_json_t **pmsg, apr_pool_t *p, md_data_t *payload, md_json_t *prot_fields, const md_data_t *hmac_key)
Definition md_jws.c:112
apr_status_t md_jws_get_jwk(md_json_t **pjwk, apr_pool_t *p, struct md_pkey_t *pkey)
Definition md_jws.c:28
void md_log_perror(const char *file, int line, md_log_level_t level, apr_status_t rv, apr_pool_t *p, const char *fmt,...)
Definition md_log.c:68
int md_log_is_level(apr_pool_t *p, md_log_level_t level)
Definition md_log.c:60
#define MD_LOG_MARK
Definition md_log.h:39
@ MD_LOG_TRACE2
Definition md_log.h:30
@ MD_LOG_TRACE1
Definition md_log.h:29
@ MD_LOG_ERR
Definition md_log.h:24
@ MD_LOG_WARNING
Definition md_log.h:25
@ MD_LOG_DEBUG
Definition md_log.h:28
@ MD_LOG_INFO
Definition md_log.h:27
void md_result_problem_set(md_result_t *result, apr_status_t status, const char *problem, const char *detail, const md_json_t *subproblems)
Definition md_result.c:100
apr_status_t md_store_save(md_store_t *store, apr_pool_t *p, md_store_group_t group, const char *name, const char *aspect, md_store_vtype_t vtype, void *data, int create)
Definition md_store.c:78
apr_status_t md_store_iter(md_store_inspect *inspect, void *baton, md_store_t *store, apr_pool_t *p, md_store_group_t group, const char *pattern, const char *aspect, md_store_vtype_t vtype)
Definition md_store.c:99
apr_status_t md_store_load_json(md_store_t *store, md_store_group_t group, const char *name, const char *aspect, struct md_json_t **pdata, apr_pool_t *p)
Definition md_store.c:106
apr_status_t md_store_load(md_store_t *store, md_store_group_t group, const char *name, const char *aspect, md_store_vtype_t vtype, void **pdata, apr_pool_t *p)
Definition md_store.c:70
md_store_group_t
Definition md_store.h:62
@ MD_SG_ACCOUNTS
Definition md_store.h:64
@ MD_SG_STAGING
Definition md_store.h:67
md_store_vtype_t
Definition md_store.h:52
@ MD_SV_PKEY
Definition md_store.h:56
@ MD_SV_JSON
Definition md_store.h:54
apr_size_t md_util_base64url_decode(md_data_t *decoded, const char *encoded, apr_pool_t *pool)
Definition md_util.c:1157
apr_status_t md_util_abs_uri_check(apr_pool_t *p, const char *uri, const char **perr)
Definition md_util.c:1005
void md_data_null(md_data_t *d)
Definition md_util.c:107
static apr_file_t * out
Definition mod_info.c:85
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
char * name
md_acme_t * acme
const char * eab_hmac
const char * eab_kid
const char * agreement
apr_pool_t * p
const md_t * md
apr_pool_t * p
const char * id
const char * agreement
apr_array_header_t * contacts
const char * ca_url
const char * eab_hmac
const char * orders
const char * eab_kid
md_acme_acct_st status
const char * id
const char * url
struct md_json_t * registration
apr_pool_t * p
Definition md_acme.h:249
struct md_result_t * result
Definition md_acme.h:267
const char * url
Definition md_acme.h:251
md_acme_t * acme
Definition md_acme.h:248
apr_pool_t * p
Definition md_acme.h:97
const char * ca_agreement
Definition md_acme.h:123
struct md_acme_acct_t * acct
Definition md_acme.h:103
const char * url
Definition md_acme.h:95
struct md_pkey_t * acct_key
Definition md_acme.h:104
const char * sname
Definition md_acme.h:96
const char * acct_id
Definition md_acme.h:102
apr_uint32_t bits
Definition md_crypt.h:56
md_pkey_type_t type
Definition md_crypt.h:64
md_pkey_rsa_params_t rsa
Definition md_crypt.h:66
union md_pkey_spec_t::@24 params
Definition md.h:76
const char * name
Definition md.h:77
const char * ca_eab_hmac
Definition md.h:94
const char * ca_effective
Definition md.h:87
const char * ca_eab_kid
Definition md.h:93
const char * ca_agreement
Definition md.h:89
struct apr_array_header_t * contacts
Definition md.h:79