xref: /openbsd-src/sbin/iked/ocsp.c (revision 1a8dbaac879b9f3335ad7fb25429ce63ac1d6bac)
1 /*	$OpenBSD: ocsp.c,v 1.20 2020/09/03 14:50:40 tobhe 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
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", __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", __func__,
110 		    url);
111 		goto done;
112 	}
113 	if (use_ssl) {
114 		log_warnx("%s: OCSP over SSL not supported: %s", __func__,
115 		    url);
116 		goto done;
117 	}
118 
119 	if ((fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1) {
120 		log_debug("%s: socket failed", __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 		    __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 	path = NULL;
153 
154 	log_debug("%s: connect(%s, %s)", __func__, host, port);
155 	if (connect(fd, res->ai_addr, res->ai_addrlen) == -1) {
156 		/* register callback for ansync connect */
157 		if (errno == EINPROGRESS) {
158 			tv.tv_sec = OCSP_TIMEOUT;
159 			tv.tv_usec = 0;
160 			event_set(&oc->oc_sock.sock_ev, fd, EV_WRITE,
161 			    ocsp_connect_cb, oc);
162 			event_add(&oc->oc_sock.sock_ev, &tv);
163 			ret = 0;
164 		} else
165 			log_warn("%s: connect(%s, %s)",
166 			    SPI_SH(&oc->oc_sh, __func__), host, port);
167 	} else {
168 		ocsp_connect_finish(env, fd, oc);
169 		ret = 0;
170 	}
171  done:
172 	if (res0)
173 		freeaddrinfo(res0);
174 	free(freeme);
175 	free(host);
176 	free(port);
177 	free(path);
178 	if (ret == -1) {
179 		ocsp_connect_finish(env, -1, oc);
180 		if (fd >= 0)
181 			close(fd);
182 	}
183 	return (ret);
184 }
185 
186 /* callback triggered if connection to ocsp-responder completes/fails */
187 void
188 ocsp_connect_cb(int fd, short event, void *arg)
189 {
190 	struct ocsp_connect	*oc = arg;
191 	int			 error, send_fd = -1;
192 	socklen_t		 len;
193 
194 	if (event == EV_TIMEOUT) {
195 		log_info("%s: timeout, giving up",
196 		    SPI_SH(&oc->oc_sh, __func__));
197 		goto done;
198 	}
199 
200 	len = sizeof(error);
201 	if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) == -1) {
202 		log_warn("%s: getsockopt SOL_SOCKET SO_ERROR", __func__);
203 	} else if (error) {
204 		log_warnx("%s: error while connecting: %s",
205 		    SPI_SH(&oc->oc_sh, __func__), strerror(error));
206 	} else {
207 		send_fd = fd;
208 	}
209  done:
210 	ocsp_connect_finish(oc->oc_sock.sock_env, send_fd, oc);
211 
212 	/* if we did not send the fd, we need to close it ourself */
213 	if (send_fd == -1)
214 		close(fd);
215 }
216 
217 /* send FD+path or error back to CA process */
218 int
219 ocsp_connect_finish(struct iked *env, int fd, struct ocsp_connect *oc)
220 {
221 	struct iovec		 iov[2];
222 	int			 iovcnt = 0, ret;
223 
224 	iov[iovcnt].iov_base = &oc->oc_sh;
225 	iov[iovcnt].iov_len = sizeof(oc->oc_sh);
226 	iovcnt++;
227 
228 	if (oc && fd >= 0) {
229 		/* the imsg framework will close the FD after send */
230 		iov[iovcnt].iov_base = oc->oc_path;
231 		iov[iovcnt].iov_len = strlen(oc->oc_path);
232 		iovcnt++;
233 		ret = proc_composev_imsg(&env->sc_ps, PROC_CERT, -1,
234 		    IMSG_OCSP_FD, -1, fd, iov, iovcnt);
235 	} else {
236 		if (oc)
237 			log_info("%s: connect failed for %s",
238 			    SPI_SH(&oc->oc_sh, __func__),
239 			    oc->oc_url ? oc->oc_url : "unknown");
240 		else
241 			log_info("%s: connect failed", __func__);
242 		ret = proc_composev_imsg(&env->sc_ps, PROC_CERT, -1,
243 		    IMSG_OCSP_FD, -1, -1, iov, iovcnt);
244 		if (fd >= 0)
245 			close(fd);
246 	}
247 	if (oc) {
248 		free(oc->oc_url);
249 		free(oc->oc_path);
250 		free(oc);
251 	}
252 	return (ret);
253 }
254 
255 
256 /* unpriv */
257 
258 /* validate the certifcate stored in 'data' by querying the ocsp-responder */
259 int
260 ocsp_validate_cert(struct iked *env, void *data, size_t len,
261     struct iked_sahdr sh, u_int8_t type, X509 *issuer)
262 {
263 	struct iovec		 iov[2];
264 	STACK_OF(OPENSSL_STRING) *aia; /* Authority Information Access */
265 	struct iked_ocsp_entry	*ioe;
266 	struct iked_ocsp	*ocsp;
267 	OCSP_CERTID		*id = NULL;
268 	char			*url;
269 	BIO			*rawcert = NULL;
270 	X509			*cert = NULL;
271 	int			 ret, iovcnt = 0;
272 
273 	if (issuer == NULL)
274 		return (-1);
275 	if ((ioe = calloc(1, sizeof(*ioe))) == NULL)
276 		return (-1);
277 	if ((ocsp = calloc(1, sizeof(*ocsp))) == NULL) {
278 		free(ioe);
279 		return (-1);
280 	}
281 
282 	ocsp->ocsp_env = env;
283 	ocsp->ocsp_sh = sh;
284 	ocsp->ocsp_type = type;
285 
286 	if ((rawcert = BIO_new_mem_buf(data, len)) == NULL ||
287 	    (cert = d2i_X509_bio(rawcert, NULL)) == NULL ||
288 	    (ocsp->ocsp_cbio = BIO_new(BIO_s_socket())) == NULL ||
289 	    (ocsp->ocsp_req = OCSP_REQUEST_new()) == NULL ||
290 	    (id = OCSP_cert_to_id(NULL, cert, issuer)) == NULL ||
291 	    !OCSP_request_add0_id(ocsp->ocsp_req, id))
292 		goto err;
293 
294 	/* id is owned by and freed together with ocsp_req */
295 	ocsp->ocsp_id = id;
296 
297 	BIO_free(rawcert);
298 	X509_free(cert);
299 
300 	ioe->ioe_ocsp = ocsp;
301 	TAILQ_INSERT_TAIL(&env->sc_ocsp, ioe, ioe_entry);
302 
303 	/* pass SA header */
304 	iov[iovcnt].iov_base = &ocsp->ocsp_sh;
305 	iov[iovcnt].iov_len = sizeof(ocsp->ocsp_sh);
306 	iovcnt++;
307 
308 	/* pass optional ocsp-url from issuer */
309 	if ((aia = X509_get1_ocsp(issuer)) != NULL) {
310 		url = sk_OPENSSL_STRING_value(aia, 0);
311 		log_debug("%s: aia %s", __func__, url);
312 		iov[iovcnt].iov_base = url;
313 		iov[iovcnt].iov_len = strlen(url);
314 		iovcnt++;
315 	}
316 	/* request connection to ocsp-responder */
317 	ret = proc_composev(&env->sc_ps, PROC_PARENT, IMSG_OCSP_FD,
318 	    iov, iovcnt);
319 
320 	if (aia)
321 		X509_email_free(aia);	/* free stack of openssl strings */
322 
323 	return (ret);
324 
325  err:
326 	ca_sslerror(__func__);
327 	free(ioe);
328 	if (rawcert != NULL)
329 		BIO_free(rawcert);
330 	if (cert != NULL)
331 		X509_free(cert);
332 	if (id != NULL)
333 		OCSP_CERTID_free(id);
334 	ocsp_validate_finish(ocsp, 0);	/* failed */
335 	return (-1);
336 }
337 
338 /* free ocsp query context */
339 void
340 ocsp_free(struct iked_ocsp *ocsp)
341 {
342 	if (ocsp != NULL) {
343 		if (ocsp->ocsp_sock != NULL) {
344 			close(ocsp->ocsp_sock->sock_fd);
345 			free(ocsp->ocsp_sock);
346 		}
347 		if (ocsp->ocsp_cbio != NULL)
348 			BIO_free_all(ocsp->ocsp_cbio);
349 
350 		if (ocsp->ocsp_req_ctx != NULL)
351 			OCSP_REQ_CTX_free(ocsp->ocsp_req_ctx);
352 
353 		if (ocsp->ocsp_req != NULL)
354 			OCSP_REQUEST_free(ocsp->ocsp_req);
355 
356 		free(ocsp);
357 	}
358 }
359 
360 /* we got a connection to the ocsp responder */
361 int
362 ocsp_receive_fd(struct iked *env, struct imsg *imsg)
363 {
364 	struct iked_ocsp_entry	*ioe = NULL;
365 	struct iked_ocsp	*ocsp = NULL, *ocsp_tmp;
366 	struct iked_socket	*sock;
367 	struct iked_sahdr	 sh;
368 	struct timeval		 tv;
369 	uint8_t			*ptr;
370 	char			*path = NULL;
371 	size_t			 len;
372 	int			 ret = -1;
373 
374 	log_debug("%s: received socket fd %d", __func__, imsg->fd);
375 
376 	IMSG_SIZE_CHECK(imsg, &sh);
377 
378 	ptr = (uint8_t *)imsg->data;
379 	len = IMSG_DATA_SIZE(imsg);
380 
381 	memcpy(&sh, ptr, sizeof(sh));
382 
383 	ptr += sizeof(sh);
384 	len -= sizeof(sh);
385 
386 	TAILQ_FOREACH(ioe, &env->sc_ocsp, ioe_entry) {
387 		ocsp_tmp = ioe->ioe_ocsp;
388 		if (memcmp(&ocsp_tmp->ocsp_sh, &sh, sizeof(sh)) == 0)
389 			break;
390 	}
391 	if (ioe == NULL) {
392 		log_debug("%s: no pending request found", __func__);
393 		if (imsg->fd != -1)
394 			close(imsg->fd);
395 		return (-1);
396 	}
397 	TAILQ_REMOVE(&env->sc_ocsp, ioe, ioe_entry);
398 	ocsp = ioe->ioe_ocsp;
399 	free(ioe);
400 
401 	if (imsg->fd == -1)
402 		goto done;
403 
404 	if ((sock = calloc(1, sizeof(*sock))) == NULL)
405 		fatal("ocsp_receive_fd: calloc sock");
406 
407 	/* note that sock_addr is not set */
408 	sock->sock_fd = imsg->fd;
409 	sock->sock_env = env;
410 	ocsp->ocsp_sock = sock;
411 
412 	/* fetch 'path' and 'fd' from imsg */
413 	if ((path = get_string(ptr, len)) == NULL)
414 		goto done;
415 
416 	BIO_set_fd(ocsp->ocsp_cbio, imsg->fd, BIO_NOCLOSE);
417 
418 	if ((ocsp->ocsp_req_ctx = OCSP_sendreq_new(ocsp->ocsp_cbio,
419 	    path, NULL, -1)) == NULL)
420 		goto done;
421 	if (!OCSP_REQ_CTX_set1_req(ocsp->ocsp_req_ctx, ocsp->ocsp_req))
422 		goto done;
423 
424 	tv.tv_sec = OCSP_TIMEOUT;
425 	tv.tv_usec = 0;
426 	event_set(&sock->sock_ev, sock->sock_fd, EV_WRITE, ocsp_callback, ocsp);
427 	event_add(&sock->sock_ev, &tv);
428 	ret = 0;
429  done:
430 	if (ret == -1)
431 		ocsp_validate_finish(ocsp, 0);	/* failed */
432 	free(path);
433 	return (ret);
434 }
435 
436 /* load a stack of x509 certificates */
437 STACK_OF(X509)*
438 ocsp_load_certs(const char *file)
439 {
440 	BIO			*bio = NULL;
441 	STACK_OF(X509)		*certs = NULL;
442 	STACK_OF(X509_INFO)	*xis = NULL;
443 	X509_INFO		*xi;
444 	int			 i;
445 
446 	if ((bio = BIO_new_file(file, "r")) == NULL) {
447 		log_warn("%s: BIO_new_file failed for %s",
448 		    __func__, file);
449 		return (NULL);
450 	}
451 	if ((xis = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL)) == NULL) {
452 		ca_sslerror(__func__);
453 		goto done;
454 	}
455 	if ((certs = sk_X509_new_null()) == NULL) {
456 		log_debug("%s: sk_X509_new_null failed for %s", __func__, file);
457 		goto done;
458 	}
459 	for (i = 0; i < sk_X509_INFO_num(xis); i++) {
460 		xi = sk_X509_INFO_value(xis, i);
461 		if (xi->x509) {
462 			if (!sk_X509_push(certs, xi->x509))
463 				goto done;
464 			xi->x509 = NULL;
465 		}
466 	}
467 
468  done:
469 	if (bio)
470 		BIO_free(bio);
471 	if (xis)
472 		sk_X509_INFO_pop_free(xis, X509_INFO_free);
473 	if (certs && sk_X509_num(certs) <= 0) {
474 		sk_X509_pop_free(certs, X509_free);
475 		certs = NULL;
476 	}
477 	return (certs);
478 }
479 
480 /* read/write callback that sends the requests and reads the ocsp response */
481 void
482 ocsp_callback(int fd, short event, void *arg)
483 {
484 	struct iked_ocsp	*ocsp = arg;
485 	struct iked_socket	*sock = ocsp->ocsp_sock;
486 	struct timeval		 tv;
487 	OCSP_RESPONSE		*resp = NULL;
488 
489 	if (event == EV_TIMEOUT) {
490 		log_info("%s: timeout, giving up",
491 		    SPI_SH(&ocsp->ocsp_sh, __func__));
492 		ocsp_validate_finish(ocsp, 0);
493 		return;
494 	}
495 	/*
496 	 * Only call OCSP_sendreq_nbio() if should_read/write is
497 	 * either not requested or read/write can be called.
498 	 */
499 	if ((!BIO_should_read(ocsp->ocsp_cbio) || (event & EV_READ)) &&
500 	    (!BIO_should_write(ocsp->ocsp_cbio) || (event & EV_WRITE)) &&
501 	    OCSP_sendreq_nbio(&resp, ocsp->ocsp_req_ctx) != -1 ) {
502 		ocsp_parse_response(ocsp, resp);
503 		return;
504 	}
505 	if (BIO_should_read(ocsp->ocsp_cbio))
506 		event_set(&sock->sock_ev, sock->sock_fd, EV_READ,
507 		    ocsp_callback, ocsp);
508 	else if (BIO_should_write(ocsp->ocsp_cbio))
509 		event_set(&sock->sock_ev, sock->sock_fd, EV_WRITE,
510 		    ocsp_callback, ocsp);
511 	tv.tv_sec = OCSP_TIMEOUT;
512 	tv.tv_usec = 0;
513 	event_add(&sock->sock_ev, &tv);
514 }
515 
516 /* parse the actual OCSP response */
517 void
518 ocsp_parse_response(struct iked_ocsp *ocsp, OCSP_RESPONSE *resp)
519 {
520 	struct iked		*env = ocsp->ocsp_env;
521 	X509_STORE		*store = NULL;
522 	STACK_OF(X509)		*verify_other = NULL;
523 	OCSP_BASICRESP		*bs = NULL;
524 	ASN1_GENERALIZEDTIME	*rev, *thisupd, *nextupd;
525 	const char		*errstr;
526 	int			 reason = 0, valid = 0, verify_flags = 0;
527 	int			 status;
528 
529 	if (!resp) {
530 		errstr = "error querying OCSP responder";
531 		goto done;
532 	}
533 
534 	status = OCSP_response_status(resp);
535 	if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
536 		errstr = OCSP_response_status_str(status);
537 		goto done;
538 	}
539 
540 	verify_other = ocsp_load_certs(IKED_OCSP_RESPCERT);
541 	verify_flags |= OCSP_TRUSTOTHER;
542 	if (!verify_other) {
543 		errstr = "no verify_other";
544 		goto done;
545 	}
546 
547 	bs = OCSP_response_get1_basic(resp);
548 	if (!bs) {
549 		errstr = "error parsing response";
550 		goto done;
551 	}
552 
553 	status = OCSP_check_nonce(ocsp->ocsp_req, bs);
554 	if (status <= 0) {
555 		if (status == -1)
556 			log_warnx("%s: no nonce in response",
557 			    SPI_SH(&ocsp->ocsp_sh, __func__));
558 		else {
559 			errstr = "nonce verify error";
560 			goto done;
561 		}
562 	}
563 
564 	store = X509_STORE_new();
565 	status = OCSP_basic_verify(bs, verify_other, store, verify_flags);
566 	if (status < 0)
567 		status = OCSP_basic_verify(bs, NULL, store, 0);
568 	if (status <= 0) {
569 		ca_sslerror(__func__);
570 		errstr = "response verify failure";
571 		goto done;
572 	}
573 	log_debug("%s: response verify ok", SPI_SH(&ocsp->ocsp_sh, __func__));
574 
575 	if (!OCSP_resp_find_status(bs, ocsp->ocsp_id, &status, &reason,
576 	    &rev, &thisupd, &nextupd)) {
577 		errstr = "no status found";
578 		goto done;
579 	}
580 	if (env->sc_ocsp_tolerate &&
581 	    !OCSP_check_validity(thisupd, nextupd, env->sc_ocsp_tolerate,
582 	    env->sc_ocsp_maxage)) {
583 		ca_sslerror(SPI_SH(&ocsp->ocsp_sh, __func__));
584 		errstr = "status times invalid";
585 		goto done;
586 	}
587 	errstr = OCSP_cert_status_str(status);
588 	if (status == V_OCSP_CERTSTATUS_GOOD) {
589 		log_debug("%s: status: %s", SPI_SH(&ocsp->ocsp_sh, __func__),
590 		    errstr);
591 		valid = 1;
592 	}
593  done:
594 	if (!valid) {
595 		log_debug("%s: status: %s", __func__, errstr);
596 	}
597 	if (store)
598 		X509_STORE_free(store);
599 	if (verify_other)
600 		sk_X509_pop_free(verify_other, X509_free);
601 	if (resp)
602 		OCSP_RESPONSE_free(resp);
603 	if (bs)
604 		OCSP_BASICRESP_free(bs);
605 
606 	ocsp_validate_finish(ocsp, valid);
607 }
608 
609 /*
610  * finish the ocsp_validate_cert() RPC by sending the appropriate
611  * message back to the IKEv2 process
612  */
613 int
614 ocsp_validate_finish(struct iked_ocsp *ocsp, int valid)
615 {
616 	struct iked		*env = ocsp->ocsp_env;
617 	struct iovec		 iov[2];
618 	int			 iovcnt = 2, ret, cmd;
619 
620 	iov[0].iov_base = &ocsp->ocsp_sh;
621 	iov[0].iov_len = sizeof(ocsp->ocsp_sh);
622 	iov[1].iov_base = &ocsp->ocsp_type;
623 	iov[1].iov_len = sizeof(ocsp->ocsp_type);
624 
625 	cmd = valid ? IMSG_CERTVALID : IMSG_CERTINVALID;
626 	ret = proc_composev(&env->sc_ps, PROC_IKEV2, cmd, iov, iovcnt);
627 
628 	ocsp_free(ocsp);
629 	return (ret);
630 }
631