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
42struct 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
53struct 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 */
63void		 ocsp_connect_cb(int, short, void *);
64int		 ocsp_connect_finish(struct iked *, int, struct ocsp_connect *);
65
66/* unpriv */
67void		 ocsp_free(struct iked_ocsp *);
68void		 ocsp_callback(int, short, void *);
69void		 ocsp_parse_response(struct iked_ocsp *, OCSP_RESPONSE *);
70STACK_OF(X509)	*ocsp_load_certs(const char *);
71int		 ocsp_validate_finish(struct iked_ocsp *, int);
72
73
74/* priv */
75
76/* async connect to configure ocsp-responder */
77int
78ocsp_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 */
191void
192ocsp_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 */
223int
224ocsp_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 */
264int
265ocsp_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 */
340void
341ocsp_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 */
356int
357ocsp_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 */
432STACK_OF(X509)*
433ocsp_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 */
474void
475ocsp_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 */
510void
511ocsp_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 */
602int
603ocsp_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