acme.c (44236B)
1 /*
2 * Copyright (c) 2019-2022 Joris Vink <joris@coders.se>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 /*
18 * ACMEv2 protocol implementation.
19 *
20 * The acme process is responsible for talking to the acme servers, parsing
21 * their JSON responses and requesting signed data / a csr from the keymgr
22 * process.
23 *
24 * The acme process does not hold your account or domain keys, so anything
25 * that needs to be signed is sent to the keymgr process instead.
26 */
27
28 #include <sys/types.h>
29 #include <sys/stat.h>
30
31 #include <openssl/sha.h>
32
33 #include <stdio.h>
34 #include <stdlib.h>
35
36 #include "kore.h"
37 #include "acme.h"
38 #include "curl.h"
39
40 #define ACME_CREATE_ACCOUNT 0
41 #define ACME_RESOLVE_ACCOUNT 1
42
43 #define ACME_STATUS_PENDING 1
44 #define ACME_STATUS_PROCESSING 2
45 #define ACME_STATUS_VALID 3
46 #define ACME_STATUS_INVALID 4
47 #define ACME_STATUS_READY 5
48 #define ACME_STATUS_EXPIRED 6
49 #define ACME_STATUS_REVOKED 7
50
51 /*
52 * The default provider is letsencrypt, can be overwritten via the config
53 * file its acme_provider setting.
54 */
55 #define ACME_DEFAULT_PROVIDER "https://acme-v02.api.letsencrypt.org/directory"
56
57 #if defined(__linux__)
58 #include "seccomp.h"
59
60 /*
61 * The syscalls our acme worker is allowed to perform, only.
62 *
63 * Since we drop all previously loaded seccomp rules to apply our own
64 * we will have to reinclude the ones curl does.
65 */
66 static struct sock_filter filter_acme[] = {
67 KORE_SYSCALL_ALLOW(prctl),
68 #if defined(SYS_poll)
69 KORE_SYSCALL_ALLOW(poll),
70 #endif
71 KORE_SYSCALL_ALLOW(ppoll),
72 KORE_SYSCALL_ALLOW(sendto),
73 KORE_SYSCALL_ALLOW(recvfrom),
74 #if defined(SYS_epoll_wait)
75 KORE_SYSCALL_ALLOW(epoll_wait),
76 #endif
77 KORE_SYSCALL_ALLOW(epoll_pwait),
78 KORE_SYSCALL_ALLOW(recvmsg),
79 KORE_SYSCALL_ALLOW(sendmsg),
80 KORE_SYSCALL_ALLOW(sendmmsg),
81 KORE_SYSCALL_ALLOW(getpeername),
82
83 KORE_SYSCALL_ALLOW(gettid),
84 KORE_SYSCALL_ALLOW(exit),
85
86 KORE_SYSCALL_ALLOW(brk),
87 #if defined(SYS_mmap)
88 KORE_SYSCALL_ALLOW(mmap),
89 #endif
90 #if defined(SYS_mmap2)
91 KORE_SYSCALL_ALLOW(mmap2),
92 #endif
93 KORE_SYSCALL_ALLOW(ioctl),
94 KORE_SYSCALL_ALLOW(uname),
95 KORE_SYSCALL_ALLOW(munmap),
96 KORE_SYSCALL_ALLOW(madvise),
97 KORE_SYSCALL_ALLOW(faccessat),
98 KORE_SYSCALL_ALLOW(newfstatat),
99 KORE_SYSCALL_ALLOW(clock_gettime),
100 #if defined(SYS_pipe2)
101 KORE_SYSCALL_ALLOW(pipe2),
102 #endif
103 #if defined(SYS_readv)
104 KORE_SYSCALL_ALLOW(readv),
105 #endif
106 KORE_SYSCALL_ALLOW(bind),
107 KORE_SYSCALL_ALLOW(ioctl),
108 KORE_SYSCALL_ALLOW(connect),
109 KORE_SYSCALL_ALLOW(getsockopt),
110 KORE_SYSCALL_ALLOW(socketpair),
111 KORE_SYSCALL_ALLOW(getsockname),
112 KORE_SYSCALL_ALLOW_ARG(socket, 0, AF_INET),
113 KORE_SYSCALL_ALLOW_ARG(socket, 0, AF_INET6),
114 KORE_SYSCALL_ALLOW_ARG(socket, 0, AF_UNIX),
115 KORE_SYSCALL_ALLOW_ARG(socket, 0, AF_NETLINK),
116
117 KORE_SYSCALL_ALLOW(clone),
118 KORE_SYSCALL_ALLOW(membarrier),
119 KORE_SYSCALL_ALLOW(set_robust_list),
120 #if defined(SYS_clone3)
121 KORE_SYSCALL_ALLOW(clone3),
122 #endif
123 #if defined(SYS_rseq)
124 KORE_SYSCALL_ALLOW(rseq),
125 #endif
126 };
127 #endif
128
129 struct acme_request {
130 struct kore_curl curl;
131 };
132
133 struct acme_sign_op {
134 u_int32_t id;
135 struct kore_timer *t;
136 void *udata;
137 char *nonce;
138 char *payload;
139 char *protected;
140 void (*cb)(struct acme_sign_op *,
141 struct kore_buf *);
142 LIST_ENTRY(acme_sign_op) list;
143 };
144
145 #define ACME_AUTH_STATE_DOWNLOAD 1
146 #define ACME_AUTH_STATE_CHALLENGE 2
147
148 struct acme_auth {
149 char *url;
150 struct acme_order *order;
151 int status;
152 struct acme_challenge *challenge;
153 LIST_ENTRY(acme_auth) list;
154 };
155
156 #define ACME_ORDER_STATE_RUNNING 1
157 #define ACME_ORDER_STATE_ERROR 2
158 #define ACME_ORDER_STATE_CANCELLED 3
159 #define ACME_ORDER_STATE_UPDATE 4
160 #define ACME_ORDER_STATE_UPDATE_AUTH 5
161 #define ACME_ORDER_STATE_WAITING 6
162 #define ACME_ORDER_STATE_FETCH_CERT 7
163 #define ACME_ORDER_STATE_COMPLETE 8
164 #define ACME_ORDER_TICK 1000
165 #define ACME_ORDER_TIMEOUT 240000
166
167 #define ACME_ORDER_CSR_REQUESTED 0x1000
168
169 struct acme_order {
170 int state;
171 int status;
172 int flags;
173 int auths;
174 u_int64_t start;
175 char *id;
176 char *final;
177 char *domain;
178 char *certloc;
179 struct acme_auth *curauth;
180 LIST_HEAD(, acme_auth) auth;
181 LIST_ENTRY(acme_order) list;
182 };
183
184 static LIST_HEAD(, acme_order) orders;
185
186 #define ACME_FLAG_CHALLENGE_CREATED 0x0001
187 #define ACME_CHALLENGE_TOKEN_MAXLEN 64
188
189 struct acme_challenge {
190 int status;
191 int flags;
192 char *url;
193 char *type;
194 char *token;
195 char *error_type;
196 char *error_detail;
197 int (*process)(struct acme_order *,
198 struct acme_challenge *);
199 };
200
201 static LIST_HEAD(, acme_sign_op) signops;
202
203 static int acme_status_type(const char *);
204 static int acme_request_run(struct acme_request *);
205 static void acme_request_cleanup(struct acme_request *);
206 static void acme_request_prepare(struct acme_request *,
207 int, const char *, const void *, size_t);
208 static void acme_request_json(struct kore_buf *, const char *,
209 const char *, const char *);
210
211 static char *acme_nonce_fetch(void);
212 static char *acme_thumbprint_component(void);
213 static char *acme_base64url(const void *, size_t);
214 static char *acme_protected_component(const char *, const char *);
215 static void acme_keymgr_key_req(const char *, const void *, size_t, int);
216
217 static void acme_parse_directory(void);
218 static void acme_directory_set(struct kore_json *, const char *, char **);
219
220 static void acme_sign_expire(void *, u_int64_t);
221 static void acme_sign_result(struct kore_msg *, const void *);
222 static void acme_sign_submit(struct kore_json_item *, const char *, void *,
223 void (*cb)(struct acme_sign_op *, struct kore_buf *));
224
225 static void acme_rsakey_exp(struct kore_msg *, const void *);
226 static void acme_rsakey_mod(struct kore_msg *, const void *);
227
228 static void acme_account_reg(int);
229 static void acme_account_create(struct kore_msg *, const void *);
230 static void acme_account_resolve(struct kore_msg *, const void *);
231 static void acme_generic_submit(struct acme_sign_op *, struct kore_buf *);
232 static void acme_account_reg_submit(struct acme_sign_op *,
233 struct kore_buf *);
234
235 static void acme_order_retry(const char *);
236 static void acme_order_process(void *, u_int64_t);
237 static void acme_order_update(struct acme_order *);
238 static void acme_order_update_submit(struct acme_sign_op *,
239 struct kore_buf *);
240 static void acme_order_request_csr(struct acme_order *);
241 static void acme_order_fetch_certificate(struct acme_order *);
242 static void acme_order_fetch_certificate_submit(struct acme_sign_op *,
243 struct kore_buf *);
244 static void acme_order_create(struct kore_msg *, const void *);
245 static void acme_order_remove(struct acme_order *, const char *);
246 static void acme_order_csr_response(struct kore_msg *, const void *);
247 static void acme_order_create_submit(struct acme_sign_op *,
248 struct kore_buf *);
249
250 static void acme_order_auth_log_error(struct acme_order *);
251 static void acme_order_auth_deactivate(struct acme_order *);
252 static int acme_order_auth_process(struct acme_order *,
253 struct acme_auth *);
254 static void acme_order_auth_update(struct acme_order *,
255 struct acme_auth *);
256 static void acme_order_auth_update_submit(struct acme_sign_op *,
257 struct kore_buf *);
258
259 static int acme_challenge_tls_alpn_01(struct acme_order *,
260 struct acme_challenge *);
261 static void acme_challenge_tls_alpn_01_create(struct acme_order *,
262 struct acme_challenge *);
263
264 static void acme_challenge_respond(struct acme_order *,
265 const char *, const char *);
266
267 static int signop_id = 0;
268 static char *rsakey_n = NULL;
269 static char *rsakey_e = NULL;
270 static char *nonce_url = NULL;
271 static char *order_url = NULL;
272 static char *revoke_url = NULL;
273 static char *account_id = NULL;
274 static char *account_url = NULL;
275
276 struct kore_privsep acme_privsep;
277 int acme_domains = 0;
278 char *acme_email = NULL;
279 char *acme_provider = NULL;
280 u_int32_t acme_request_timeout = 8;
281
282 void
283 kore_acme_init(void)
284 {
285 acme_provider = kore_strdup(ACME_DEFAULT_PROVIDER);
286 }
287
288 void
289 kore_acme_run(void)
290 {
291 int quit;
292 u_int64_t now, netwait;
293
294 quit = 0;
295
296 kore_server_closeall();
297 kore_module_cleanup();
298
299 net_init();
300 kore_timer_init();
301 kore_connection_init();
302 kore_platform_event_init();
303 kore_msg_worker_init();
304
305 kore_msg_register(KORE_ACME_RSAKEY_E, acme_rsakey_exp);
306 kore_msg_register(KORE_ACME_RSAKEY_N, acme_rsakey_mod);
307 kore_msg_register(KORE_ACME_SIGN_RESULT, acme_sign_result);
308 kore_msg_register(KORE_ACME_ORDER_CREATE, acme_order_create);
309 kore_msg_register(KORE_ACME_ACCOUNT_CREATE, acme_account_create);
310 kore_msg_register(KORE_ACME_ACCOUNT_RESOLVE, acme_account_resolve);
311 kore_msg_register(KORE_ACME_CSR_RESPONSE, acme_order_csr_response);
312
313 #if defined(__linux__)
314 /* Drop all enabled seccomp filters, and add only ours. */
315 kore_seccomp_drop();
316 kore_seccomp_filter("acme", filter_acme, KORE_FILTER_LEN(filter_acme));
317 #endif
318 #if defined(KORE_USE_PYTHON)
319 kore_msg_unregister(KORE_PYTHON_SEND_OBJ);
320 #endif
321 kore_worker_privsep();
322
323 #if defined(__OpenBSD__)
324 if (unveil("/etc/ssl/", "r") == -1)
325 fatal("unveil: %s", errno_s);
326 if (pledge("stdio inet dns rpath", NULL) == -1)
327 fatal("pledge acme process: %s", errno_s);
328 #endif
329
330 http_init();
331
332 LIST_INIT(&orders);
333 LIST_INIT(&signops);
334
335 kore_worker_started();
336 acme_parse_directory();
337
338 while (quit != 1) {
339 now = kore_time_ms();
340 netwait = kore_timer_next_run(now);
341 kore_platform_event_wait(netwait);
342
343 if (sig_recv != 0) {
344 switch (sig_recv) {
345 case SIGQUIT:
346 case SIGINT:
347 case SIGTERM:
348 quit = 1;
349 break;
350 default:
351 break;
352 }
353 sig_recv = 0;
354 }
355
356 if (quit)
357 break;
358
359 now = kore_time_ms();
360 kore_timer_run(now);
361 kore_connection_prune(KORE_CONNECTION_PRUNE_DISCONNECT);
362 }
363
364 kore_platform_event_cleanup();
365 kore_connection_cleanup();
366 net_cleanup();
367 }
368
369 void
370 kore_acme_get_paths(const char *domain, char **key, char **cert)
371 {
372 int len;
373 char path[MAXPATHLEN];
374
375 len = snprintf(path, sizeof(path), "%s/%s/fullchain.pem",
376 KORE_ACME_CERTDIR, domain);
377 if (len == -1 || (size_t)len >= sizeof(path))
378 fatal("failed to create certfile path");
379
380 *cert = kore_strdup(path);
381
382 len = snprintf(path, sizeof(path), "%s/%s/key.pem",
383 KORE_ACME_CERTDIR, domain);
384 if (len == -1 || (size_t)len >= sizeof(path))
385 fatal("failed to create certkey path");
386
387 *key = kore_strdup(path);
388 }
389
390 static void
391 acme_parse_directory(void)
392 {
393 struct acme_request req;
394 size_t len;
395 struct kore_json json;
396 const u_int8_t *body;
397
398 acme_request_prepare(&req, HTTP_METHOD_GET, acme_provider, NULL, 0);
399
400 if (!acme_request_run(&req)) {
401 acme_request_cleanup(&req);
402 return;
403 }
404
405 if (req.curl.http.status != HTTP_STATUS_OK) {
406 kore_log(LOG_NOTICE,
407 "request to '%s' failed: got %ld - expected 200",
408 req.curl.url, req.curl.http.status);
409 acme_request_cleanup(&req);
410 return;
411 }
412
413 kore_curl_response_as_bytes(&req.curl, &body, &len);
414
415 kore_json_init(&json, body, len);
416
417 if (!kore_json_parse(&json)) {
418 kore_log(LOG_NOTICE,
419 "failed to parse directory payload from ACME server (%s)",
420 kore_json_strerror());
421 goto cleanup;
422 }
423
424 acme_directory_set(&json, "newNonce", &nonce_url);
425 acme_directory_set(&json, "newOrder", &order_url);
426 acme_directory_set(&json, "newAccount", &account_url);
427 acme_directory_set(&json, "revokeCert", &revoke_url);
428
429 cleanup:
430 kore_json_cleanup(&json);
431 acme_request_cleanup(&req);
432 }
433
434 static char *
435 acme_nonce_fetch(void)
436 {
437 struct acme_request req;
438 char *ret;
439 const char *nonce;
440
441 ret = NULL;
442 acme_request_prepare(&req, HTTP_METHOD_HEAD, nonce_url, NULL, 0);
443
444 if (!acme_request_run(&req))
445 goto cleanup;
446
447 if (req.curl.http.status != HTTP_STATUS_OK) {
448 kore_log(LOG_NOTICE,
449 "request to '%s' failed: got %ld - expected 200",
450 req.curl.url, req.curl.http.status);
451 goto cleanup;
452 }
453
454 if (!kore_curl_http_get_header(&req.curl, "replay-nonce", &nonce)) {
455 kore_log(LOG_NOTICE, "new-nonce: no replay-nonce header found");
456 goto cleanup;
457 }
458
459 ret = kore_strdup(nonce);
460
461 cleanup:
462 acme_request_cleanup(&req);
463
464 return (ret);
465 }
466
467 static void
468 acme_account_create(struct kore_msg *msg, const void *data)
469 {
470 acme_account_reg(ACME_CREATE_ACCOUNT);
471 }
472
473 static void
474 acme_account_resolve(struct kore_msg *msg, const void *data)
475 {
476 acme_account_reg(ACME_RESOLVE_ACCOUNT);
477 }
478
479 static void
480 acme_account_reg(int resolve_only)
481 {
482 int len;
483 char mail[1024];
484 struct kore_json_item *json, *contact;
485
486 if (account_url == NULL)
487 return;
488
489 kore_free(account_id);
490 account_id = NULL;
491
492 kore_log(LOG_INFO, "%s account with ACME provider",
493 resolve_only ? "resolving" : "creating");
494
495 json = kore_json_create_object(NULL, NULL);
496 kore_json_create_literal(json, "termsOfServiceAgreed", KORE_JSON_TRUE);
497
498 if (acme_email) {
499 len = snprintf(mail, sizeof(mail), "mailto:%s", acme_email);
500 if (len == -1 || (size_t)len >= sizeof(mail))
501 fatalx("mail contact '%s' too large", acme_email);
502
503 contact = kore_json_create_array(json, "contact");
504 kore_json_create_string(contact, NULL, mail);
505 }
506
507 if (resolve_only) {
508 kore_json_create_literal(json,
509 "onlyReturnExisting", KORE_JSON_TRUE);
510 }
511
512 acme_sign_submit(json, account_url, NULL, acme_account_reg_submit);
513 kore_json_item_free(json);
514 }
515
516 static void
517 acme_account_reg_submit(struct acme_sign_op *op, struct kore_buf *payload)
518 {
519 struct acme_request req;
520 const char *header;
521
522 acme_request_prepare(&req, HTTP_METHOD_POST, account_url,
523 payload->data, payload->offset);
524
525 if (!acme_request_run(&req))
526 goto cleanup;
527
528 switch (req.curl.http.status) {
529 case HTTP_STATUS_OK:
530 case HTTP_STATUS_CREATED:
531 break;
532 default:
533 kore_log(LOG_NOTICE,
534 "request to '%s' failed: status %ld - body '%s'",
535 req.curl.url, req.curl.http.status,
536 kore_curl_response_as_string(&req.curl));
537 goto cleanup;
538 }
539
540 if (!kore_curl_http_get_header(&req.curl, "location", &header)) {
541 kore_log(LOG_NOTICE, "new-acct: no location header found");
542 goto cleanup;
543 }
544
545 account_id = kore_strdup(header);
546 kore_log(LOG_INFO, "account_id = %s", account_id);
547 kore_msg_send(KORE_WORKER_KEYMGR, KORE_ACME_PROC_READY, NULL, 0);
548
549 cleanup:
550 acme_request_cleanup(&req);
551 }
552
553 static void
554 acme_order_create(struct kore_msg *msg, const void *data)
555 {
556 char *domain;
557 struct kore_json_item *json, *identifiers, *identifier;
558
559 domain = kore_calloc(1, msg->length + 1);
560 memcpy(domain, data, msg->length);
561 domain[msg->length] = '\0';
562
563 kore_log(LOG_INFO, "[%s] creating order", domain);
564
565 json = kore_json_create_object(NULL, NULL);
566 identifiers = kore_json_create_array(json, "identifiers");
567
568 identifier = kore_json_create_object(identifiers, NULL);
569 kore_json_create_string(identifier, "type", "dns");
570 kore_json_create_string(identifier, "value", domain);
571
572 acme_sign_submit(json, order_url, domain, acme_order_create_submit);
573 kore_json_item_free(json);
574 }
575
576 static void
577 acme_order_create_submit(struct acme_sign_op *op, struct kore_buf *payload)
578 {
579 struct acme_request req;
580 size_t len;
581 struct kore_json json;
582 int stval;
583 const u_int8_t *body;
584 struct acme_auth *auth;
585 struct acme_order *order;
586 const char *header;
587 const char *domain;
588 struct kore_json_item *item, *array, *final, *status;
589
590 order = NULL;
591 domain = op->udata;
592 acme_request_prepare(&req, HTTP_METHOD_POST, order_url,
593 payload->data, payload->offset);
594
595 if (!acme_request_run(&req)) {
596 acme_request_cleanup(&req);
597 acme_order_retry(domain);
598 return;
599 }
600
601 if (req.curl.http.status != HTTP_STATUS_CREATED) {
602 kore_log(LOG_NOTICE,
603 "[%s] - request to '%s' failed: status %ld - body '%s'",
604 domain, req.curl.url, req.curl.http.status,
605 kore_curl_response_as_string(&req.curl));
606 acme_request_cleanup(&req);
607 acme_order_retry(domain);
608 return;
609 }
610
611 if (!kore_curl_http_get_header(&req.curl, "location", &header)) {
612 kore_log(LOG_NOTICE,
613 "[%s] new-order: no order id found", domain);
614 acme_request_cleanup(&req);
615 acme_order_retry(domain);
616 return;
617 }
618
619 kore_curl_response_as_bytes(&req.curl, &body, &len);
620 kore_json_init(&json, body, len);
621
622 if (!kore_json_parse(&json)) {
623 kore_log(LOG_NOTICE,
624 "[%s] failed to parse order payload from ACME server (%s)",
625 domain, kore_json_strerror());
626 goto cleanup;
627 }
628
629 array = kore_json_find_array(json.root, "authorizations");
630 if (array == NULL) {
631 kore_log(LOG_NOTICE, "[%s] body has no 'authorizations' array",
632 domain);
633 goto cleanup;
634 }
635
636 if (TAILQ_EMPTY(&array->data.items)) {
637 kore_log(LOG_NOTICE, "[%s] no authoritization URLs in payload",
638 domain);
639 goto cleanup;
640 }
641
642 if ((status = kore_json_find_string(json.root, "status")) == NULL) {
643 kore_log(LOG_NOTICE, "[%s] order has no 'status' string",
644 domain);
645 goto cleanup;
646 }
647
648 if ((final = kore_json_find_string(json.root, "finalize")) == NULL) {
649 kore_log(LOG_NOTICE, "[%s] order has no 'finalize' string",
650 domain);
651 goto cleanup;
652 }
653
654 if ((stval = acme_status_type(status->data.string)) == -1) {
655 kore_log(LOG_NOTICE, "[%s] order has invalid status",
656 domain);
657 goto cleanup;
658 }
659
660 order = kore_calloc(1, sizeof(*order));
661 LIST_INSERT_HEAD(&orders, order, list);
662
663 LIST_INIT(&order->auth);
664
665 order->status = stval;
666 order->start = kore_time_ms();
667 order->id = kore_strdup(header);
668 order->domain = kore_strdup(domain);
669 order->state = ACME_ORDER_STATE_UPDATE;
670 order->final = kore_strdup(final->data.string);
671
672 kore_timer_add(acme_order_process, ACME_ORDER_TICK,
673 order, KORE_TIMER_ONESHOT);
674
675 TAILQ_FOREACH(item, &array->data.items, list) {
676 if (item->type != KORE_JSON_TYPE_STRING)
677 continue;
678
679 auth = kore_calloc(1, sizeof(*auth));
680 auth->order = order;
681 auth->url = kore_strdup(item->data.string);
682 LIST_INSERT_HEAD(&order->auth, auth, list);
683 }
684
685 order->curauth = LIST_FIRST(&order->auth);
686 kore_log(LOG_INFO, "[%s] order_id = %s", order->domain, order->id);
687
688 cleanup:
689 if (order == NULL)
690 acme_order_retry(domain);
691
692 kore_json_cleanup(&json);
693 acme_request_cleanup(&req);
694 }
695
696 static void
697 acme_order_update(struct acme_order *order)
698 {
699 acme_sign_submit(NULL, order->id, order, acme_order_update_submit);
700 }
701
702 static void
703 acme_order_update_submit(struct acme_sign_op *op, struct kore_buf *payload)
704 {
705 struct acme_request req;
706 size_t len;
707 struct kore_json json;
708 struct acme_order *order;
709 const u_int8_t *body;
710 int stval, ret;
711 struct kore_json_item *status, *cert;
712
713 order = op->udata;
714 op->udata = NULL;
715
716 acme_request_prepare(&req, HTTP_METHOD_POST, order->id,
717 payload->data, payload->offset);
718
719 if (!acme_request_run(&req)) {
720 acme_request_cleanup(&req);
721 order->state = ACME_ORDER_STATE_ERROR;
722 return;
723 }
724
725 if (req.curl.http.status != HTTP_STATUS_OK) {
726 kore_log(LOG_NOTICE,
727 "[%s] - request to '%s' failed: status %ld - body '%s'",
728 order->domain, req.curl.url, req.curl.http.status,
729 kore_curl_response_as_string(&req.curl));
730 acme_request_cleanup(&req);
731 order->state = ACME_ORDER_STATE_ERROR;
732 return;
733 }
734
735 ret = KORE_RESULT_ERROR;
736 kore_curl_response_as_bytes(&req.curl, &body, &len);
737
738 kore_json_init(&json, body, len);
739
740 if (!kore_json_parse(&json)) {
741 kore_log(LOG_NOTICE,
742 "[%s] failed to parse order payload from ACME server (%s)",
743 order->domain, kore_json_strerror());
744 goto cleanup;
745 }
746
747 if ((status = kore_json_find_string(json.root, "status")) == NULL) {
748 kore_log(LOG_NOTICE, "[%s] order has no 'status' string",
749 order->domain);
750 goto cleanup;
751 }
752
753 if ((stval = acme_status_type(status->data.string)) == -1) {
754 kore_log(LOG_NOTICE, "[%s] order has invalid status",
755 order->domain);
756 goto cleanup;
757 }
758
759 order->status = stval;
760
761 if (order->status == ACME_STATUS_VALID) {
762 cert = kore_json_find_string(json.root, "certificate");
763 if (cert == NULL) {
764 kore_log(LOG_NOTICE,
765 "[%s] order has 'certificate' member",
766 order->domain);
767 goto cleanup;
768 }
769
770 order->certloc = kore_strdup(cert->data.string);
771 }
772
773 ret = KORE_RESULT_OK;
774
775 cleanup:
776 if (ret == KORE_RESULT_ERROR)
777 order->state = ACME_ORDER_STATE_ERROR;
778 else
779 order->state = ACME_ORDER_STATE_UPDATE_AUTH;
780
781 kore_json_cleanup(&json);
782 acme_request_cleanup(&req);
783 }
784
785 /*
786 * We currently don't care why an order may have failed, (rate-limited,
787 * auth failed, etc).
788 *
789 * It would be neat if we could obey that a bit better.
790 */
791 static void
792 acme_order_retry(const char *domain)
793 {
794 u_int32_t retry_after;
795
796 /* arbitrary number */
797 retry_after = 60000;
798
799 acme_keymgr_key_req(domain, &retry_after, sizeof(retry_after),
800 KORE_ACME_ORDER_FAILED);
801 }
802
803 /*
804 * Process an order, step by step.
805 *
806 * This callback is called every second to check on an active order.
807 * It will first update the order if required, and updated any of its
808 * active awuthoritizations to get the latest data.
809 */
810 static void
811 acme_order_process(void *udata, u_int64_t now)
812 {
813 struct acme_auth *auth;
814 struct acme_order *order = udata;
815
816 if ((now - order->start) >= ACME_ORDER_TIMEOUT) {
817 acme_order_auth_deactivate(order);
818 acme_order_remove(order, "order ran too long");
819 return;
820 }
821
822 switch (order->state) {
823 case ACME_ORDER_STATE_WAITING:
824 break;
825 case ACME_ORDER_STATE_UPDATE:
826 acme_order_update(order);
827 order->state = ACME_ORDER_STATE_WAITING;
828 break;
829 case ACME_ORDER_STATE_UPDATE_AUTH:
830 order->auths = 0;
831 LIST_FOREACH(auth, &order->auth, list) {
832 acme_order_auth_update(order, auth);
833 order->auths++;
834 }
835 order->state = ACME_ORDER_STATE_WAITING;
836 break;
837 case ACME_ORDER_STATE_CANCELLED:
838 acme_order_remove(order, "cancelled");
839 order = NULL;
840 break;
841 case ACME_ORDER_STATE_COMPLETE:
842 acme_order_remove(order, "completed");
843 order = NULL;
844 break;
845 case ACME_ORDER_STATE_FETCH_CERT:
846 acme_order_fetch_certificate(order);
847 order->state = ACME_ORDER_STATE_WAITING;
848 break;
849 case ACME_ORDER_STATE_RUNNING:
850 switch (order->status) {
851 case ACME_STATUS_PENDING:
852 if (!acme_order_auth_process(order, order->curauth)) {
853 acme_order_auth_log_error(order);
854 acme_order_remove(order, "cancelled");
855 order = NULL;
856 }
857 break;
858 case ACME_STATUS_READY:
859 acme_order_request_csr(order);
860 break;
861 case ACME_STATUS_PROCESSING:
862 kore_log(LOG_INFO, "[%s] waiting for certificate",
863 order->domain);
864 break;
865 case ACME_STATUS_VALID:
866 kore_log(LOG_INFO, "[%s] certificate available",
867 order->domain);
868 order->state = ACME_ORDER_STATE_FETCH_CERT;
869 break;
870 case ACME_STATUS_INVALID:
871 kore_log(LOG_INFO, "[%s] order authorization failed",
872 order->domain);
873 acme_order_auth_log_error(order);
874 acme_order_remove(order, "authorization failure");
875 order = NULL;
876 break;
877 default:
878 acme_order_auth_deactivate(order);
879 acme_order_remove(order, "unknown status");
880 order = NULL;
881 break;
882 }
883 break;
884 case ACME_ORDER_STATE_ERROR:
885 acme_order_auth_deactivate(order);
886 acme_order_remove(order, "error");
887 order = NULL;
888 break;
889 default:
890 fatal("%s: invalid order state %d", __func__, order->state);
891 }
892
893 if (order != NULL) {
894 /* Do not go back to update if we are ready for the cert. */
895 if (order->state != ACME_ORDER_STATE_FETCH_CERT)
896 order->state = ACME_ORDER_STATE_UPDATE;
897
898 kore_timer_add(acme_order_process, ACME_ORDER_TICK,
899 order, KORE_TIMER_ONESHOT);
900 }
901 }
902
903 static void
904 acme_order_remove(struct acme_order *order, const char *reason)
905 {
906 struct acme_auth *auth;
907
908 LIST_REMOVE(order, list);
909
910 while ((auth = LIST_FIRST(&order->auth)) != NULL) {
911 LIST_REMOVE(auth, list);
912
913 if (auth->challenge != NULL) {
914 kore_free(auth->challenge->error_detail);
915 kore_free(auth->challenge->error_type);
916 kore_free(auth->challenge->token);
917 kore_free(auth->challenge->type);
918 kore_free(auth->challenge->url);
919 kore_free(auth->challenge);
920 }
921
922 kore_free(auth->url);
923 kore_free(auth);
924 }
925
926 kore_log(LOG_INFO, "[%s] order removed (%s)", order->domain, reason);
927
928 if (strcmp(reason, "completed"))
929 acme_order_retry(order->domain);
930
931 kore_free(order->domain);
932 kore_free(order->final);
933 kore_free(order->id);
934 kore_free(order);
935 }
936
937 static void
938 acme_order_fetch_certificate(struct acme_order *order)
939 {
940 acme_sign_submit(NULL, order->certloc, order,
941 acme_order_fetch_certificate_submit);
942 }
943
944 static void
945 acme_order_fetch_certificate_submit(struct acme_sign_op *op,
946 struct kore_buf *payload)
947 {
948 struct acme_request req;
949 size_t len;
950 const u_int8_t *body;
951 struct acme_order *order;
952
953 order = op->udata;
954 op->udata = NULL;
955
956 acme_request_prepare(&req, HTTP_METHOD_POST, order->certloc,
957 payload->data, payload->offset);
958
959 if (!acme_request_run(&req)) {
960 acme_request_cleanup(&req);
961 order->state = ACME_ORDER_STATE_CANCELLED;
962 return;
963 }
964
965 if (req.curl.http.status != HTTP_STATUS_OK) {
966 kore_log(LOG_NOTICE,
967 "[%s] request to '%s' failed: got %ld - expected 200",
968 order->domain, order->certloc, req.curl.http.status);
969 acme_request_cleanup(&req);
970 order->state = ACME_ORDER_STATE_CANCELLED;
971 return;
972 }
973
974 kore_curl_response_as_bytes(&req.curl, &body, &len);
975
976 kore_log(LOG_INFO, "got %zu bytes of cert data", len);
977 acme_keymgr_key_req(order->domain, body, len, KORE_ACME_INSTALL_CERT);
978
979 acme_request_cleanup(&req);
980 order->state = ACME_ORDER_STATE_COMPLETE;
981 }
982
983 static void
984 acme_order_request_csr(struct acme_order *order)
985 {
986 if (order->flags & ACME_ORDER_CSR_REQUESTED)
987 return;
988
989 kore_log(LOG_INFO, "[%s] requesting CSR", order->domain);
990
991 order->flags |= ACME_ORDER_CSR_REQUESTED;
992 acme_keymgr_key_req(order->domain, NULL, 0, KORE_ACME_CSR_REQUEST);
993 }
994
995 static void
996 acme_order_csr_response(struct kore_msg *msg, const void *data)
997 {
998 const struct kore_x509_msg *req;
999 struct kore_json_item *json;
1000 struct acme_order *order;
1001 char *b64, *url;
1002
1003 if (!kore_worker_keymgr_response_verify(msg, data, NULL))
1004 return;
1005
1006 req = (const struct kore_x509_msg *)data;
1007
1008 LIST_FOREACH(order, &orders, list) {
1009 if (!strcmp(order->domain, req->domain))
1010 break;
1011 }
1012
1013 if (order == NULL) {
1014 kore_log(LOG_NOTICE, "[%s] csr received but no order active",
1015 req->domain);
1016 return;
1017 }
1018
1019 url = kore_strdup(order->final);
1020 b64 = acme_base64url(req->data, req->data_len);
1021
1022 json = kore_json_create_object(NULL, NULL);
1023 kore_json_create_string(json, "csr", b64);
1024 acme_sign_submit(json, url, url, acme_generic_submit);
1025
1026 kore_json_item_free(json);
1027 kore_free(b64);
1028 }
1029
1030 static void
1031 acme_order_auth_deactivate(struct acme_order *order)
1032 {
1033 struct acme_request req;
1034 struct acme_auth *auth;
1035
1036 LIST_FOREACH(auth, &order->auth, list) {
1037 acme_request_prepare(&req, HTTP_METHOD_GET, auth->url, NULL, 0);
1038
1039 if (!acme_request_run(&req)) {
1040 kore_log(LOG_NOTICE,
1041 "[%s:auth] failed to deactivate %s", order->domain,
1042 auth->url);
1043 } else {
1044 kore_log(LOG_NOTICE, "[%s:auth] deactivated %s",
1045 order->domain, auth->url);
1046 }
1047
1048 acme_request_cleanup(&req);
1049 }
1050 }
1051
1052 static void
1053 acme_order_auth_log_error(struct acme_order *order)
1054 {
1055 struct acme_auth *auth;
1056
1057 LIST_FOREACH(auth, &order->auth, list) {
1058 if (auth->challenge->status == ACME_STATUS_PENDING ||
1059 auth->challenge->status == ACME_STATUS_VALID ||
1060 auth->challenge->status == ACME_STATUS_PROCESSING)
1061 continue;
1062
1063 kore_log(LOG_INFO, "[%s:auth:challenge] %s = %s (%s)",
1064 order->domain, auth->challenge->type,
1065 auth->challenge->error_type, auth->challenge->error_detail);
1066 }
1067 }
1068
1069 static int
1070 acme_order_auth_process(struct acme_order *order, struct acme_auth *auth)
1071 {
1072 int ret;
1073
1074 if (auth == NULL)
1075 return (KORE_RESULT_OK);
1076
1077 ret = KORE_RESULT_ERROR;
1078 kore_log(LOG_INFO, "[%s] processing authentication", order->domain);
1079
1080 switch (auth->status) {
1081 case ACME_STATUS_PENDING:
1082 ret = auth->challenge->process(order, auth->challenge);
1083 break;
1084 case ACME_STATUS_VALID:
1085 case ACME_STATUS_PROCESSING:
1086 ret = KORE_RESULT_OK;
1087 break;
1088 case ACME_STATUS_INVALID:
1089 kore_log(LOG_NOTICE, "[%s:auth] authorization invalid",
1090 order->domain);
1091 break;
1092 case ACME_STATUS_EXPIRED:
1093 kore_log(LOG_NOTICE, "[%s:auth] authorization expired",
1094 order->domain);
1095 break;
1096 case ACME_STATUS_REVOKED:
1097 kore_log(LOG_NOTICE, "[%s:auth] authorization revoked",
1098 order->domain);
1099 break;
1100 default:
1101 kore_log(LOG_NOTICE, "[%s:auth] invalid auth status %d",
1102 order->domain, auth->status);
1103 break;
1104 }
1105
1106 if (ret == KORE_RESULT_OK)
1107 order->curauth = LIST_NEXT(order->curauth, list);
1108
1109 return (ret);
1110 }
1111
1112 static void
1113 acme_order_auth_update(struct acme_order *order, struct acme_auth *auth)
1114 {
1115 acme_sign_submit(NULL, auth->url, auth, acme_order_auth_update_submit);
1116 }
1117
1118 static void
1119 acme_order_auth_update_submit(struct acme_sign_op *op, struct kore_buf *payload)
1120 {
1121 const char *p;
1122 struct acme_request req;
1123 size_t len;
1124 struct kore_json json;
1125 const u_int8_t *body;
1126 struct acme_auth *auth;
1127 struct acme_order *order;
1128 struct acme_challenge *challenge;
1129 int ret, stval;
1130 struct kore_json_item *status, *type, *url, *token;
1131 struct kore_json_item *array, *object, *err, *detail;
1132
1133 ret = KORE_RESULT_ERROR;
1134 memset(&json, 0, sizeof(json));
1135
1136 auth = op->udata;
1137 order = auth->order;
1138
1139 op->udata = NULL;
1140
1141 acme_request_prepare(&req, HTTP_METHOD_POST, auth->url,
1142 payload->data, payload->offset);
1143
1144 if (!acme_request_run(&req))
1145 goto cleanup;
1146
1147 if (req.curl.http.status != HTTP_STATUS_OK) {
1148 kore_log(LOG_NOTICE,
1149 "[%s:auth] request to '%s' failed: got %ld - expected 200",
1150 order->domain, auth->url, req.curl.http.status);
1151 goto cleanup;
1152 }
1153
1154 kore_curl_response_as_bytes(&req.curl, &body, &len);
1155
1156 kore_json_init(&json, body, len);
1157
1158 if (!kore_json_parse(&json)) {
1159 kore_log(LOG_NOTICE,
1160 "[%s:auth] failed to parse payload from ACME server (%s)",
1161 order->domain, kore_json_strerror());
1162 goto cleanup;
1163 }
1164
1165 kore_log(LOG_INFO, "[%s:auth] %s updated", order->domain, auth->url);
1166
1167 if ((status = kore_json_find_string(json.root, "status")) == NULL) {
1168 kore_log(LOG_NOTICE, "[%s:auth] payload has no 'status' string",
1169 order->domain);
1170 goto cleanup;
1171 }
1172
1173 if ((array = kore_json_find_array(json.root, "challenges")) == NULL) {
1174 kore_log(LOG_NOTICE,
1175 "[%s:auth] payload has no 'challenges' array",
1176 order->domain);
1177 goto cleanup;
1178 }
1179
1180 if (TAILQ_EMPTY(&array->data.items)) {
1181 kore_log(LOG_NOTICE,
1182 "[%s:auth] no challenges URLs in challenge array",
1183 order->domain);
1184 goto cleanup;
1185 }
1186
1187 if ((stval = acme_status_type(status->data.string)) == -1) {
1188 kore_log(LOG_NOTICE, "[%s] auth has invalid status",
1189 order->domain);
1190 goto cleanup;
1191 }
1192
1193 auth->status = stval;
1194
1195 TAILQ_FOREACH(object, &array->data.items, list) {
1196 if (object->type != KORE_JSON_TYPE_OBJECT)
1197 continue;
1198
1199 if ((type = kore_json_find_string(object, "type")) == NULL) {
1200 kore_log(LOG_NOTICE,
1201 "[%s:auth:challenge] no type", order->domain);
1202 continue;
1203 }
1204
1205 /*
1206 * We only support tls-alpn-01 for now, we ignore the rest.
1207 */
1208 if (strcmp(type->data.string, "tls-alpn-01"))
1209 continue;
1210
1211 url = kore_json_find_string(object, "url");
1212 token = kore_json_find_string(object, "token");
1213 status = kore_json_find_string(object, "status");
1214
1215 if (url == NULL || token == NULL || status == NULL) {
1216 kore_log(LOG_NOTICE,
1217 "[%s:auth:challenge] missing members",
1218 order->domain);
1219 continue;
1220 }
1221
1222 if (strlen(token->data.string) > ACME_CHALLENGE_TOKEN_MAXLEN) {
1223 kore_log(LOG_NOTICE,
1224 "[%s:auth:challenge] invalid token length",
1225 order->domain);
1226 continue;
1227 }
1228
1229 for (p = token->data.string; *p != '\0'; p++) {
1230 if ((*p >= 'a' && *p <= 'z') ||
1231 (*p >= 'A' && *p <= 'Z') ||
1232 (*p >= '0' && *p <= '9') || *p == '_' || *p == '-')
1233 continue;
1234 break;
1235 }
1236
1237 if (*p != '\0') {
1238 kore_log(LOG_NOTICE,
1239 "[%s:auth:challenge] invalid token",
1240 order->domain);
1241 continue;
1242 }
1243
1244 if ((stval = acme_status_type(status->data.string)) == -1) {
1245 kore_log(LOG_NOTICE,
1246 "[%s:auth:challenge] invalid challenge status",
1247 order->domain);
1248 continue;
1249 }
1250
1251 if (auth->challenge == NULL) {
1252 challenge = kore_calloc(1, sizeof(*challenge));
1253
1254 challenge->url = kore_strdup(url->data.string);
1255 challenge->process = acme_challenge_tls_alpn_01;
1256 challenge->token = kore_strdup(token->data.string);
1257 challenge->type = kore_strdup(type->data.string);
1258
1259 auth->challenge = challenge;
1260 } else {
1261 challenge = auth->challenge;
1262 }
1263
1264 challenge->status = stval;
1265
1266 if (challenge->status == ACME_STATUS_INVALID &&
1267 (err = kore_json_find_object(object, "error")) != NULL) {
1268 type = kore_json_find_string(err, "type");
1269 detail = kore_json_find_string(err, "detail");
1270
1271 if (type == NULL || detail == NULL) {
1272 kore_log(LOG_NOTICE,
1273 "[%s:auth:challenge] error missing fields",
1274 order->domain);
1275 } else {
1276 kore_free(challenge->error_type);
1277 kore_free(challenge->error_detail);
1278
1279 challenge->error_type =
1280 kore_strdup(type->data.string);
1281 challenge->error_detail =
1282 kore_strdup(detail->data.string);
1283 }
1284 }
1285
1286 break;
1287 }
1288
1289 if (auth->challenge == NULL) {
1290 kore_log(LOG_NOTICE,
1291 "[%s:auth] no supported challenges found", order->domain);
1292 goto cleanup;
1293 }
1294
1295 ret = KORE_RESULT_OK;
1296
1297 cleanup:
1298 if (ret != KORE_RESULT_OK) {
1299 order->state = ACME_ORDER_STATE_CANCELLED;
1300 } else {
1301 order->auths--;
1302 if (order->auths == 0) {
1303 kore_log(LOG_INFO,
1304 "[%s:auth] authentications done", order->domain);
1305 order->state = ACME_ORDER_STATE_RUNNING;
1306 }
1307 }
1308
1309 kore_json_cleanup(&json);
1310 acme_request_cleanup(&req);
1311 }
1312
1313 static int
1314 acme_challenge_tls_alpn_01(struct acme_order *order,
1315 struct acme_challenge *challenge)
1316 {
1317 int ret;
1318
1319 ret = KORE_RESULT_RETRY;
1320
1321 switch (challenge->status) {
1322 case ACME_STATUS_PENDING:
1323 acme_challenge_tls_alpn_01_create(order, challenge);
1324 break;
1325 case ACME_STATUS_PROCESSING:
1326 kore_log(LOG_INFO,
1327 "[%s:auth:challenge:tls-alpn-01] processing",
1328 order->domain);
1329 break;
1330 case ACME_STATUS_VALID:
1331 kore_log(LOG_INFO,
1332 "[%s:auth:challenge:tls-alpn-01] valid",
1333 order->domain);
1334 ret = KORE_RESULT_OK;
1335 break;
1336 default:
1337 kore_log(LOG_NOTICE,
1338 "[%s:auth:challenge:tls-alpn-01] invalid (%d)",
1339 order->domain, challenge->status);
1340 ret = KORE_RESULT_ERROR;
1341 break;
1342 }
1343
1344 return (ret);
1345 }
1346
1347 static void
1348 acme_challenge_tls_alpn_01_create(struct acme_order *order,
1349 struct acme_challenge *challenge)
1350 {
1351 struct kore_buf auth;
1352 char *thumb;
1353 u_int8_t digest[SHA256_DIGEST_LENGTH];
1354
1355 if (challenge->flags & ACME_FLAG_CHALLENGE_CREATED) {
1356 kore_log(LOG_INFO,
1357 "[%s:auth:challenge:tls-alpn-01] pending keymgr",
1358 order->domain);
1359 return;
1360 }
1361
1362 challenge->flags |= ACME_FLAG_CHALLENGE_CREATED;
1363
1364 kore_log(LOG_INFO,
1365 "[%s:auth:challenge:tls-alpn-01] requested from keymgr",
1366 order->domain);
1367
1368 thumb = acme_thumbprint_component();
1369
1370 kore_buf_init(&auth, 128);
1371 kore_buf_appendf(&auth, "%s.%s", challenge->token, thumb);
1372 (void)SHA256(auth.data, auth.offset, digest);
1373
1374 kore_buf_cleanup(&auth);
1375 kore_free(thumb);
1376
1377 acme_keymgr_key_req(order->domain, digest, sizeof(digest),
1378 KORE_ACME_CHALLENGE_CERT);
1379
1380 /* XXX - this maybe too fast, keymgr may not have had time. */
1381 acme_challenge_respond(order, challenge->url, "tls-alpn-01");
1382 }
1383
1384 static void
1385 acme_challenge_respond(struct acme_order *order, const char *url,
1386 const char *name)
1387 {
1388 struct kore_json_item *json;
1389 char *copy;
1390
1391 kore_log(LOG_INFO, "[%s:auth:challenge:%s] submitting challenge",
1392 order->domain, name);
1393
1394 copy = kore_strdup(url);
1395
1396 json = kore_json_create_object(NULL, NULL);
1397 acme_sign_submit(json, url, copy, acme_generic_submit);
1398 kore_json_item_free(json);
1399 }
1400
1401 static void
1402 acme_generic_submit(struct acme_sign_op *op, struct kore_buf *payload)
1403 {
1404 struct acme_request req;
1405
1406 acme_request_prepare(&req, HTTP_METHOD_POST, op->udata,
1407 payload->data, payload->offset);
1408
1409 if (!acme_request_run(&req))
1410 goto cleanup;
1411
1412 if (req.curl.http.status != HTTP_STATUS_OK) {
1413 kore_log(LOG_NOTICE,
1414 "request to '%s' failed: status %ld - body '%s'",
1415 req.curl.url, req.curl.http.status,
1416 kore_curl_response_as_string(&req.curl));
1417 goto cleanup;
1418 }
1419
1420 kore_log(LOG_INFO, "submitted %zu bytes to %s",
1421 payload->offset, req.curl.url);
1422
1423 cleanup:
1424 acme_request_cleanup(&req);
1425 }
1426
1427 static void
1428 acme_request_prepare(struct acme_request *req, int method,
1429 const char *url, const void *data, size_t len)
1430 {
1431 memset(req, 0, sizeof(*req));
1432
1433 if (!kore_curl_init(&req->curl, url, KORE_CURL_SYNC))
1434 fatal("failed to initialize request to '%s'", url);
1435
1436 /* Override default timeout. */
1437 curl_easy_setopt(req->curl.handle,
1438 CURLOPT_TIMEOUT, acme_request_timeout);
1439
1440 kore_curl_http_setup(&req->curl, method, data, len);
1441 kore_curl_http_set_header(&req->curl, "content-type",
1442 "application/jose+json");
1443 }
1444
1445 static void
1446 acme_request_json(struct kore_buf *buf, const char *payload,
1447 const char *protected, const char *sig)
1448 {
1449 struct kore_json_item *json;
1450
1451 json = kore_json_create_object(NULL, NULL);
1452
1453 kore_json_create_string(json, "signature", sig);
1454 kore_json_create_string(json, "payload", payload);
1455 kore_json_create_string(json, "protected", protected);
1456
1457 kore_json_item_tobuf(json, buf);
1458 kore_json_item_free(json);
1459 }
1460
1461 static int
1462 acme_request_run(struct acme_request *req)
1463 {
1464 size_t len;
1465 struct kore_json json;
1466 const u_int8_t *body;
1467 struct kore_json_item *detail;
1468
1469 kore_curl_run(&req->curl);
1470
1471 if (!kore_curl_success(&req->curl)) {
1472 kore_log(LOG_NOTICE, "request to '%s' failed: %s",
1473 req->curl.url, kore_curl_strerror(&req->curl));
1474 return (KORE_RESULT_ERROR);
1475 }
1476
1477 if (req->curl.http.status == HTTP_STATUS_BAD_REQUEST) {
1478 kore_curl_response_as_bytes(&req->curl, &body, &len);
1479 kore_json_init(&json, body, len);
1480
1481 if (!kore_json_parse(&json)) {
1482 detail = NULL;
1483 } else {
1484 detail = kore_json_find_string(json.root, "detail");
1485 }
1486
1487 if (detail != NULL) {
1488 kore_log(LOG_NOTICE,
1489 "request to '%s' failed with 400 - detail: %s",
1490 req->curl.url, detail->data.string);
1491 } else {
1492 kore_log(LOG_NOTICE,
1493 "request to '%s' failed with 400 - body: %.*s",
1494 req->curl.url, (int)len, (const char *)body);
1495 }
1496
1497 kore_json_cleanup(&json);
1498 return (KORE_RESULT_ERROR);
1499 }
1500
1501 return (KORE_RESULT_OK);
1502 }
1503
1504 static void
1505 acme_request_cleanup(struct acme_request *req)
1506 {
1507 kore_curl_cleanup(&req->curl);
1508 }
1509
1510 static void
1511 acme_directory_set(struct kore_json *json, const char *name, char **out)
1512 {
1513 struct kore_json_item *item;
1514
1515 if ((item = kore_json_find_string(json->root, name)) == NULL) {
1516 kore_log(LOG_NOTICE, "directory has missing '%s' URI", name);
1517 return;
1518 }
1519
1520 *out = kore_strdup(item->data.string);
1521 }
1522
1523 static void
1524 acme_sign_submit(struct kore_json_item *json, const char *url, void *udata,
1525 void (*cb)(struct acme_sign_op *, struct kore_buf *))
1526 {
1527 struct acme_sign_op *op;
1528 struct kore_buf buf;
1529 char *nonce;
1530
1531 if ((nonce = acme_nonce_fetch()) == NULL) {
1532 kore_log(LOG_ERR, "failed to fetch nonce from servers");
1533 return;
1534 }
1535
1536 kore_buf_init(&buf, 1024);
1537
1538 if (json != NULL)
1539 kore_json_item_tobuf(json, &buf);
1540
1541 op = kore_calloc(1, sizeof(*op));
1542 LIST_INSERT_HEAD(&signops, op, list);
1543
1544 op->cb = cb;
1545 op->udata = udata;
1546 op->nonce = nonce;
1547 op->id = signop_id++;
1548 op->payload = acme_base64url(buf.data, buf.offset);
1549 op->protected = acme_protected_component(op->nonce, url);
1550 op->t = kore_timer_add(acme_sign_expire, 30000, op, KORE_TIMER_ONESHOT);
1551
1552 kore_buf_reset(&buf);
1553 kore_buf_append(&buf, &op->id, sizeof(op->id));
1554 kore_buf_appendf(&buf, "%s.%s", op->protected, op->payload);
1555
1556 kore_msg_send(KORE_WORKER_KEYMGR, KORE_ACME_SIGN, buf.data, buf.offset);
1557 kore_buf_cleanup(&buf);
1558 }
1559
1560 static void
1561 acme_sign_expire(void *udata, u_int64_t now)
1562 {
1563 struct acme_sign_op *op = udata;
1564
1565 kore_log(LOG_NOTICE, "signop %u expired (no answer)", op->id);
1566
1567 LIST_REMOVE(op, list);
1568
1569 kore_free(op->protected);
1570 kore_free(op->payload);
1571 kore_free(op->udata);
1572 kore_free(op->nonce);
1573 kore_free(op);
1574 }
1575
1576 static void
1577 acme_sign_result(struct kore_msg *msg, const void *data)
1578 {
1579 u_int32_t id;
1580 struct kore_buf buf;
1581 struct acme_sign_op *op;
1582 char *sig;
1583 const u_int8_t *ptr;
1584
1585 if (msg->length < sizeof(id))
1586 fatal("%s: invalid length (%zu)", __func__, msg->length);
1587
1588 ptr = data;
1589 memcpy(&id, ptr, sizeof(id));
1590
1591 ptr += sizeof(id);
1592 msg->length -= sizeof(id);
1593
1594 LIST_FOREACH(op, &signops, list) {
1595 if (op->id == id)
1596 break;
1597 }
1598
1599 if (op == NULL) {
1600 kore_log(LOG_NOTICE,
1601 "received KORE_ACME_SIGN_RESULT for unknown op: %u", id);
1602 return;
1603 }
1604
1605 kore_timer_remove(op->t);
1606 LIST_REMOVE(op, list);
1607
1608 sig = kore_malloc(msg->length + 1);
1609 memcpy(sig, ptr, msg->length);
1610 sig[msg->length] = '\0';
1611
1612 kore_buf_init(&buf, 1024);
1613 acme_request_json(&buf, op->payload, op->protected, sig);
1614
1615 op->cb(op, &buf);
1616
1617 kore_free(op->protected);
1618 kore_free(op->payload);
1619 kore_free(op->udata);
1620 kore_free(op->nonce);
1621 kore_free(op);
1622
1623 kore_free(sig);
1624 kore_buf_cleanup(&buf);
1625 }
1626
1627 static char *
1628 acme_protected_component(const char *nonce, const char *url)
1629 {
1630 char *b64;
1631 struct kore_buf payload;
1632 struct kore_json_item *root, *jwk;
1633
1634 root = kore_json_create_object(NULL, NULL);
1635
1636 kore_json_create_string(root, "url", url);
1637 kore_json_create_string(root, "alg", "RS256");
1638 kore_json_create_string(root, "nonce", nonce);
1639
1640 if (account_id == NULL) {
1641 jwk = kore_json_create_object(root, "jwk");
1642 kore_json_create_string(jwk, "kty", "RSA");
1643 kore_json_create_string(jwk, "e", rsakey_e);
1644 kore_json_create_string(jwk, "n", rsakey_n);
1645 } else {
1646 kore_json_create_string(root, "kid", account_id);
1647 }
1648
1649 kore_buf_init(&payload, 128);
1650 kore_json_item_tobuf(root, &payload);
1651
1652 b64 = acme_base64url(payload.data, payload.offset);
1653
1654 kore_json_item_free(root);
1655 kore_buf_cleanup(&payload);
1656
1657 return (b64);
1658 }
1659
1660 static char *
1661 acme_thumbprint_component(void)
1662 {
1663 struct kore_json_item *json;
1664 struct kore_buf payload;
1665 u_int8_t digest[SHA256_DIGEST_LENGTH];
1666
1667 json = kore_json_create_object(NULL, NULL);
1668
1669 /* Order matters here, see RFC7638. */
1670 kore_json_create_string(json, "e", rsakey_e);
1671 kore_json_create_string(json, "kty", "RSA");
1672 kore_json_create_string(json, "n", rsakey_n);
1673
1674 kore_buf_init(&payload, 128);
1675 kore_json_item_tobuf(json, &payload);
1676
1677 (void)SHA256(payload.data, payload.offset, digest);
1678
1679 kore_json_item_free(json);
1680 kore_buf_cleanup(&payload);
1681
1682 return (acme_base64url(digest, sizeof(digest)));
1683 }
1684
1685 static char *
1686 acme_base64url(const void *data, size_t len)
1687 {
1688 char *b64;
1689
1690 if (!kore_base64url_encode(data, len, &b64, KORE_BASE64_RAW)) {
1691 fatal("%s: failed to encode base64url data of %zu bytes",
1692 __func__, len);
1693 }
1694
1695 return (b64);
1696 }
1697
1698 static void
1699 acme_keymgr_key_req(const char *domain, const void *data, size_t len, int msg)
1700 {
1701 struct kore_keyreq req;
1702 struct kore_buf buf;
1703
1704 memset(&req, 0, sizeof(req));
1705 req.data_len = len;
1706
1707 if (kore_strlcpy(req.domain, domain, sizeof(req.domain)) >=
1708 sizeof(req.domain))
1709 fatal("%s: domain truncated", __func__);
1710
1711 kore_buf_init(&buf, sizeof(req) + len);
1712 kore_buf_append(&buf, &req, sizeof(req));
1713
1714 if (data != NULL)
1715 kore_buf_append(&buf, data, len);
1716
1717 kore_msg_send(KORE_WORKER_KEYMGR, msg, buf.data, buf.offset);
1718 kore_buf_cleanup(&buf);
1719 }
1720
1721 static int
1722 acme_status_type(const char *status)
1723 {
1724 int type;
1725
1726 if (!strcmp(status, "pending")) {
1727 type = ACME_STATUS_PENDING;
1728 } else if (!strcmp(status, "processing")) {
1729 type = ACME_STATUS_PROCESSING;
1730 } else if (!strcmp(status, "valid")) {
1731 type = ACME_STATUS_VALID;
1732 } else if (!strcmp(status, "invalid")) {
1733 type = ACME_STATUS_INVALID;
1734 } else if (!strcmp(status, "ready")) {
1735 type = ACME_STATUS_READY;
1736 } else if (!strcmp(status, "expired")) {
1737 type = ACME_STATUS_EXPIRED;
1738 } else if (!strcmp(status, "revoked")) {
1739 type = ACME_STATUS_REVOKED;
1740 } else {
1741 type = -1;
1742 }
1743
1744 return (type);
1745 }
1746
1747 static void
1748 acme_rsakey_exp(struct kore_msg *msg, const void *data)
1749 {
1750 kore_free(rsakey_e);
1751 rsakey_e = kore_calloc(1, msg->length + 1);
1752 memcpy(rsakey_e, data, msg->length);
1753 rsakey_e[msg->length] = '\0';
1754 }
1755
1756 static void
1757 acme_rsakey_mod(struct kore_msg *msg, const void *data)
1758 {
1759 kore_free(rsakey_n);
1760 rsakey_n = kore_calloc(1, msg->length + 1);
1761 memcpy(rsakey_n, data, msg->length);
1762 rsakey_n[msg->length] = '\0';
1763 }