620 lines
15 KiB
C
620 lines
15 KiB
C
/* $OpenBSD: ocsp.c,v 1.25 2024/01/17 08:25:02 claudio Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 2014 Markus Friedl
|
|
* Copyright (c) 2005 Marco Pfatschbacher
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include <sys/queue.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/uio.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <netdb.h>
|
|
|
|
#include <openssl/pem.h>
|
|
#include <openssl/ocsp.h>
|
|
#include <openssl/err.h>
|
|
#include <openssl/ssl.h>
|
|
|
|
#include <event.h>
|
|
|
|
#include "iked.h"
|
|
|
|
struct iked_ocsp {
|
|
struct iked *ocsp_env; /* back pointer to env */
|
|
struct iked_sahdr ocsp_sh; /* ike sa */
|
|
uint8_t ocsp_type; /* auth type */
|
|
struct iked_socket *ocsp_sock; /* socket to ocsp responder */
|
|
BIO *ocsp_cbio; /* matching OpenSSL obj */
|
|
OCSP_CERTID *ocsp_id; /* ocsp-id for cert */
|
|
OCSP_REQUEST *ocsp_req; /* ocsp-request */
|
|
OCSP_REQ_CTX *ocsp_req_ctx; /* async ocsp-request */
|
|
};
|
|
|
|
struct ocsp_connect {
|
|
struct iked_sahdr oc_sh;
|
|
struct iked_socket oc_sock;
|
|
char *oc_path;
|
|
char *oc_url;
|
|
};
|
|
|
|
#define OCSP_TIMEOUT 30
|
|
|
|
/* priv */
|
|
void ocsp_connect_cb(int, short, void *);
|
|
int ocsp_connect_finish(struct iked *, int, struct ocsp_connect *);
|
|
|
|
/* unpriv */
|
|
void ocsp_free(struct iked_ocsp *);
|
|
void ocsp_callback(int, short, void *);
|
|
void ocsp_parse_response(struct iked_ocsp *, OCSP_RESPONSE *);
|
|
STACK_OF(X509) *ocsp_load_certs(const char *);
|
|
int ocsp_validate_finish(struct iked_ocsp *, int);
|
|
|
|
|
|
/* priv */
|
|
|
|
/* async connect to configure ocsp-responder */
|
|
int
|
|
ocsp_connect(struct iked *env, struct imsg *imsg)
|
|
{
|
|
struct ocsp_connect *oc = NULL;
|
|
struct iked_sahdr sh;
|
|
struct addrinfo hints, *res0 = NULL, *res;
|
|
struct timeval tv;
|
|
uint8_t *ptr;
|
|
size_t len;
|
|
char *host = NULL, *port = NULL, *path = NULL;
|
|
char *url, *freeme = NULL;
|
|
int use_ssl, fd = -1, ret = -1, error;
|
|
|
|
IMSG_SIZE_CHECK(imsg, &sh);
|
|
|
|
ptr = (uint8_t *)imsg->data;
|
|
len = IMSG_DATA_SIZE(imsg);
|
|
|
|
memcpy(&sh, ptr, sizeof(sh));
|
|
|
|
ptr += sizeof(sh);
|
|
len -= sizeof(sh);
|
|
|
|
if (len > 0)
|
|
url = freeme = get_string(ptr, len);
|
|
else if (env->sc_ocsp_url)
|
|
url = env->sc_ocsp_url;
|
|
else {
|
|
log_warnx("%s: no ocsp url", SPI_SH(&sh, __func__));
|
|
goto done;
|
|
}
|
|
if (!OCSP_parse_url(url, &host, &port, &path, &use_ssl)) {
|
|
log_warnx("%s: error parsing OCSP-request-URL: %s",
|
|
SPI_SH(&sh, __func__), url);
|
|
goto done;
|
|
}
|
|
if (use_ssl) {
|
|
log_warnx("%s: OCSP over SSL not supported: %s",
|
|
SPI_SH(&sh, __func__), url);
|
|
goto done;
|
|
}
|
|
|
|
if ((fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1) {
|
|
log_debug("%s: socket failed", SPI_SH(&sh, __func__));
|
|
goto done;
|
|
}
|
|
if ((oc = calloc(1, sizeof(*oc))) == NULL) {
|
|
log_debug("%s: calloc failed", __func__);
|
|
goto done;
|
|
}
|
|
|
|
bzero(&hints, sizeof(struct addrinfo));
|
|
hints.ai_family = PF_UNSPEC;
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
error = getaddrinfo(host, port, &hints, &res0);
|
|
if (error) {
|
|
log_warn("%s: getaddrinfo(%s, %s) failed",
|
|
SPI_SH(&sh, __func__), host, port);
|
|
goto done;
|
|
}
|
|
/* XXX just pick the first answer. we could loop instead */
|
|
for (res = res0; res; res = res->ai_next)
|
|
if (res->ai_family == AF_INET)
|
|
break;
|
|
if (res == NULL) {
|
|
log_debug("%s: no addr to connect to for %s:%s",
|
|
SPI_SH(&sh, __func__), host, port);
|
|
goto done;
|
|
}
|
|
|
|
oc->oc_sock.sock_fd = fd;
|
|
oc->oc_sock.sock_env = env;
|
|
oc->oc_sh = sh;
|
|
oc->oc_path = path;
|
|
oc->oc_url = strdup(url);
|
|
if (oc->oc_url == NULL) {
|
|
log_warn("%s: strdup failed", SPI_SH(&sh, __func__));
|
|
goto done;
|
|
}
|
|
path = NULL;
|
|
|
|
log_debug("%s: connect(%s, %s)", __func__, host, port);
|
|
if (connect(fd, res->ai_addr, res->ai_addrlen) == -1) {
|
|
/* register callback for ansync connect */
|
|
if (errno == EINPROGRESS) {
|
|
tv.tv_sec = OCSP_TIMEOUT;
|
|
tv.tv_usec = 0;
|
|
event_set(&oc->oc_sock.sock_ev, fd, EV_WRITE,
|
|
ocsp_connect_cb, oc);
|
|
event_add(&oc->oc_sock.sock_ev, &tv);
|
|
ret = 0;
|
|
} else
|
|
log_warn("%s: connect(%s, %s)",
|
|
SPI_SH(&oc->oc_sh, __func__), host, port);
|
|
} else {
|
|
ocsp_connect_finish(env, fd, oc);
|
|
ret = 0;
|
|
}
|
|
done:
|
|
if (res0)
|
|
freeaddrinfo(res0);
|
|
free(freeme);
|
|
free(host);
|
|
free(port);
|
|
free(path);
|
|
if (ret == -1) {
|
|
ocsp_connect_finish(env, -1, oc);
|
|
if (fd >= 0)
|
|
close(fd);
|
|
}
|
|
return (ret);
|
|
}
|
|
|
|
/* callback triggered if connection to ocsp-responder completes/fails */
|
|
void
|
|
ocsp_connect_cb(int fd, short event, void *arg)
|
|
{
|
|
struct ocsp_connect *oc = arg;
|
|
int error, send_fd = -1;
|
|
socklen_t len;
|
|
|
|
if (event == EV_TIMEOUT) {
|
|
log_info("%s: timeout, giving up",
|
|
SPI_SH(&oc->oc_sh, __func__));
|
|
goto done;
|
|
}
|
|
|
|
len = sizeof(error);
|
|
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) == -1) {
|
|
log_warn("%s: getsockopt SOL_SOCKET SO_ERROR",
|
|
SPI_SH(&oc->oc_sh, __func__));
|
|
} else if (error) {
|
|
log_warnx("%s: error while connecting: %s",
|
|
SPI_SH(&oc->oc_sh, __func__), strerror(error));
|
|
} else {
|
|
send_fd = fd;
|
|
}
|
|
done:
|
|
ocsp_connect_finish(oc->oc_sock.sock_env, send_fd, oc);
|
|
|
|
/* if we did not send the fd, we need to close it ourself */
|
|
if (send_fd == -1)
|
|
close(fd);
|
|
}
|
|
|
|
/* send FD+path or error back to CA process */
|
|
int
|
|
ocsp_connect_finish(struct iked *env, int fd, struct ocsp_connect *oc)
|
|
{
|
|
struct iovec iov[2];
|
|
int iovcnt = 0, ret;
|
|
|
|
iov[iovcnt].iov_base = &oc->oc_sh;
|
|
iov[iovcnt].iov_len = sizeof(oc->oc_sh);
|
|
iovcnt++;
|
|
|
|
if (oc && fd >= 0) {
|
|
/* the imsg framework will close the FD after send */
|
|
iov[iovcnt].iov_base = oc->oc_path;
|
|
iov[iovcnt].iov_len = strlen(oc->oc_path);
|
|
iovcnt++;
|
|
ret = proc_composev_imsg(&env->sc_ps, PROC_CERT, -1,
|
|
IMSG_OCSP_FD, -1, fd, iov, iovcnt);
|
|
} else {
|
|
if (oc)
|
|
log_info("%s: connect failed for %s",
|
|
SPI_SH(&oc->oc_sh, __func__),
|
|
oc->oc_url ? oc->oc_url : "unknown");
|
|
else
|
|
log_info("%s: connect failed", __func__);
|
|
ret = proc_composev_imsg(&env->sc_ps, PROC_CERT, -1,
|
|
IMSG_OCSP_FD, -1, -1, iov, iovcnt);
|
|
if (fd >= 0)
|
|
close(fd);
|
|
}
|
|
if (oc) {
|
|
free(oc->oc_url);
|
|
free(oc->oc_path);
|
|
free(oc);
|
|
}
|
|
return (ret);
|
|
}
|
|
|
|
|
|
/* unpriv */
|
|
|
|
/* validate the certifcate stored in 'data' by querying the ocsp-responder */
|
|
int
|
|
ocsp_validate_cert(struct iked *env, void *data, size_t len,
|
|
struct iked_sahdr sh, uint8_t type, X509 *issuer)
|
|
{
|
|
struct iovec iov[2];
|
|
STACK_OF(OPENSSL_STRING) *aia; /* Authority Information Access */
|
|
struct iked_ocsp_entry *ioe;
|
|
struct iked_ocsp *ocsp;
|
|
OCSP_CERTID *id = NULL;
|
|
char *url;
|
|
BIO *rawcert = NULL;
|
|
X509 *cert = NULL;
|
|
int ret, iovcnt = 0;
|
|
|
|
if (issuer == NULL)
|
|
return (-1);
|
|
if ((ioe = calloc(1, sizeof(*ioe))) == NULL)
|
|
return (-1);
|
|
if ((ocsp = calloc(1, sizeof(*ocsp))) == NULL) {
|
|
free(ioe);
|
|
return (-1);
|
|
}
|
|
|
|
ocsp->ocsp_env = env;
|
|
ocsp->ocsp_sh = sh;
|
|
ocsp->ocsp_type = type;
|
|
|
|
if ((rawcert = BIO_new_mem_buf(data, len)) == NULL ||
|
|
(cert = d2i_X509_bio(rawcert, NULL)) == NULL ||
|
|
(ocsp->ocsp_cbio = BIO_new(BIO_s_socket())) == NULL ||
|
|
(ocsp->ocsp_req = OCSP_REQUEST_new()) == NULL ||
|
|
(id = OCSP_cert_to_id(NULL, cert, issuer)) == NULL ||
|
|
!OCSP_request_add0_id(ocsp->ocsp_req, id))
|
|
goto err;
|
|
|
|
/* id is owned by and freed together with ocsp_req */
|
|
ocsp->ocsp_id = id;
|
|
|
|
BIO_free(rawcert);
|
|
X509_free(cert);
|
|
|
|
ioe->ioe_ocsp = ocsp;
|
|
TAILQ_INSERT_TAIL(&env->sc_ocsp, ioe, ioe_entry);
|
|
|
|
/* pass SA header */
|
|
iov[iovcnt].iov_base = &ocsp->ocsp_sh;
|
|
iov[iovcnt].iov_len = sizeof(ocsp->ocsp_sh);
|
|
iovcnt++;
|
|
|
|
/* pass optional ocsp-url from issuer */
|
|
if ((aia = X509_get1_ocsp(issuer)) != NULL) {
|
|
url = sk_OPENSSL_STRING_value(aia, 0);
|
|
log_debug("%s: aia %s", __func__, url);
|
|
iov[iovcnt].iov_base = url;
|
|
iov[iovcnt].iov_len = strlen(url);
|
|
iovcnt++;
|
|
}
|
|
/* request connection to ocsp-responder */
|
|
ret = proc_composev(&env->sc_ps, PROC_PARENT, IMSG_OCSP_FD,
|
|
iov, iovcnt);
|
|
|
|
X509_email_free(aia); /* free stack of openssl strings */
|
|
|
|
return (ret);
|
|
|
|
err:
|
|
ca_sslerror(__func__);
|
|
free(ioe);
|
|
BIO_free(rawcert);
|
|
X509_free(cert);
|
|
OCSP_CERTID_free(id);
|
|
ocsp_validate_finish(ocsp, 0); /* failed */
|
|
return (-1);
|
|
}
|
|
|
|
/* free ocsp query context */
|
|
void
|
|
ocsp_free(struct iked_ocsp *ocsp)
|
|
{
|
|
if (ocsp != NULL) {
|
|
if (ocsp->ocsp_sock != NULL) {
|
|
close(ocsp->ocsp_sock->sock_fd);
|
|
free(ocsp->ocsp_sock);
|
|
}
|
|
BIO_free_all(ocsp->ocsp_cbio);
|
|
OCSP_REQ_CTX_free(ocsp->ocsp_req_ctx);
|
|
OCSP_REQUEST_free(ocsp->ocsp_req);
|
|
free(ocsp);
|
|
}
|
|
}
|
|
|
|
/* we got a connection to the ocsp responder */
|
|
int
|
|
ocsp_receive_fd(struct iked *env, struct imsg *imsg)
|
|
{
|
|
struct iked_ocsp_entry *ioe = NULL;
|
|
struct iked_ocsp *ocsp = NULL, *ocsp_tmp;
|
|
struct iked_socket *sock;
|
|
struct iked_sahdr sh;
|
|
struct timeval tv;
|
|
uint8_t *ptr;
|
|
char *path = NULL;
|
|
size_t len;
|
|
int fd, ret = -1;
|
|
|
|
IMSG_SIZE_CHECK(imsg, &sh);
|
|
|
|
ptr = (uint8_t *)imsg->data;
|
|
len = IMSG_DATA_SIZE(imsg);
|
|
|
|
memcpy(&sh, ptr, sizeof(sh));
|
|
|
|
ptr += sizeof(sh);
|
|
len -= sizeof(sh);
|
|
|
|
TAILQ_FOREACH(ioe, &env->sc_ocsp, ioe_entry) {
|
|
ocsp_tmp = ioe->ioe_ocsp;
|
|
if (memcmp(&ocsp_tmp->ocsp_sh, &sh, sizeof(sh)) == 0)
|
|
break;
|
|
}
|
|
if (ioe == NULL) {
|
|
log_debug("%s: no pending request found", __func__);
|
|
if ((fd = imsg_get_fd(imsg)) != -1) /* XXX */
|
|
close(fd);
|
|
return (-1);
|
|
}
|
|
TAILQ_REMOVE(&env->sc_ocsp, ioe, ioe_entry);
|
|
ocsp = ioe->ioe_ocsp;
|
|
free(ioe);
|
|
|
|
if ((fd = imsg_get_fd(imsg)) == -1)
|
|
goto done;
|
|
|
|
if ((sock = calloc(1, sizeof(*sock))) == NULL)
|
|
fatal("ocsp_receive_fd: calloc sock");
|
|
|
|
/* note that sock_addr is not set */
|
|
sock->sock_fd = fd;
|
|
sock->sock_env = env;
|
|
ocsp->ocsp_sock = sock;
|
|
|
|
log_debug("%s: received socket fd %d", __func__, sock->sock_fd);
|
|
|
|
/* fetch 'path' and 'fd' from imsg */
|
|
if ((path = get_string(ptr, len)) == NULL)
|
|
goto done;
|
|
|
|
BIO_set_fd(ocsp->ocsp_cbio, sock->sock_fd, BIO_NOCLOSE);
|
|
|
|
if ((ocsp->ocsp_req_ctx = OCSP_sendreq_new(ocsp->ocsp_cbio,
|
|
path, NULL, -1)) == NULL)
|
|
goto done;
|
|
if (!OCSP_REQ_CTX_set1_req(ocsp->ocsp_req_ctx, ocsp->ocsp_req))
|
|
goto done;
|
|
|
|
tv.tv_sec = OCSP_TIMEOUT;
|
|
tv.tv_usec = 0;
|
|
event_set(&sock->sock_ev, sock->sock_fd, EV_WRITE, ocsp_callback, ocsp);
|
|
event_add(&sock->sock_ev, &tv);
|
|
ret = 0;
|
|
done:
|
|
if (ret == -1)
|
|
ocsp_validate_finish(ocsp, 0); /* failed */
|
|
free(path);
|
|
return (ret);
|
|
}
|
|
|
|
/* load a stack of x509 certificates */
|
|
STACK_OF(X509)*
|
|
ocsp_load_certs(const char *file)
|
|
{
|
|
BIO *bio = NULL;
|
|
STACK_OF(X509) *certs = NULL;
|
|
STACK_OF(X509_INFO) *xis = NULL;
|
|
X509_INFO *xi;
|
|
int i;
|
|
|
|
if ((bio = BIO_new_file(file, "r")) == NULL) {
|
|
log_warn("%s: BIO_new_file failed for %s",
|
|
__func__, file);
|
|
return (NULL);
|
|
}
|
|
if ((xis = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL)) == NULL) {
|
|
ca_sslerror(__func__);
|
|
goto done;
|
|
}
|
|
if ((certs = sk_X509_new_null()) == NULL) {
|
|
log_debug("%s: sk_X509_new_null failed for %s", __func__, file);
|
|
goto done;
|
|
}
|
|
for (i = 0; i < sk_X509_INFO_num(xis); i++) {
|
|
xi = sk_X509_INFO_value(xis, i);
|
|
if (xi->x509) {
|
|
if (!sk_X509_push(certs, xi->x509))
|
|
goto done;
|
|
xi->x509 = NULL;
|
|
}
|
|
}
|
|
|
|
done:
|
|
BIO_free(bio);
|
|
sk_X509_INFO_pop_free(xis, X509_INFO_free);
|
|
if (sk_X509_num(certs) <= 0) {
|
|
sk_X509_free(certs);
|
|
certs = NULL;
|
|
}
|
|
return (certs);
|
|
}
|
|
|
|
/* read/write callback that sends the requests and reads the ocsp response */
|
|
void
|
|
ocsp_callback(int fd, short event, void *arg)
|
|
{
|
|
struct iked_ocsp *ocsp = arg;
|
|
struct iked_socket *sock = ocsp->ocsp_sock;
|
|
struct timeval tv;
|
|
OCSP_RESPONSE *resp = NULL;
|
|
|
|
if (event == EV_TIMEOUT) {
|
|
log_info("%s: timeout, giving up",
|
|
SPI_SH(&ocsp->ocsp_sh, __func__));
|
|
ocsp_validate_finish(ocsp, 0);
|
|
return;
|
|
}
|
|
/*
|
|
* Only call OCSP_sendreq_nbio() if should_read/write is
|
|
* either not requested or read/write can be called.
|
|
*/
|
|
if ((!BIO_should_read(ocsp->ocsp_cbio) || (event & EV_READ)) &&
|
|
(!BIO_should_write(ocsp->ocsp_cbio) || (event & EV_WRITE)) &&
|
|
OCSP_sendreq_nbio(&resp, ocsp->ocsp_req_ctx) != -1 ) {
|
|
ocsp_parse_response(ocsp, resp);
|
|
return;
|
|
}
|
|
if (BIO_should_read(ocsp->ocsp_cbio))
|
|
event_set(&sock->sock_ev, sock->sock_fd, EV_READ,
|
|
ocsp_callback, ocsp);
|
|
else if (BIO_should_write(ocsp->ocsp_cbio))
|
|
event_set(&sock->sock_ev, sock->sock_fd, EV_WRITE,
|
|
ocsp_callback, ocsp);
|
|
tv.tv_sec = OCSP_TIMEOUT;
|
|
tv.tv_usec = 0;
|
|
event_add(&sock->sock_ev, &tv);
|
|
}
|
|
|
|
/* parse the actual OCSP response */
|
|
void
|
|
ocsp_parse_response(struct iked_ocsp *ocsp, OCSP_RESPONSE *resp)
|
|
{
|
|
struct iked *env = ocsp->ocsp_env;
|
|
X509_STORE *store = NULL;
|
|
STACK_OF(X509) *verify_other = NULL;
|
|
OCSP_BASICRESP *bs = NULL;
|
|
ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
|
|
const char *errstr;
|
|
int reason = 0, valid = 0, verify_flags = 0;
|
|
int status;
|
|
|
|
if (!resp) {
|
|
errstr = "error querying OCSP responder";
|
|
goto done;
|
|
}
|
|
|
|
status = OCSP_response_status(resp);
|
|
if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
|
|
errstr = OCSP_response_status_str(status);
|
|
goto done;
|
|
}
|
|
|
|
verify_other = ocsp_load_certs(IKED_OCSP_RESPCERT);
|
|
verify_flags |= OCSP_TRUSTOTHER;
|
|
if (!verify_other) {
|
|
errstr = "no verify_other";
|
|
goto done;
|
|
}
|
|
|
|
bs = OCSP_response_get1_basic(resp);
|
|
if (!bs) {
|
|
errstr = "error parsing response";
|
|
goto done;
|
|
}
|
|
|
|
status = OCSP_check_nonce(ocsp->ocsp_req, bs);
|
|
if (status <= 0) {
|
|
if (status == -1)
|
|
log_warnx("%s: no nonce in response",
|
|
SPI_SH(&ocsp->ocsp_sh, __func__));
|
|
else {
|
|
errstr = "nonce verify error";
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
store = X509_STORE_new();
|
|
status = OCSP_basic_verify(bs, verify_other, store, verify_flags);
|
|
if (status < 0)
|
|
status = OCSP_basic_verify(bs, NULL, store, 0);
|
|
if (status <= 0) {
|
|
ca_sslerror(__func__);
|
|
errstr = "response verify failure";
|
|
goto done;
|
|
}
|
|
log_debug("%s: response verify ok", SPI_SH(&ocsp->ocsp_sh, __func__));
|
|
|
|
if (!OCSP_resp_find_status(bs, ocsp->ocsp_id, &status, &reason,
|
|
&rev, &thisupd, &nextupd)) {
|
|
errstr = "no status found";
|
|
goto done;
|
|
}
|
|
if (env->sc_ocsp_tolerate &&
|
|
!OCSP_check_validity(thisupd, nextupd, env->sc_ocsp_tolerate,
|
|
env->sc_ocsp_maxage)) {
|
|
ca_sslerror(SPI_SH(&ocsp->ocsp_sh, __func__));
|
|
errstr = "status times invalid";
|
|
goto done;
|
|
}
|
|
errstr = OCSP_cert_status_str(status);
|
|
if (status == V_OCSP_CERTSTATUS_GOOD) {
|
|
log_debug("%s: status: %s", SPI_SH(&ocsp->ocsp_sh, __func__),
|
|
errstr);
|
|
valid = 1;
|
|
}
|
|
done:
|
|
if (!valid) {
|
|
log_debug("%s: status: %s", __func__, errstr);
|
|
}
|
|
X509_STORE_free(store);
|
|
sk_X509_pop_free(verify_other, X509_free);
|
|
OCSP_RESPONSE_free(resp);
|
|
OCSP_BASICRESP_free(bs);
|
|
|
|
ocsp_validate_finish(ocsp, valid);
|
|
}
|
|
|
|
/*
|
|
* finish the ocsp_validate_cert() RPC by sending the appropriate
|
|
* message back to the IKEv2 process
|
|
*/
|
|
int
|
|
ocsp_validate_finish(struct iked_ocsp *ocsp, int valid)
|
|
{
|
|
struct iked *env = ocsp->ocsp_env;
|
|
struct iovec iov[2];
|
|
int iovcnt = 2, ret, cmd;
|
|
|
|
iov[0].iov_base = &ocsp->ocsp_sh;
|
|
iov[0].iov_len = sizeof(ocsp->ocsp_sh);
|
|
iov[1].iov_base = &ocsp->ocsp_type;
|
|
iov[1].iov_len = sizeof(ocsp->ocsp_type);
|
|
|
|
cmd = valid ? IMSG_CERTVALID : IMSG_CERTINVALID;
|
|
ret = proc_composev(&env->sc_ps, PROC_IKEV2, cmd, iov, iovcnt);
|
|
|
|
ocsp_free(ocsp);
|
|
return (ret);
|
|
}
|