Apache HTTPD
md_acme.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 <stdlib.h>
19
20#include <apr_lib.h>
21#include <apr_strings.h>
22#include <apr_buckets.h>
23#include <apr_hash.h>
24#include <apr_uri.h>
25
26#include "md.h"
27#include "md_crypt.h"
28#include "md_json.h"
29#include "md_jws.h"
30#include "md_http.h"
31#include "md_log.h"
32#include "md_store.h"
33#include "md_result.h"
34#include "md_util.h"
35#include "md_version.h"
36
37#include "md_acme.h"
38#include "md_acme_acct.h"
39
40
41static const char *base_product= "-";
42
44
46 const char *type; /* the ACME error string */
47 apr_status_t rv; /* what Apache status code we give it */
48 int input_related; /* if error indicates wrong input value */
49};
50
52 { "acme:error:badCSR", APR_EINVAL, 1 },
53 { "acme:error:badNonce", APR_EAGAIN, 0 },
54 { "acme:error:badSignatureAlgorithm", APR_EINVAL, 1 },
55 { "acme:error:externalAccountRequired", APR_EINVAL, 1 },
56 { "acme:error:invalidContact", APR_BADARG, 1 },
57 { "acme:error:unsupportedContact", APR_EGENERAL, 1 },
58 { "acme:error:malformed", APR_EINVAL, 1 },
59 { "acme:error:rateLimited", APR_BADARG, 0 },
60 { "acme:error:rejectedIdentifier", APR_BADARG, 1 },
61 { "acme:error:serverInternal", APR_EGENERAL, 0 },
62 { "acme:error:unauthorized", APR_EACCES, 0 },
63 { "acme:error:unsupportedIdentifier", APR_BADARG, 1 },
64 { "acme:error:userActionRequired", APR_EAGAIN, 0 },
65 { "acme:error:badRevocationReason", APR_EINVAL, 1 },
66 { "acme:error:caa", APR_EGENERAL, 0 },
67 { "acme:error:dns", APR_EGENERAL, 0 },
68 { "acme:error:connection", APR_EGENERAL, 0 },
69 { "acme:error:tls", APR_EGENERAL, 0 },
70 { "acme:error:incorrectResponse", APR_EGENERAL, 0 },
71};
72
74 size_t i;
75
76 if (strstr(type, "urn:ietf:params:") == type) {
77 type += strlen("urn:ietf:params:");
78 }
79 else if (strstr(type, "urn:") == type) {
80 type += strlen("urn:");
81 }
82
83 for(i = 0; i < (sizeof(Problems)/sizeof(Problems[0])); ++i) {
85 return Problems[i].rv;
86 }
87 }
88 return APR_EGENERAL;
89}
90
91int md_acme_problem_is_input_related(const char *problem) {
92 size_t i;
93
94 if (!problem) return 0;
95 if (strstr(problem, "urn:ietf:params:") == problem) {
96 problem += strlen("urn:ietf:params:");
97 }
98 else if (strstr(problem, "urn:") == problem) {
99 problem += strlen("urn:");
100 }
101
102 for(i = 0; i < (sizeof(Problems)/sizeof(Problems[0])); ++i) {
103 if (!apr_strnatcasecmp(problem, Problems[i].type)) {
104 return Problems[i].input_related;
105 }
106 }
107 return 0;
108}
109
110/**************************************************************************************************/
111/* acme requests */
112
113static void req_update_nonce(md_acme_t *acme, apr_table_t *hdrs)
114{
115 if (hdrs) {
116 const char *nonce = apr_table_get(hdrs, "Replay-Nonce");
117 if (nonce) {
118 acme->nonce = apr_pstrdup(acme->p, nonce);
119 }
120 }
121}
122
124{
125 req_update_nonce(data, res->headers);
126 return APR_SUCCESS;
127}
128
129static md_acme_req_t *md_acme_req_create(md_acme_t *acme, const char *method, const char *url)
130{
132 md_acme_req_t *req;
133 apr_status_t rv;
134
135 rv = apr_pool_create(&pool, acme->p);
136 if (rv != APR_SUCCESS) {
137 return NULL;
138 }
139 apr_pool_tag(pool, "md_acme_req");
140
141 req = apr_pcalloc(pool, sizeof(*req));
142 if (!req) {
144 return NULL;
145 }
146
147 req->acme = acme;
148 req->p = pool;
149 req->method = method;
150 req->url = url;
152 req->max_retries = acme->max_retries;
153 req->result = md_result_make(req->p, APR_SUCCESS);
154 return req;
155}
156
158{
159 return md_http_HEAD_perform(acme->http, acme->api.v2.new_nonce, NULL, http_update_nonce, acme);
160}
161
162
168
170{
171 const char *ctype;
172 md_json_t *problem = NULL;
173 apr_status_t rv;
174
175 ctype = apr_table_get(req->resp_hdrs, "content-type");
176 ctype = md_util_parse_ct(res->req->pool, ctype);
177 if (ctype && !strcmp(ctype, "application/problem+json")) {
178 /* RFC 7807 */
179 rv = md_json_read_http(&problem, req->p, res);
180 if (rv == APR_SUCCESS && problem) {
181 const char *ptype, *pdetail;
182
183 req->resp_json = problem;
184 ptype = md_json_gets(problem, MD_KEY_TYPE, NULL);
186 req->rv = problem_status_get(ptype);
187 md_result_problem_set(req->result, req->rv, ptype, pdetail,
189
190
191
192 if (APR_STATUS_IS_EAGAIN(req->rv)) {
194 "acme reports %s: %s", ptype, pdetail);
195 }
196 else {
198 "acme problem %s: %s", ptype, pdetail);
199 }
200 return req->rv;
201 }
202 }
203
204 switch (res->status) {
205 case 400:
206 return APR_EINVAL;
207 case 401: /* sectigo returns this instead of 403 */
208 case 403:
209 return APR_EACCES;
210 case 404:
211 return APR_ENOENT;
212 default:
214 "acme problem unknown: http status %d", res->status);
215 md_result_printf(req->result, APR_EGENERAL, "unexpected http status: %d",
216 res->status);
217 return req->result->status;
218 }
219 return APR_SUCCESS;
220}
221
222/**************************************************************************************************/
223/* ACME requests with nonce handling */
224
226{
228
230 if (!req->acme->acct) {
231 return APR_EINVAL;
232 }
233 if (jpayload) {
235 if (!payload.data) {
236 return APR_EINVAL;
237 }
238 }
239 else {
240 payload.data = "";
241 }
242
243 payload.len = strlen(payload.data);
245 "acme payload(len=%" APR_SIZE_T_FMT "): %s", payload.len, payload.data);
246 return md_jws_sign(&req->req_json, req->p, &payload,
247 req->prot_fields, req->acme->acct_key, req->acme->acct->url);
248}
249
254
256{
257 if (req->result->status != APR_SUCCESS) {
258 if (req->on_err) {
259 req->on_err(req, req->result, req->baton);
260 }
261 }
262 /* An error in rv superceeds the result->status */
263 if (APR_SUCCESS != rv) req->result->status = rv;
264 rv = req->result->status;
265 /* transfer results into the acme's central result for longer life and later inspection */
266 md_result_dup(req->acme->last, req->result);
267 if (req->p) {
268 apr_pool_destroy(req->p);
269 }
270 return rv;
271}
272
274{
275 md_acme_req_t *req = data;
277
278 req->resp_hdrs = apr_table_clone(req->p, res->headers);
279 req_update_nonce(req->acme, res->headers);
280
281 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, rv, req->p, "response: %d", res->status);
282 if (res->status >= 200 && res->status < 300) {
283 int processed = 0;
284
285 if (req->on_json) {
286 processed = 1;
287 rv = md_json_read_http(&req->resp_json, req->p, res);
288 if (APR_SUCCESS == rv) {
289 if (md_log_is_level(req->p, MD_LOG_TRACE2)) {
290 const char *s;
293 "response: %s",
294 s ? s : "<failed to serialize!>");
295 }
296 rv = req->on_json(req->acme, req->p, req->resp_hdrs, req->resp_json, req->baton);
297 }
298 else if (APR_STATUS_IS_ENOENT(rv)) {
299 /* not JSON content, fall through */
300 processed = 0;
301 }
302 else {
303 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, req->p, "parsing JSON body");
304 }
305 }
306
307 if (!processed && req->on_res) {
308 processed = 1;
309 rv = req->on_res(req->acme, res, req->baton);
310 }
311
312 if (!processed) {
313 rv = APR_EINVAL;
314 md_result_printf(req->result, rv, "unable to process the response: "
315 "http-status=%d, content-type=%s",
316 res->status, apr_table_get(res->headers, "Content-Type"));
318 }
319 }
320 else if (APR_EAGAIN == (rv = inspect_problem(req, res))) {
321 /* leave req alive */
322 return rv;
323 }
324
325 md_acme_req_done(req, rv);
326 return rv;
327}
328
330{
331 (void)baton;
332 return md_acme_req_body_init(req, NULL);
333}
334
336{
337 apr_status_t rv;
338 md_acme_t *acme = req->acme;
339 md_data_t *body = NULL;
341
342 assert(acme->url);
343
345 "sending req: %s %s", req->method, req->url);
348
349 /* Whom are we talking to? */
350 if (acme->version == MD_ACME_VERSION_UNKNOWN) {
351 rv = md_acme_setup(acme, result);
352 if (APR_SUCCESS != rv) goto leave;
353 }
354
355 if (!strcmp("GET", req->method) && !req->on_init && !req->req_json) {
356 /* See <https://ietf-wg-acme.github.io/acme/draft-ietf-acme-acme.html#rfc.section.6.3>
357 * and <https://mailarchive.ietf.org/arch/msg/acme/sotffSQ0OWV-qQJodLwWYWcEVKI>
358 * and <https://community.letsencrypt.org/t/acme-v2-scheduled-deprecation-of-unauthenticated-resource-gets/74380>
359 * We implement this change in ACMEv2 and higher as keeping the md_acme_GET() methods,
360 * but switching them to POSTs with a empty, JWS signed, body when we call
361 * our HTTP client. */
362 req->method = "POST";
364 /*req->max_retries = 0; don't do retries on these "GET"s */
365 }
366
367 /* Besides GET/HEAD, we always need a fresh nonce */
368 if (strcmp("GET", req->method) && strcmp("HEAD", req->method)) {
369 if (acme->version == MD_ACME_VERSION_UNKNOWN) {
370 rv = md_acme_setup(acme, result);
371 if (APR_SUCCESS != rv) goto leave;
372 }
373 if (!acme->nonce && (APR_SUCCESS != (rv = acme->new_nonce_fn(acme)))) {
375 "error retrieving new nonce from ACME server");
376 goto leave;
377 }
378
379 md_json_sets(acme->nonce, req->prot_fields, "nonce", NULL);
380 md_json_sets(req->url, req->prot_fields, "url", NULL);
381 acme->nonce = NULL;
382 }
383
384 rv = req->on_init? req->on_init(req, req->baton) : APR_SUCCESS;
385 if (APR_SUCCESS != rv) goto leave;
386
387 if (req->req_json) {
388 body = apr_pcalloc(req->p, sizeof(*body));
389 body->data = md_json_writep(req->req_json, req->p, MD_JSON_FMT_INDENT);
390 body->len = strlen(body->data);
392 "sending JSON body: %s", body->data);
393 }
394
395 if (body && md_log_is_level(req->p, MD_LOG_TRACE4)) {
397 "req: %s %s, body:\n%s", req->method, req->url, body->data);
398 }
399 else {
401 "req: %s %s", req->method, req->url);
402 }
403
404 if (!strcmp("GET", req->method)) {
405 rv = md_http_GET_perform(req->acme->http, req->url, NULL, on_response, req);
406 }
407 else if (!strcmp("POST", req->method)) {
408 rv = md_http_POSTd_perform(req->acme->http, req->url, NULL, "application/jose+json",
409 body, on_response, req);
410 }
411 else if (!strcmp("HEAD", req->method)) {
412 rv = md_http_HEAD_perform(req->acme->http, req->url, NULL, on_response, req);
413 }
414 else {
416 "HTTP method %s against: %s", req->method, req->url);
417 rv = APR_ENOTIMPL;
418 }
419 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, req->p, "req sent");
420
421 if (APR_EAGAIN == rv && req->max_retries > 0) {
422 --req->max_retries;
423 rv = md_acme_req_send(req);
424 }
425 req = NULL;
426
427leave:
428 if (req) md_acme_req_done(req, rv);
429 return rv;
430}
431
433 md_acme_req_init_cb *on_init,
434 md_acme_req_json_cb *on_json,
435 md_acme_req_res_cb *on_res,
436 md_acme_req_err_cb *on_err,
437 void *baton)
438{
439 md_acme_req_t *req;
440
441 assert(url);
442 assert(on_json || on_res);
443
444 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, acme->p, "add acme POST: %s", url);
445 req = md_acme_req_create(acme, "POST", url);
446 req->on_init = on_init;
447 req->on_json = on_json;
448 req->on_res = on_res;
449 req->on_err = on_err;
450 req->baton = baton;
451
452 return md_acme_req_send(req);
453}
454
456 md_acme_req_init_cb *on_init,
457 md_acme_req_json_cb *on_json,
458 md_acme_req_res_cb *on_res,
459 md_acme_req_err_cb *on_err,
460 void *baton)
461{
462 md_acme_req_t *req;
463
464 assert(url);
465 assert(on_json || on_res);
466
467 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, acme->p, "add acme GET: %s", url);
468 req = md_acme_req_create(acme, "GET", url);
469 req->on_init = on_init;
470 req->on_json = on_json;
471 req->on_res = on_res;
472 req->on_err = on_err;
473 req->baton = baton;
474
475 return md_acme_req_send(req);
476}
477
479{
480 if (acme->last->status == APR_SUCCESS) {
482 }
483 else {
485 acme->last->detail, acme->last->subproblems);
486 }
487}
488
489/**************************************************************************************************/
490/* GET JSON */
491
492typedef struct {
495} json_ctx;
496
498 md_json_t *jbody, void *baton)
499{
500 json_ctx *ctx = baton;
501
502 (void)acme;
503 (void)p;
504 (void)headers;
505 ctx->json = md_json_clone(ctx->pool, jbody);
506 return APR_SUCCESS;
507}
508
510 const char *url, apr_pool_t *p)
511{
512 apr_status_t rv;
514
515 ctx.pool = p;
516 ctx.json = NULL;
517
518 rv = md_acme_GET(acme, url, NULL, on_got_json, NULL, NULL, &ctx);
519 *pjson = (APR_SUCCESS == rv)? ctx.json : NULL;
520 return rv;
521}
522
523/**************************************************************************************************/
524/* Generic ACME operations */
525
527{
528 acme->acct_id = NULL;
529 acme->acct = NULL;
530 acme->acct_key = NULL;
531}
532
534{
535 return acme->acct_id;
536}
537
539{
540 return acme->acct? acme->acct->url : NULL;
541}
542
544 apr_pool_t *p, const char *acct_id)
545{
546 md_acme_acct_t *acct;
548 apr_status_t rv;
549
550 if (APR_SUCCESS == (rv = md_acme_acct_load(&acct, &pkey,
551 store, MD_SG_ACCOUNTS, acct_id, acme->p))) {
552 if (md_acme_acct_matches_url(acct, acme->url)) {
553 acme->acct_id = apr_pstrdup(p, acct_id);
554 acme->acct = acct;
555 acme->acct_key = pkey;
556 rv = md_acme_acct_validate(acme, store, p);
557 }
558 else {
559 /* account is from another server or, more likely, from another
560 * protocol endpoint on the same server */
561 rv = APR_ENOENT;
562 }
563 }
564 return rv;
565}
566
568 apr_pool_t *p, const char *acct_id,
569 const md_t *md)
570{
571 md_acme_acct_t *acct;
573 apr_status_t rv;
574
575 if (APR_SUCCESS == (rv = md_acme_acct_load(&acct, &pkey,
576 store, MD_SG_ACCOUNTS, acct_id, acme->p))) {
577 if (md_acme_acct_matches_md(acct, md)) {
578 acme->acct_id = apr_pstrdup(p, acct_id);
579 acme->acct = acct;
580 acme->acct_key = pkey;
581 rv = md_acme_acct_validate(acme, store, p);
582 }
583 else {
584 /* account is from another server or, more likely, from another
585 * protocol endpoint on the same server */
586 rv = APR_ENOENT;
587 }
588 }
589 return rv;
590}
591
593{
594 return md_acme_acct_save(store, p, acme, &acme->acct_id, acme->acct, acme->acct_key);
595}
596
598 md_acme_req_init_cb *on_init,
599 md_acme_req_json_cb *on_json,
600 md_acme_req_res_cb *on_res,
601 md_acme_req_err_cb *on_err,
602 void *baton)
603{
604 return md_acme_POST(acme, acme->api.v2.new_account, on_init, on_json, on_res, on_err, baton);
605}
606
608 md_acme_req_init_cb *on_init,
609 md_acme_req_json_cb *on_json,
610 md_acme_req_res_cb *on_res,
611 md_acme_req_err_cb *on_err,
612 void *baton)
613{
614 return acme->post_new_account_fn(acme, on_init, on_json, on_res, on_err, baton);
615}
616
617/**************************************************************************************************/
618/* ACME setup */
619
621 const char *proxy_url, const char *ca_file)
622{
623 md_acme_t *acme;
624 const char *err = NULL;
625 apr_status_t rv;
627 size_t len;
628
629 if (!url) {
630 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, APR_EINVAL, p, "create ACME without url");
631 return APR_EINVAL;
632 }
633
634 if (APR_SUCCESS != (rv = md_util_abs_uri_check(p, url, &err))) {
635 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "invalid ACME uri (%s): %s", err, url);
636 return rv;
637 }
638
639 acme = apr_pcalloc(p, sizeof(*acme));
640 acme->url = url;
641 acme->p = p;
642 acme->user_agent = apr_psprintf(p, "%s mod_md/%s",
644 acme->proxy_url = proxy_url? apr_pstrdup(p, proxy_url) : NULL;
645 acme->max_retries = 99;
646 acme->ca_file = ca_file;
647
648 if (APR_SUCCESS != (rv = apr_uri_parse(p, url, &uri_parsed))) {
649 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "parsing ACME uri: %s", url);
650 return APR_EINVAL;
651 }
652
653 len = strlen(uri_parsed.hostname);
654 acme->sname = (len <= 16)? uri_parsed.hostname : apr_pstrdup(p, uri_parsed.hostname + len - 16);
656 acme->last = md_result_make(acme->p, APR_SUCCESS);
657
658 *pacme = acme;
659 return rv;
660}
661
666
668{
669 md_http_request_t *req = res->req;
670 md_acme_t *acme = ((update_dir_ctx *)data)->acme;
671 md_result_t *result = ((update_dir_ctx *)data)->result;
672 apr_status_t rv;
673 md_json_t *json;
674 const char *s;
675
676 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, req->pool, "directory lookup response: %d", res->status);
677 if (res->status == 503) {
679 "The ACME server at <%s> reports that Service is Unavailable (503). This "
680 "may happen during maintenance for short periods of time.", acme->url);
682 rv = result->status;
683 goto leave;
684 }
685 else if (res->status < 200 || res->status >= 300) {
687 "The ACME server at <%s> responded with HTTP status %d. This "
688 "is unusual. Please verify that the URL is correct and that you can indeed "
689 "make request from the server to it by other means, e.g. invoking curl/wget.",
690 acme->url, res->status);
691 rv = result->status;
692 goto leave;
693 }
694
695 rv = md_json_read_http(&json, req->pool, res);
696 if (APR_SUCCESS != rv) {
697 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, req->pool, "reading JSON body");
698 goto leave;
699 }
700
701 if (md_log_is_level(acme->p, MD_LOG_TRACE2)) {
704 "response: %s", s ? s : "<failed to serialize!>");
705 }
706
707 /* What have we got? */
708 if ((s = md_json_dups(acme->p, json, "newAccount", NULL))) {
709 acme->api.v2.new_account = s;
710 acme->api.v2.new_order = md_json_dups(acme->p, json, "newOrder", NULL);
711 acme->api.v2.revoke_cert = md_json_dups(acme->p, json, "revokeCert", NULL);
712 acme->api.v2.key_change = md_json_dups(acme->p, json, "keyChange", NULL);
713 acme->api.v2.new_nonce = md_json_dups(acme->p, json, "newNonce", NULL);
714 /* RFC 8555 only requires "directory" and "newNonce" resources.
715 * mod_md uses "newAccount" and "newOrder" so check for them.
716 * But mod_md does not use the "revokeCert" or "keyChange"
717 * resources, so tolerate the absence of those keys. In the
718 * future if mod_md implements revocation or key rollover then
719 * the use of those features should be predicated on the
720 * server's advertised capabilities. */
721 if (acme->api.v2.new_account
722 && acme->api.v2.new_order
723 && acme->api.v2.new_nonce) {
725 }
726 acme->ca_agreement = md_json_dups(acme->p, json, "meta", MD_KEY_TOS, NULL);
727 acme->eab_required = md_json_getb(json, "meta", MD_KEY_EAB_REQUIRED, NULL);
731 }
732 else if ((s = md_json_dups(acme->p, json, "new-authz", NULL))) {
733 acme->api.v1.new_authz = s;
734 acme->api.v1.new_cert = md_json_dups(acme->p, json, "new-cert", NULL);
735 acme->api.v1.new_reg = md_json_dups(acme->p, json, "new-reg", NULL);
736 acme->api.v1.revoke_cert = md_json_dups(acme->p, json, "revoke-cert", NULL);
737 if (acme->api.v1.new_authz && acme->api.v1.new_cert
738 && acme->api.v1.new_reg && acme->api.v1.revoke_cert) {
740 }
741 acme->ca_agreement = md_json_dups(acme->p, json, "meta", "terms-of-service", NULL);
742 /* we init that far, but will not use the v1 api */
743 }
744
745 if (MD_ACME_VERSION_UNKNOWN == acme->version) {
747 "Unable to understand ACME server response from <%s>. "
748 "Wrong ACME protocol version or link?", acme->url);
750 rv = result->status;
751 }
752leave:
753 return rv;
754}
755
757{
758 apr_status_t rv;
760
761 assert(acme->url);
763
764 if (!acme->http && APR_SUCCESS != (rv = md_http_create(&acme->http, acme->p,
765 acme->user_agent, acme->proxy_url))) {
766 return rv;
767 }
768 /* TODO: maybe this should be configurable. Let's take some reasonable
769 * defaults for now that protect our client */
770 md_http_set_response_limit(acme->http, 1024*1024);
774 md_http_set_ca_file(acme->http, acme->ca_file);
775
776 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, acme->p, "get directory from %s", acme->url);
777
778 ctx.acme = acme;
779 ctx.result = result;
780 rv = md_http_GET_perform(acme->http, acme->url, NULL, update_directory, &ctx);
781
782 if (APR_SUCCESS != rv && APR_SUCCESS == result->status) {
783 /* If the result reports no error, we never got a response from the server */
785 "Unsuccessful in contacting ACME server at <%s>. If this problem persists, "
786 "please check your network connectivity from your Apache server to the "
787 "ACME server. Also, older servers might have trouble verifying the certificates "
788 "of the ACME server. You can check if you are able to contact it manually via the "
789 "curl command. Sometimes, the ACME server might be down for maintenance, "
790 "so failing to contact it is not an immediate problem. Apache will "
791 "continue retrying this.", acme->url);
793 }
794 return rv;
795}
796
797
const char apr_size_t len
Definition ap_regex.h:187
APR-UTIL Buckets/Bucket Brigades.
char * strstr(char *s1, char *s2)
APR Hash Tables.
APR general purpose library routines.
APR Strings library.
APR-UTIL URI Routines.
ap_conf_vector_t * base
ap_vhost_iterate_conn_cb void * baton
Definition http_vhost.h:87
#define APR_EAGAIN
Definition apr_errno.h:730
#define APR_EGENERAL
Definition apr_errno.h:313
#define APR_EACCES
Definition apr_errno.h:641
#define APR_BADARG
Definition apr_errno.h:459
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_ENOENT
Definition apr_errno.h:662
#define APR_EINVAL
Definition apr_errno.h:711
#define APR_STATUS_IS_EAGAIN(s)
Definition apr_errno.h:1272
#define APR_STATUS_IS_ENOENT(s)
Definition apr_errno.h:1246
apr_brigade_flush void * ctx
apr_pool_t apr_dbd_t apr_dbd_results_t ** res
Definition apr_dbd.h:287
apr_datum_t * pkey
Definition apr_dbm.h:158
const char * url
Definition apr_escape.h:120
apr_size_t size
const char int apr_pool_t * pool
Definition apr_cstr.h:84
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
void * data
int type
apr_array_header_t ** result
apr_uint32_t apr_pool_t apr_uint32_t apr_pollset_method_e method
Definition apr_poll.h:195
#define apr_pool_create(newpool, parent)
Definition apr_pools.h:322
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const char * s
Definition apr_strings.h:95
apr_int32_t apr_int32_t apr_int32_t err
#define apr_time_from_sec(sec)
Definition apr_time.h:78
#define MD_KEY_TYPE
Definition md.h:204
#define MD_KEY_SUBPROBLEMS
Definition md.h:198
#define MD_KEY_TOS
Definition md.h:200
#define MD_KEY_EAB_REQUIRED
Definition md.h:142
#define MD_KEY_DETAIL
Definition md.h:136
const char * md_acme_acct_url_get(md_acme_t *acme)
Definition md_acme.c:538
apr_status_t md_acme_get_json(struct md_json_t **pjson, md_acme_t *acme, const char *url, apr_pool_t *p)
Definition md_acme.c:509
void md_acme_clear_acct(md_acme_t *acme)
Definition md_acme.c:526
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)
Definition md_acme.c:567
static apr_status_t on_response(const md_http_response_t *res, void *data)
Definition md_acme.c:273
const char * md_acme_acct_id_get(md_acme_t *acme)
Definition md_acme.c:533
static apr_status_t acmev2_GET_as_POST_init(md_acme_req_t *req, void *baton)
Definition md_acme.c:329
static md_acme_req_t * md_acme_req_create(md_acme_t *acme, const char *method, const char *url)
Definition md_acme.c:129
apr_status_t md_acme_save_acct(md_acme_t *acme, apr_pool_t *p, md_store_t *store)
Definition md_acme.c:592
apr_status_t md_acme_init(apr_pool_t *p, const char *base, int init_ssl)
Definition md_acme.c:163
int md_acme_problem_is_input_related(const char *problem)
Definition md_acme.c:91
static acme_problem_status_t Problems[]
Definition md_acme.c:51
static apr_status_t on_got_json(md_acme_t *acme, apr_pool_t *p, const apr_table_t *headers, md_json_t *jbody, void *baton)
Definition md_acme.c:497
apr_status_t md_acme_req_body_init(md_acme_req_t *req, md_json_t *payload)
Definition md_acme.c:250
static apr_status_t inspect_problem(md_acme_req_t *req, const md_http_response_t *res)
Definition md_acme.c:169
static const char * base_product
Definition md_acme.c:41
apr_status_t md_acme_setup(md_acme_t *acme, md_result_t *result)
Definition md_acme.c:756
static apr_status_t acmev2_req_init(md_acme_req_t *req, md_json_t *jpayload)
Definition md_acme.c:225
static void req_update_nonce(md_acme_t *acme, apr_table_t *hdrs)
Definition md_acme.c:113
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
static apr_status_t acmev2_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:597
static apr_status_t http_update_nonce(const md_http_response_t *res, void *data)
Definition md_acme.c:123
apr_status_t md_acme_use_acct(md_acme_t *acme, md_store_t *store, apr_pool_t *p, const char *acct_id)
Definition md_acme.c:543
static apr_status_t update_directory(const md_http_response_t *res, void *data)
Definition md_acme.c:667
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)
Definition md_acme.c:455
static apr_status_t md_acme_req_send(md_acme_req_t *req)
Definition md_acme.c:335
static apr_status_t problem_status_get(const char *type)
Definition md_acme.c:73
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 md_acme_req_done(md_acme_req_t *req, apr_status_t rv)
Definition md_acme.c:255
apr_status_t md_acme_create(md_acme_t **pacme, apr_pool_t *p, const char *url, const char *proxy_url, const char *ca_file)
Definition md_acme.c:620
static apr_status_t acmev2_new_nonce(md_acme_t *acme)
Definition md_acme.c:157
void md_acme_report_result(md_acme_t *acme, apr_status_t rv, struct md_result_t *result)
Definition md_acme.c:478
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)
Definition md_acme.h:73
apr_status_t md_acme_req_init_cb(md_acme_req_t *req, void *baton)
Definition md_acme.h:67
apr_status_t md_acme_req_res_cb(md_acme_t *acme, const struct md_http_response_t *res, void *baton)
Definition md_acme.h:60
apr_status_t md_acme_req_err_cb(md_acme_req_t *req, const struct md_result_t *result, void *baton)
Definition md_acme.h:80
#define MD_ACME_VERSION_UNKNOWN
Definition md_acme.h:38
#define MD_ACME_VERSION_2
Definition md_acme.h:40
#define MD_ACME_VERSION_1
Definition md_acme.h:39
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)
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)
int md_acme_acct_matches_url(md_acme_acct_t *acct, const char *url)
apr_status_t md_acme_acct_validate(md_acme_t *acme, md_store_t *store, apr_pool_t *p)
apr_status_t md_crypt_init(apr_pool_t *pool)
Definition md_crypt.c:133
apr_pool_t * p
Definition md_event.c:32
void md_http_set_response_limit(md_http_t *http, apr_off_t resp_limit)
Definition md_http.c:124
apr_status_t md_http_GET_perform(struct md_http_t *http, const char *url, struct apr_table_t *headers, md_http_response_cb *cb, void *baton)
Definition md_http.c:349
void md_http_set_ca_file(md_http_t *http, const char *ca_file)
Definition md_http.c:161
void md_http_set_connect_timeout_default(md_http_t *http, apr_time_t timeout)
Definition md_http.c:139
apr_status_t md_http_HEAD_perform(struct md_http_t *http, const char *url, struct apr_table_t *headers, md_http_response_cb *cb, void *baton)
Definition md_http.c:361
void md_http_set_stalling_default(md_http_t *http, long bytes_per_sec, apr_time_t timeout)
Definition md_http.c:149
void md_http_set_timeout_default(md_http_t *http, apr_time_t timeout)
Definition md_http.c:129
apr_status_t md_http_create(md_http_t **phttp, apr_pool_t *p, const char *user_agent, const char *proxy_url)
Definition md_http.c:61
apr_status_t md_http_POSTd_perform(md_http_t *http, const char *url, struct apr_table_t *headers, const char *content_type, const md_data_t *body, md_http_response_cb *cb, void *baton)
Definition md_http.c:386
md_json_t * md_json_create(apr_pool_t *pool)
Definition md_json.c:92
int md_json_getb(const md_json_t *json,...)
Definition md_json.c:330
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_getj(md_json_t *json,...)
Definition md_json.c:473
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_read_http(md_json_t **pjson, apr_pool_t *pool, const md_http_response_t *res)
Definition md_json.c:1185
const char * md_json_dups(apr_pool_t *p, const md_json_t *json,...)
Definition md_json.c:418
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
@ MD_JSON_FMT_INDENT
Definition md_json.h:44
apr_status_t md_jws_sign(md_json_t **pmsg, apr_pool_t *p, md_data_t *payload, md_json_t *prot_fields, struct md_pkey_t *pkey, const char *key_id)
Definition md_jws.c:42
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_TRACE4
Definition md_log.h:32
@ MD_LOG_ERR
Definition md_log.h:24
@ MD_LOG_WARNING
Definition md_log.h:25
@ MD_LOG_TRACE3
Definition md_log.h:31
@ MD_LOG_DEBUG
Definition md_log.h:28
@ MD_LOG_INFO
Definition md_log.h:27
void md_result_dup(md_result_t *dest, const md_result_t *src)
Definition md_result.c:216
void md_result_printf(md_result_t *result, apr_status_t status, const char *fmt,...)
Definition md_result.c:126
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
md_result_t * md_result_make(apr_pool_t *p, apr_status_t status)
Definition md_result.c:39
void md_result_reset(md_result_t *result)
Definition md_result.c:57
void md_result_log(md_result_t *result, unsigned int level)
Definition md_result.c:227
void md_result_set(md_result_t *result, apr_status_t status, const char *detail)
Definition md_result.c:91
@ MD_SG_ACCOUNTS
Definition md_store.h:64
apr_status_t md_util_abs_uri_check(apr_pool_t *p, const char *uri, const char **perr)
Definition md_util.c:1005
const char * md_util_parse_ct(apr_pool_t *pool, const char *cth)
Definition md_util.c:1547
void md_data_null(md_data_t *d)
Definition md_util.c:107
#define MOD_MD_VERSION
Definition md_version.h:30
static void init_ssl(void)
Definition mod_md.c:112
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
apr_status_t rv
Definition md_acme.c:47
const char * type
Definition md_acme.c:46
md_json_t * json
Definition md_acme.c:494
apr_pool_t * pool
Definition md_acme.c:493
const char * url
apr_pool_t * p
Definition md_acme.h:249
struct md_result_t * result
Definition md_acme.h:267
struct md_json_t * req_json
Definition md_acme.h:254
void * baton
Definition md_acme.h:266
md_acme_req_err_cb * on_err
Definition md_acme.h:264
md_acme_req_res_cb * on_res
Definition md_acme.h:263
md_acme_req_json_cb * on_json
Definition md_acme.h:262
const char * method
Definition md_acme.h:252
struct md_json_t * resp_json
Definition md_acme.h:257
int max_retries
Definition md_acme.h:265
struct md_json_t * prot_fields
Definition md_acme.h:253
const char * url
Definition md_acme.h:251
md_acme_t * acme
Definition md_acme.h:248
apr_table_t * resp_hdrs
Definition md_acme.h:256
md_acme_req_init_cb * on_init
Definition md_acme.h:261
apr_status_t rv
Definition md_acme.h:259
struct md_acme_t::@21::@22 v1
struct md_result_t * last
Definition md_acme.h:135
const char * revoke_cert
Definition md_acme.h:112
const char * new_account
Definition md_acme.h:116
int version
Definition md_acme.h:106
int max_retries
Definition md_acme.h:134
md_acme_post_fn * post_new_account_fn
Definition md_acme.h:129
const char * new_reg
Definition md_acme.h:111
apr_pool_t * p
Definition md_acme.h:97
const char * proxy_url
Definition md_acme.h:99
const char * ca_agreement
Definition md_acme.h:123
struct md_acme_t::@21::@23 v2
const char * new_authz
Definition md_acme.h:109
union md_acme_t::@21 api
const char * user_agent
Definition md_acme.h:98
int eab_required
Definition md_acme.h:125
struct md_http_t * http
Definition md_acme.h:131
const char * new_nonce
Definition md_acme.h:120
const char * new_cert
Definition md_acme.h:110
md_acme_req_init_fn * req_init_fn
Definition md_acme.h:128
struct md_acme_acct_t * acct
Definition md_acme.h:103
const char * nonce
Definition md_acme.h:133
const char * key_change
Definition md_acme.h:118
const char * new_order
Definition md_acme.h:117
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 * ca_file
Definition md_acme.h:100
md_acme_new_nonce_fn * new_nonce_fn
Definition md_acme.h:127
const char * acct_id
Definition md_acme.h:102
const char * data
Definition md_util.h:42
apr_size_t len
Definition md_util.h:43
apr_pool_t * pool
Definition md_http.h:60
const struct md_json_t * subproblems
Definition md_result.h:35
const char * detail
Definition md_result.h:34
const char * problem
Definition md_result.h:33
apr_status_t status
Definition md_result.h:32
Definition md.h:76
md_result_t * result
Definition md_acme.c:664
md_acme_t * acme
Definition md_acme.c:663