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