-/* $OpenBSD: ca.c,v 1.87 2021/12/14 13:44:36 tobhe Exp $ */
+/* $OpenBSD: ca.c,v 1.88 2022/07/08 19:51:11 tobhe Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
return (0);
}
+static int
+ca_setscert(struct iked *env, struct iked_sahdr *sh, uint8_t type, X509 *cert)
+{
+ struct iovec iov[3];
+ int iovcnt = 0;
+ struct ibuf *buf;
+ int ret;
+
+ if ((buf = ca_x509_serialize(cert)) == NULL)
+ return (-1);
+
+ iov[iovcnt].iov_base = sh;
+ iov[iovcnt].iov_len = sizeof(*sh);
+ iovcnt++;
+ iov[iovcnt].iov_base = &type;
+ iov[iovcnt].iov_len = sizeof(type);
+ iovcnt++;
+ iov[iovcnt].iov_base = ibuf_data(buf);
+ iov[iovcnt].iov_len = ibuf_size(buf);
+ iovcnt++;
+
+ ret = proc_composev(&env->sc_ps, PROC_IKEV2, IMSG_SCERT, iov, iovcnt);
+ ibuf_release(buf);
+ return (ret);
+}
+
int
ca_setreq(struct iked *env, struct iked_sa *sa,
struct iked_static_id *localid, uint8_t type, uint8_t more, uint8_t *data,
return (0);
}
+static unsigned int
+ca_chain_by_issuer(struct ca_store *store, X509_NAME *subject,
+ struct iked_static_id *id, X509 **dst, size_t dstlen)
+{
+ STACK_OF(X509_OBJECT) *h;
+ X509_OBJECT *xo;
+ X509 *cert;
+ int i;
+ unsigned int n;
+ X509_NAME *issuer, *subj;
+
+ if (subject == NULL || dstlen == 0)
+ return (0);
+
+ if ((cert = ca_by_issuer(store->ca_certs, subject, id)) != NULL) {
+ *dst = cert;
+ return (1);
+ }
+
+ h = X509_STORE_get0_objects(store->ca_cas);
+ for (i = 0; i < sk_X509_OBJECT_num(h); i++) {
+ xo = sk_X509_OBJECT_value(h, i);
+ if (X509_OBJECT_get_type(xo) != X509_LU_X509)
+ continue;
+ cert = X509_OBJECT_get0_X509(xo);
+ if ((issuer = X509_get_issuer_name(cert)) == NULL)
+ continue;
+ if (X509_NAME_cmp(subject, issuer) == 0) {
+ if ((subj = X509_get_subject_name(cert)) == NULL)
+ continue;
+ /* Skip root CAs */
+ if (X509_NAME_cmp(subj, issuer) == 0)
+ continue;
+ n = ca_chain_by_issuer(store, subj, id,
+ dst + 1, dstlen - 1);
+ if (n > 0) {
+ *dst = cert;
+ return (n + 1);
+ }
+ }
+ }
+
+ return (0);
+}
+
int
ca_getreq(struct iked *env, struct imsg *imsg)
{
size_t len;
unsigned int i;
X509 *ca = NULL, *cert = NULL;
+ X509 *chain[IKED_SCERT_MAX + 1];
+ size_t chain_len = 0;
struct ibuf *buf;
struct iked_static_id id;
char idstr[IKED_ID_SIZE];
log_debug("%s: found CA %s", __func__, subj_name);
free(subj_name);
- if ((cert = ca_by_issuer(store->ca_certs,
- subj, &id)) != NULL) {
+ chain_len = ca_chain_by_issuer(store, subj, &id,
+ chain, nitems(chain));
+ if (chain_len > 0) {
+ cert = chain[chain_len - 1];
if (!ca_cert_local(env, cert)) {
log_info("%s: found cert with matching "
"ID but without matching key.",
break;
}
}
+
+ for (i = chain_len; i >= 2; i--)
+ ca_setscert(env, &sh, type, chain[i - 2]);
+
/* Fallthrough */
case IKEV2_CERT_NONE:
fallback:
-/* $OpenBSD: config.c,v 1.85 2022/05/08 20:26:31 tobhe Exp $ */
+/* $OpenBSD: config.c,v 1.86 2022/07/08 19:51:11 tobhe Exp $ */
/*
* Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de>
void
config_free_sa(struct iked *env, struct iked_sa *sa)
{
+ int i;
+
timer_del(env, &sa->sa_timer);
timer_del(env, &sa->sa_keepalive);
timer_del(env, &sa->sa_rekey);
ibuf_release(sa->sa_rid.id_buf);
ibuf_release(sa->sa_icert.id_buf);
ibuf_release(sa->sa_rcert.id_buf);
+ for (i = 0; i < IKED_SCERT_MAX; i++)
+ ibuf_release(sa->sa_scert[i].id_buf);
ibuf_release(sa->sa_localauth.id_buf);
ibuf_release(sa->sa_peerauth.id_buf);
-/* $OpenBSD: eap.c,v 1.20 2022/01/28 05:24:15 guenther Exp $ */
+/* $OpenBSD: eap.c,v 1.21 2022/07/08 19:51:11 tobhe Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
uint8_t firstpayload;
int ret = -1;
ssize_t len = 0;
+ int i;
/* Responder only */
if (sa->sa_hdr.sh_initiator)
if (ibuf_cat(e, certid->id_buf) != 0)
goto done;
len = ibuf_size(certid->id_buf) + sizeof(*cert);
+
+ for (i = 0; i < IKED_SCERT_MAX; i++) {
+ if (sa->sa_scert[i].id_type == IKEV2_CERT_NONE)
+ break;
+ if (ikev2_next_payload(pld, len,
+ IKEV2_PAYLOAD_CERT) == -1)
+ goto done;
+ if ((pld = ikev2_add_payload(e)) == NULL)
+ goto done;
+ if ((cert = ibuf_advance(e, sizeof(*cert))) == NULL)
+ goto done;
+ cert->cert_type = sa->sa_scert[i].id_type;
+ if (ibuf_cat(e, sa->sa_scert[i].id_buf) != 0)
+ goto done;
+ len = ibuf_size(sa->sa_scert[i].id_buf) + sizeof(*cert);
+ }
}
if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_AUTH) == -1)
-/* $OpenBSD: iked.h,v 1.204 2022/03/14 12:58:55 tobhe Exp $ */
+/* $OpenBSD: iked.h,v 1.205 2022/07/08 19:51:11 tobhe Exp $ */
/*
* Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de>
struct iked_id sa_localauth; /* local AUTH message */
struct iked_id sa_peerauth; /* peer AUTH message */
int sa_sigsha2; /* use SHA2 for signatures */
+#define IKED_SCERT_MAX 3 /* max # of supplemental cert payloads */
struct iked_id sa_iid; /* initiator id */
struct iked_id sa_rid; /* responder id */
struct iked_id sa_icert; /* initiator cert */
struct iked_id sa_rcert; /* responder cert */
+ struct iked_id sa_scert[IKED_SCERT_MAX]; /* supplemental certs */
#define IKESA_SRCID(x) ((x)->sa_hdr.sh_initiator ? &(x)->sa_iid : &(x)->sa_rid)
#define IKESA_DSTID(x) ((x)->sa_hdr.sh_initiator ? &(x)->sa_rid : &(x)->sa_iid)
-/* $OpenBSD: ikev2.c,v 1.348 2022/07/04 08:39:55 tobhe Exp $ */
+/* $OpenBSD: ikev2.c,v 1.349 2022/07/08 19:51:11 tobhe Exp $ */
/*
* Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de>
size_t len;
struct iked_id *id = NULL;
int ignore = 0;
+ int i;
switch (imsg->hdr.type) {
case IMSG_CERTREQ:
if (ikev2_ike_auth(env, sa) != 0)
log_debug("%s: failed to send ike auth", __func__);
break;
+ case IMSG_SCERT:
+ if ((sa = ikev2_getimsgdata(env, imsg,
+ &sh, &type, &ptr, &len)) == NULL) {
+ log_debug("%s: invalid supplemental cert reply",
+ __func__);
+ break;
+ }
+
+ if (sa->sa_stateflags & IKED_REQ_CERT ||
+ type == IKEV2_CERT_NONE)
+ ignore = 1;
+
+ log_debug("%s: supplemental cert type %s length %zu, %s",
+ __func__,
+ print_map(type, ikev2_cert_map), len,
+ ignore ? "ignored" : "ok");
+
+ if (ignore)
+ break;
+
+ for (i = 0; i < IKED_SCERT_MAX; i++) {
+ id = &sa->sa_scert[i];
+ if (id->id_type == IKEV2_CERT_NONE)
+ break;
+ id = NULL;
+ }
+
+ if (id == NULL) {
+ log_debug("%s: too many supplemental cert. ignored",
+ __func__);
+ break;
+ }
+
+ id->id_type = type;
+ id->id_offset = 0;
+ ibuf_release(id->id_buf);
+ id->id_buf = NULL;
+
+ if (len <= 0 || (id->id_buf = ibuf_new(ptr, len)) == NULL) {
+ log_debug("%s: failed to get supplemental cert payload",
+ __func__);
+ break;
+ }
+
+ break;
case IMSG_AUTH:
if ((sa = ikev2_getimsgdata(env, imsg,
&sh, &type, &ptr, &len)) == NULL) {
uint8_t firstpayload;
int ret = -1;
ssize_t len;
+ int i;
if (!sa_stateok(sa, IKEV2_STATE_SA_INIT))
return (0);
goto done;
len = ibuf_size(certid->id_buf) + sizeof(*cert);
+ for (i = 0; i < IKED_SCERT_MAX; i++) {
+ if (sa->sa_scert[i].id_type == IKEV2_CERT_NONE)
+ break;
+ if (ikev2_next_payload(pld, len,
+ IKEV2_PAYLOAD_CERT) == -1)
+ goto done;
+ if ((pld = ikev2_add_payload(e)) == NULL)
+ goto done;
+ if ((cert = ibuf_advance(e, sizeof(*cert))) == NULL)
+ goto done;
+ cert->cert_type = sa->sa_scert[i].id_type;
+ if (ibuf_cat(e, sa->sa_scert[i].id_buf) != 0)
+ goto done;
+ len = ibuf_size(sa->sa_scert[i].id_buf) + sizeof(*cert);
+ }
+
/* CERTREQ payload(s) */
if ((len = ikev2_add_certreq(e, &pld,
len, env->sc_certreq, env->sc_certreqtype)) == -1)
uint8_t firstpayload;
int ret = -1;
ssize_t len;
+ int i;
if (sa == NULL)
return (-1);
if (ibuf_cat(e, certid->id_buf) != 0)
goto done;
len = ibuf_size(certid->id_buf) + sizeof(*cert);
+
+ for (i = 0; i < IKED_SCERT_MAX; i++) {
+ if (sa->sa_scert[i].id_type == IKEV2_CERT_NONE)
+ break;
+ if (ikev2_next_payload(pld, len,
+ IKEV2_PAYLOAD_CERT) == -1)
+ goto done;
+ if ((pld = ikev2_add_payload(e)) == NULL)
+ goto done;
+ if ((cert = ibuf_advance(e,
+ sizeof(*cert))) == NULL)
+ goto done;
+ cert->cert_type = sa->sa_scert[i].id_type;
+ if (ibuf_cat(e, sa->sa_scert[i].id_buf) != 0)
+ goto done;
+ len = ibuf_size(sa->sa_scert[i].id_buf)
+ + sizeof(*cert);
+ }
}
if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_AUTH) == -1)
struct iked_childsa *csa, *csatmp, *ipcomp;
struct iked_flow *flow, *flowtmp;
struct iked_proposal *prop, *proptmp;
+ int i;
log_debug("%s: IKE SA %p ispi %s rspi %s replaced"
" by SA %p ispi %s rspi %s ",
nsa->sa_icert = sa->sa_rcert;
nsa->sa_rcert = sa->sa_icert;
}
+ for (i = 0; i < IKED_SCERT_MAX; i++)
+ nsa->sa_scert[i] = sa->sa_scert[i];
/* duplicate the actual buffer */
nsa->sa_iid.id_buf = ibuf_dup(nsa->sa_iid.id_buf);
nsa->sa_rid.id_buf = ibuf_dup(nsa->sa_rid.id_buf);
nsa->sa_icert.id_buf = ibuf_dup(nsa->sa_icert.id_buf);
nsa->sa_rcert.id_buf = ibuf_dup(nsa->sa_rcert.id_buf);
+ for (i = 0; i < IKED_SCERT_MAX; i++)
+ nsa->sa_scert[i].id_buf = ibuf_dup(nsa->sa_scert[i].id_buf);
/* Transfer sa_addrpool address */
if (sa->sa_addrpool) {
-/* $OpenBSD: types.h,v 1.48 2022/04/13 20:54:55 deraadt Exp $ */
+/* $OpenBSD: types.h,v 1.49 2022/07/08 19:51:11 tobhe Exp $ */
/*
* Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de>
IMSG_CERTVALID,
IMSG_CERTINVALID,
IMSG_CERT_PARTIAL_CHAIN,
+ IMSG_SCERT,
IMSG_IF_ADDADDR,
IMSG_IF_DELADDR,
IMSG_VROUTE_ADD,