1 /* $OpenBSD: ocsp.c,v 1.25 2024/01/17 08:25:02 claudio Exp $ */
2
3 /*
4 * Copyright (c) 2014 Markus Friedl
5 * Copyright (c) 2005 Marco Pfatschbacher
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 #include <sys/queue.h>
21 #include <sys/socket.h>
22 #include <sys/uio.h>
23 #include <sys/stat.h>
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <netdb.h>
32
33 #include <openssl/pem.h>
34 #include <openssl/ocsp.h>
35 #include <openssl/err.h>
36 #include <openssl/ssl.h>
37
38 #include <event.h>
39
40 #include "iked.h"
41
42 struct iked_ocsp {
43 struct iked *ocsp_env; /* back pointer to env */
44 struct iked_sahdr ocsp_sh; /* ike sa */
45 uint8_t ocsp_type; /* auth type */
46 struct iked_socket *ocsp_sock; /* socket to ocsp responder */
47 BIO *ocsp_cbio; /* matching OpenSSL obj */
48 OCSP_CERTID *ocsp_id; /* ocsp-id for cert */
49 OCSP_REQUEST *ocsp_req; /* ocsp-request */
50 OCSP_REQ_CTX *ocsp_req_ctx; /* async ocsp-request */
51 };
52
53 struct ocsp_connect {
54 struct iked_sahdr oc_sh;
55 struct iked_socket oc_sock;
56 char *oc_path;
57 char *oc_url;
58 };
59
60 #define OCSP_TIMEOUT 30
61
62 /* priv */
63 void ocsp_connect_cb(int, short, void *);
64 int ocsp_connect_finish(struct iked *, int, struct ocsp_connect *);
65
66 /* unpriv */
67 void ocsp_free(struct iked_ocsp *);
68 void ocsp_callback(int, short, void *);
69 void ocsp_parse_response(struct iked_ocsp *, OCSP_RESPONSE *);
70 STACK_OF(X509) *ocsp_load_certs(const char *);
71 int ocsp_validate_finish(struct iked_ocsp *, int);
72
73
74 /* priv */
75
76 /* async connect to configure ocsp-responder */
77 int
ocsp_connect(struct iked * env,struct imsg * imsg)78 ocsp_connect(struct iked *env, struct imsg *imsg)
79 {
80 struct ocsp_connect *oc = NULL;
81 struct iked_sahdr sh;
82 struct addrinfo hints, *res0 = NULL, *res;
83 struct timeval tv;
84 uint8_t *ptr;
85 size_t len;
86 char *host = NULL, *port = NULL, *path = NULL;
87 char *url, *freeme = NULL;
88 int use_ssl, fd = -1, ret = -1, error;
89
90 IMSG_SIZE_CHECK(imsg, &sh);
91
92 ptr = (uint8_t *)imsg->data;
93 len = IMSG_DATA_SIZE(imsg);
94
95 memcpy(&sh, ptr, sizeof(sh));
96
97 ptr += sizeof(sh);
98 len -= sizeof(sh);
99
100 if (len > 0)
101 url = freeme = get_string(ptr, len);
102 else if (env->sc_ocsp_url)
103 url = env->sc_ocsp_url;
104 else {
105 log_warnx("%s: no ocsp url", SPI_SH(&sh, __func__));
106 goto done;
107 }
108 if (!OCSP_parse_url(url, &host, &port, &path, &use_ssl)) {
109 log_warnx("%s: error parsing OCSP-request-URL: %s",
110 SPI_SH(&sh, __func__), url);
111 goto done;
112 }
113 if (use_ssl) {
114 log_warnx("%s: OCSP over SSL not supported: %s",
115 SPI_SH(&sh, __func__), url);
116 goto done;
117 }
118
119 if ((fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1) {
120 log_debug("%s: socket failed", SPI_SH(&sh, __func__));
121 goto done;
122 }
123 if ((oc = calloc(1, sizeof(*oc))) == NULL) {
124 log_debug("%s: calloc failed", __func__);
125 goto done;
126 }
127
128 bzero(&hints, sizeof(struct addrinfo));
129 hints.ai_family = PF_UNSPEC;
130 hints.ai_socktype = SOCK_STREAM;
131 error = getaddrinfo(host, port, &hints, &res0);
132 if (error) {
133 log_warn("%s: getaddrinfo(%s, %s) failed",
134 SPI_SH(&sh, __func__), host, port);
135 goto done;
136 }
137 /* XXX just pick the first answer. we could loop instead */
138 for (res = res0; res; res = res->ai_next)
139 if (res->ai_family == AF_INET)
140 break;
141 if (res == NULL) {
142 log_debug("%s: no addr to connect to for %s:%s",
143 SPI_SH(&sh, __func__), host, port);
144 goto done;
145 }
146
147 oc->oc_sock.sock_fd = fd;
148 oc->oc_sock.sock_env = env;
149 oc->oc_sh = sh;
150 oc->oc_path = path;
151 oc->oc_url = strdup(url);
152 if (oc->oc_url == NULL) {
153 log_warn("%s: strdup failed", SPI_SH(&sh, __func__));
154 goto done;
155 }
156 path = NULL;
157
158 log_debug("%s: connect(%s, %s)", __func__, host, port);
159 if (connect(fd, res->ai_addr, res->ai_addrlen) == -1) {
160 /* register callback for ansync connect */
161 if (errno == EINPROGRESS) {
162 tv.tv_sec = OCSP_TIMEOUT;
163 tv.tv_usec = 0;
164 event_set(&oc->oc_sock.sock_ev, fd, EV_WRITE,
165 ocsp_connect_cb, oc);
166 event_add(&oc->oc_sock.sock_ev, &tv);
167 ret = 0;
168 } else
169 log_warn("%s: connect(%s, %s)",
170 SPI_SH(&oc->oc_sh, __func__), host, port);
171 } else {
172 ocsp_connect_finish(env, fd, oc);
173 ret = 0;
174 }
175 done:
176 if (res0)
177 freeaddrinfo(res0);
178 free(freeme);
179 free(host);
180 free(port);
181 free(path);
182 if (ret == -1) {
183 ocsp_connect_finish(env, -1, oc);
184 if (fd >= 0)
185 close(fd);
186 }
187 return (ret);
188 }
189
190 /* callback triggered if connection to ocsp-responder completes/fails */
191 void
ocsp_connect_cb(int fd,short event,void * arg)192 ocsp_connect_cb(int fd, short event, void *arg)
193 {
194 struct ocsp_connect *oc = arg;
195 int error, send_fd = -1;
196 socklen_t len;
197
198 if (event == EV_TIMEOUT) {
199 log_info("%s: timeout, giving up",
200 SPI_SH(&oc->oc_sh, __func__));
201 goto done;
202 }
203
204 len = sizeof(error);
205 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) == -1) {
206 log_warn("%s: getsockopt SOL_SOCKET SO_ERROR",
207 SPI_SH(&oc->oc_sh, __func__));
208 } else if (error) {
209 log_warnx("%s: error while connecting: %s",
210 SPI_SH(&oc->oc_sh, __func__), strerror(error));
211 } else {
212 send_fd = fd;
213 }
214 done:
215 ocsp_connect_finish(oc->oc_sock.sock_env, send_fd, oc);
216
217 /* if we did not send the fd, we need to close it ourself */
218 if (send_fd == -1)
219 close(fd);
220 }
221
222 /* send FD+path or error back to CA process */
223 int
ocsp_connect_finish(struct iked * env,int fd,struct ocsp_connect * oc)224 ocsp_connect_finish(struct iked *env, int fd, struct ocsp_connect *oc)
225 {
226 struct iovec iov[2];
227 int iovcnt = 0, ret;
228
229 iov[iovcnt].iov_base = &oc->oc_sh;
230 iov[iovcnt].iov_len = sizeof(oc->oc_sh);
231 iovcnt++;
232
233 if (oc && fd >= 0) {
234 /* the imsg framework will close the FD after send */
235 iov[iovcnt].iov_base = oc->oc_path;
236 iov[iovcnt].iov_len = strlen(oc->oc_path);
237 iovcnt++;
238 ret = proc_composev_imsg(&env->sc_ps, PROC_CERT, -1,
239 IMSG_OCSP_FD, -1, fd, iov, iovcnt);
240 } else {
241 if (oc)
242 log_info("%s: connect failed for %s",
243 SPI_SH(&oc->oc_sh, __func__),
244 oc->oc_url ? oc->oc_url : "unknown");
245 else
246 log_info("%s: connect failed", __func__);
247 ret = proc_composev_imsg(&env->sc_ps, PROC_CERT, -1,
248 IMSG_OCSP_FD, -1, -1, iov, iovcnt);
249 if (fd >= 0)
250 close(fd);
251 }
252 if (oc) {
253 free(oc->oc_url);
254 free(oc->oc_path);
255 free(oc);
256 }
257 return (ret);
258 }
259
260
261 /* unpriv */
262
263 /* validate the certifcate stored in 'data' by querying the ocsp-responder */
264 int
ocsp_validate_cert(struct iked * env,void * data,size_t len,struct iked_sahdr sh,uint8_t type,X509 * issuer)265 ocsp_validate_cert(struct iked *env, void *data, size_t len,
266 struct iked_sahdr sh, uint8_t type, X509 *issuer)
267 {
268 struct iovec iov[2];
269 STACK_OF(OPENSSL_STRING) *aia; /* Authority Information Access */
270 struct iked_ocsp_entry *ioe;
271 struct iked_ocsp *ocsp;
272 OCSP_CERTID *id = NULL;
273 char *url;
274 BIO *rawcert = NULL;
275 X509 *cert = NULL;
276 int ret, iovcnt = 0;
277
278 if (issuer == NULL)
279 return (-1);
280 if ((ioe = calloc(1, sizeof(*ioe))) == NULL)
281 return (-1);
282 if ((ocsp = calloc(1, sizeof(*ocsp))) == NULL) {
283 free(ioe);
284 return (-1);
285 }
286
287 ocsp->ocsp_env = env;
288 ocsp->ocsp_sh = sh;
289 ocsp->ocsp_type = type;
290
291 if ((rawcert = BIO_new_mem_buf(data, len)) == NULL ||
292 (cert = d2i_X509_bio(rawcert, NULL)) == NULL ||
293 (ocsp->ocsp_cbio = BIO_new(BIO_s_socket())) == NULL ||
294 (ocsp->ocsp_req = OCSP_REQUEST_new()) == NULL ||
295 (id = OCSP_cert_to_id(NULL, cert, issuer)) == NULL ||
296 !OCSP_request_add0_id(ocsp->ocsp_req, id))
297 goto err;
298
299 /* id is owned by and freed together with ocsp_req */
300 ocsp->ocsp_id = id;
301
302 BIO_free(rawcert);
303 X509_free(cert);
304
305 ioe->ioe_ocsp = ocsp;
306 TAILQ_INSERT_TAIL(&env->sc_ocsp, ioe, ioe_entry);
307
308 /* pass SA header */
309 iov[iovcnt].iov_base = &ocsp->ocsp_sh;
310 iov[iovcnt].iov_len = sizeof(ocsp->ocsp_sh);
311 iovcnt++;
312
313 /* pass optional ocsp-url from issuer */
314 if ((aia = X509_get1_ocsp(issuer)) != NULL) {
315 url = sk_OPENSSL_STRING_value(aia, 0);
316 log_debug("%s: aia %s", __func__, url);
317 iov[iovcnt].iov_base = url;
318 iov[iovcnt].iov_len = strlen(url);
319 iovcnt++;
320 }
321 /* request connection to ocsp-responder */
322 ret = proc_composev(&env->sc_ps, PROC_PARENT, IMSG_OCSP_FD,
323 iov, iovcnt);
324
325 X509_email_free(aia); /* free stack of openssl strings */
326
327 return (ret);
328
329 err:
330 ca_sslerror(__func__);
331 free(ioe);
332 BIO_free(rawcert);
333 X509_free(cert);
334 OCSP_CERTID_free(id);
335 ocsp_validate_finish(ocsp, 0); /* failed */
336 return (-1);
337 }
338
339 /* free ocsp query context */
340 void
ocsp_free(struct iked_ocsp * ocsp)341 ocsp_free(struct iked_ocsp *ocsp)
342 {
343 if (ocsp != NULL) {
344 if (ocsp->ocsp_sock != NULL) {
345 close(ocsp->ocsp_sock->sock_fd);
346 free(ocsp->ocsp_sock);
347 }
348 BIO_free_all(ocsp->ocsp_cbio);
349 OCSP_REQ_CTX_free(ocsp->ocsp_req_ctx);
350 OCSP_REQUEST_free(ocsp->ocsp_req);
351 free(ocsp);
352 }
353 }
354
355 /* we got a connection to the ocsp responder */
356 int
ocsp_receive_fd(struct iked * env,struct imsg * imsg)357 ocsp_receive_fd(struct iked *env, struct imsg *imsg)
358 {
359 struct iked_ocsp_entry *ioe = NULL;
360 struct iked_ocsp *ocsp = NULL, *ocsp_tmp;
361 struct iked_socket *sock;
362 struct iked_sahdr sh;
363 struct timeval tv;
364 uint8_t *ptr;
365 char *path = NULL;
366 size_t len;
367 int fd, ret = -1;
368
369 IMSG_SIZE_CHECK(imsg, &sh);
370
371 ptr = (uint8_t *)imsg->data;
372 len = IMSG_DATA_SIZE(imsg);
373
374 memcpy(&sh, ptr, sizeof(sh));
375
376 ptr += sizeof(sh);
377 len -= sizeof(sh);
378
379 TAILQ_FOREACH(ioe, &env->sc_ocsp, ioe_entry) {
380 ocsp_tmp = ioe->ioe_ocsp;
381 if (memcmp(&ocsp_tmp->ocsp_sh, &sh, sizeof(sh)) == 0)
382 break;
383 }
384 if (ioe == NULL) {
385 log_debug("%s: no pending request found", __func__);
386 if ((fd = imsg_get_fd(imsg)) != -1) /* XXX */
387 close(fd);
388 return (-1);
389 }
390 TAILQ_REMOVE(&env->sc_ocsp, ioe, ioe_entry);
391 ocsp = ioe->ioe_ocsp;
392 free(ioe);
393
394 if ((fd = imsg_get_fd(imsg)) == -1)
395 goto done;
396
397 if ((sock = calloc(1, sizeof(*sock))) == NULL)
398 fatal("ocsp_receive_fd: calloc sock");
399
400 /* note that sock_addr is not set */
401 sock->sock_fd = fd;
402 sock->sock_env = env;
403 ocsp->ocsp_sock = sock;
404
405 log_debug("%s: received socket fd %d", __func__, sock->sock_fd);
406
407 /* fetch 'path' and 'fd' from imsg */
408 if ((path = get_string(ptr, len)) == NULL)
409 goto done;
410
411 BIO_set_fd(ocsp->ocsp_cbio, sock->sock_fd, BIO_NOCLOSE);
412
413 if ((ocsp->ocsp_req_ctx = OCSP_sendreq_new(ocsp->ocsp_cbio,
414 path, NULL, -1)) == NULL)
415 goto done;
416 if (!OCSP_REQ_CTX_set1_req(ocsp->ocsp_req_ctx, ocsp->ocsp_req))
417 goto done;
418
419 tv.tv_sec = OCSP_TIMEOUT;
420 tv.tv_usec = 0;
421 event_set(&sock->sock_ev, sock->sock_fd, EV_WRITE, ocsp_callback, ocsp);
422 event_add(&sock->sock_ev, &tv);
423 ret = 0;
424 done:
425 if (ret == -1)
426 ocsp_validate_finish(ocsp, 0); /* failed */
427 free(path);
428 return (ret);
429 }
430
431 /* load a stack of x509 certificates */
STACK_OF(X509)432 STACK_OF(X509)*
433 ocsp_load_certs(const char *file)
434 {
435 BIO *bio = NULL;
436 STACK_OF(X509) *certs = NULL;
437 STACK_OF(X509_INFO) *xis = NULL;
438 X509_INFO *xi;
439 int i;
440
441 if ((bio = BIO_new_file(file, "r")) == NULL) {
442 log_warn("%s: BIO_new_file failed for %s",
443 __func__, file);
444 return (NULL);
445 }
446 if ((xis = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL)) == NULL) {
447 ca_sslerror(__func__);
448 goto done;
449 }
450 if ((certs = sk_X509_new_null()) == NULL) {
451 log_debug("%s: sk_X509_new_null failed for %s", __func__, file);
452 goto done;
453 }
454 for (i = 0; i < sk_X509_INFO_num(xis); i++) {
455 xi = sk_X509_INFO_value(xis, i);
456 if (xi->x509) {
457 if (!sk_X509_push(certs, xi->x509))
458 goto done;
459 xi->x509 = NULL;
460 }
461 }
462
463 done:
464 BIO_free(bio);
465 sk_X509_INFO_pop_free(xis, X509_INFO_free);
466 if (sk_X509_num(certs) <= 0) {
467 sk_X509_free(certs);
468 certs = NULL;
469 }
470 return (certs);
471 }
472
473 /* read/write callback that sends the requests and reads the ocsp response */
474 void
ocsp_callback(int fd,short event,void * arg)475 ocsp_callback(int fd, short event, void *arg)
476 {
477 struct iked_ocsp *ocsp = arg;
478 struct iked_socket *sock = ocsp->ocsp_sock;
479 struct timeval tv;
480 OCSP_RESPONSE *resp = NULL;
481
482 if (event == EV_TIMEOUT) {
483 log_info("%s: timeout, giving up",
484 SPI_SH(&ocsp->ocsp_sh, __func__));
485 ocsp_validate_finish(ocsp, 0);
486 return;
487 }
488 /*
489 * Only call OCSP_sendreq_nbio() if should_read/write is
490 * either not requested or read/write can be called.
491 */
492 if ((!BIO_should_read(ocsp->ocsp_cbio) || (event & EV_READ)) &&
493 (!BIO_should_write(ocsp->ocsp_cbio) || (event & EV_WRITE)) &&
494 OCSP_sendreq_nbio(&resp, ocsp->ocsp_req_ctx) != -1 ) {
495 ocsp_parse_response(ocsp, resp);
496 return;
497 }
498 if (BIO_should_read(ocsp->ocsp_cbio))
499 event_set(&sock->sock_ev, sock->sock_fd, EV_READ,
500 ocsp_callback, ocsp);
501 else if (BIO_should_write(ocsp->ocsp_cbio))
502 event_set(&sock->sock_ev, sock->sock_fd, EV_WRITE,
503 ocsp_callback, ocsp);
504 tv.tv_sec = OCSP_TIMEOUT;
505 tv.tv_usec = 0;
506 event_add(&sock->sock_ev, &tv);
507 }
508
509 /* parse the actual OCSP response */
510 void
ocsp_parse_response(struct iked_ocsp * ocsp,OCSP_RESPONSE * resp)511 ocsp_parse_response(struct iked_ocsp *ocsp, OCSP_RESPONSE *resp)
512 {
513 struct iked *env = ocsp->ocsp_env;
514 X509_STORE *store = NULL;
515 STACK_OF(X509) *verify_other = NULL;
516 OCSP_BASICRESP *bs = NULL;
517 ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
518 const char *errstr;
519 int reason = 0, valid = 0, verify_flags = 0;
520 int status;
521
522 if (!resp) {
523 errstr = "error querying OCSP responder";
524 goto done;
525 }
526
527 status = OCSP_response_status(resp);
528 if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
529 errstr = OCSP_response_status_str(status);
530 goto done;
531 }
532
533 verify_other = ocsp_load_certs(IKED_OCSP_RESPCERT);
534 verify_flags |= OCSP_TRUSTOTHER;
535 if (!verify_other) {
536 errstr = "no verify_other";
537 goto done;
538 }
539
540 bs = OCSP_response_get1_basic(resp);
541 if (!bs) {
542 errstr = "error parsing response";
543 goto done;
544 }
545
546 status = OCSP_check_nonce(ocsp->ocsp_req, bs);
547 if (status <= 0) {
548 if (status == -1)
549 log_warnx("%s: no nonce in response",
550 SPI_SH(&ocsp->ocsp_sh, __func__));
551 else {
552 errstr = "nonce verify error";
553 goto done;
554 }
555 }
556
557 store = X509_STORE_new();
558 status = OCSP_basic_verify(bs, verify_other, store, verify_flags);
559 if (status < 0)
560 status = OCSP_basic_verify(bs, NULL, store, 0);
561 if (status <= 0) {
562 ca_sslerror(__func__);
563 errstr = "response verify failure";
564 goto done;
565 }
566 log_debug("%s: response verify ok", SPI_SH(&ocsp->ocsp_sh, __func__));
567
568 if (!OCSP_resp_find_status(bs, ocsp->ocsp_id, &status, &reason,
569 &rev, &thisupd, &nextupd)) {
570 errstr = "no status found";
571 goto done;
572 }
573 if (env->sc_ocsp_tolerate &&
574 !OCSP_check_validity(thisupd, nextupd, env->sc_ocsp_tolerate,
575 env->sc_ocsp_maxage)) {
576 ca_sslerror(SPI_SH(&ocsp->ocsp_sh, __func__));
577 errstr = "status times invalid";
578 goto done;
579 }
580 errstr = OCSP_cert_status_str(status);
581 if (status == V_OCSP_CERTSTATUS_GOOD) {
582 log_debug("%s: status: %s", SPI_SH(&ocsp->ocsp_sh, __func__),
583 errstr);
584 valid = 1;
585 }
586 done:
587 if (!valid) {
588 log_debug("%s: status: %s", __func__, errstr);
589 }
590 X509_STORE_free(store);
591 sk_X509_pop_free(verify_other, X509_free);
592 OCSP_RESPONSE_free(resp);
593 OCSP_BASICRESP_free(bs);
594
595 ocsp_validate_finish(ocsp, valid);
596 }
597
598 /*
599 * finish the ocsp_validate_cert() RPC by sending the appropriate
600 * message back to the IKEv2 process
601 */
602 int
ocsp_validate_finish(struct iked_ocsp * ocsp,int valid)603 ocsp_validate_finish(struct iked_ocsp *ocsp, int valid)
604 {
605 struct iked *env = ocsp->ocsp_env;
606 struct iovec iov[2];
607 int iovcnt = 2, ret, cmd;
608
609 iov[0].iov_base = &ocsp->ocsp_sh;
610 iov[0].iov_len = sizeof(ocsp->ocsp_sh);
611 iov[1].iov_base = &ocsp->ocsp_type;
612 iov[1].iov_len = sizeof(ocsp->ocsp_type);
613
614 cmd = valid ? IMSG_CERTVALID : IMSG_CERTINVALID;
615 ret = proc_composev(&env->sc_ps, PROC_IKEV2, cmd, iov, iovcnt);
616
617 ocsp_free(ocsp);
618 return (ret);
619 }
620