summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormikeb <mikeb@openbsd.org>2017-03-13 18:49:20 +0000
committermikeb <mikeb@openbsd.org>2017-03-13 18:49:20 +0000
commit83e6846f5db17ad2b04f51ae5fab0425e51be247 (patch)
treeb3f411f860687839fe86c1172b397c05267f8d2d
parentResolve simultaneous IKE SA rekeying (diff)
downloadwireguard-openbsd-83e6846f5db17ad2b04f51ae5fab0425e51be247.tar.xz
wireguard-openbsd-83e6846f5db17ad2b04f51ae5fab0425e51be247.zip
Resolve simultaneous Child SA rekeying
From and OK markus, OK reyk
-rw-r--r--sbin/iked/config.c4
-rw-r--r--sbin/iked/iked.h5
-rw-r--r--sbin/iked/ikev2.c111
3 files changed, 113 insertions, 7 deletions
diff --git a/sbin/iked/config.c b/sbin/iked/config.c
index 527083d4d88..2f1c35196be 100644
--- a/sbin/iked/config.c
+++ b/sbin/iked/config.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: config.c,v 1.43 2017/01/03 17:51:38 reyk Exp $ */
+/* $OpenBSD: config.c,v 1.44 2017/03/13 18:49:20 mikeb Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -128,6 +128,8 @@ config_free_sa(struct iked *env, struct iked_sa *sa)
ibuf_release(sa->sa_dhiexchange);
ibuf_release(sa->sa_dhrexchange);
+ ibuf_release(sa->sa_simult);
+
hash_free(sa->sa_prf);
hash_free(sa->sa_integr);
cipher_free(sa->sa_encr);
diff --git a/sbin/iked/iked.h b/sbin/iked/iked.h
index c7b06f4f9de..d16404c75bb 100644
--- a/sbin/iked/iked.h
+++ b/sbin/iked/iked.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: iked.h,v 1.108 2017/03/13 18:48:16 mikeb Exp $ */
+/* $OpenBSD: iked.h,v 1.109 2017/03/13 18:49:20 mikeb Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -433,7 +433,8 @@ struct iked_sa {
struct iked_sa *sa_nexti; /* initiated IKE SA */
struct iked_sa *sa_nextr; /* simultaneous rekey */
- uint64_t sa_rekeyspi; /* peerspi for rekey*/
+ uint64_t sa_rekeyspi; /* peerspi CSA rekey*/
+ struct ibuf *sa_simult; /* simultaneous rekey */
uint8_t sa_ipcomp; /* IPcomp transform */
uint16_t sa_cpi_out; /* IPcomp outgoing */
diff --git a/sbin/iked/ikev2.c b/sbin/iked/ikev2.c
index 9021d635d63..15d57ba3806 100644
--- a/sbin/iked/ikev2.c
+++ b/sbin/iked/ikev2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ikev2.c,v 1.142 2017/03/13 18:48:16 mikeb Exp $ */
+/* $OpenBSD: ikev2.c,v 1.143 2017/03/13 18:49:20 mikeb Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -106,6 +106,8 @@ int ikev2_set_sa_proposal(struct iked_sa *, struct iked_policy *,
int ikev2_childsa_negotiate(struct iked *, struct iked_sa *,
struct iked_kex *, struct iked_proposals *, int, int, int);
+int ikev2_childsa_delete_proposed(struct iked *, struct iked_sa *,
+ struct iked_proposals *);
int ikev2_match_proposals(struct iked_proposal *, struct iked_proposal *,
struct iked_transform **, int);
int ikev2_valid_proposal(struct iked_proposal *,
@@ -2278,7 +2280,8 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa)
if (sa->sa_state == IKEV2_STATE_EAP)
return (ikev2_resp_ike_eap(env, sa, NULL));
- else if (!sa_stateok(sa, IKEV2_STATE_VALID))
+
+ if (!sa_stateok(sa, IKEV2_STATE_VALID))
return (0); /* ignore */
if (ikev2_cp_setaddr(env, sa, AF_INET) < 0 ||
@@ -2971,6 +2974,25 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg)
ibuf_release(sa->sa_rnonce);
sa->sa_rnonce = ibuf_dup(msg->msg_nonce);
+ if (csa && (ni = sa->sa_simult) != NULL) {
+ log_debug("%s: resolving simultaneous CHILD SA rekeying",
+ __func__);
+ /* set nr to minimum nonce for exchange initiated by peer */
+ if (ikev2_nonce_cmp(sa->sa_inonce, sa->sa_rnonce) < 0)
+ nr = sa->sa_inonce;
+ else
+ nr = sa->sa_rnonce;
+ /*
+ * If the exchange initated by us has smaller nonce,
+ * then we have to delete our SAs.
+ */
+ if (ikev2_nonce_cmp(ni, nr) < 0) {
+ ret = ikev2_childsa_delete_proposed(env, sa,
+ &sa->sa_proposals);
+ goto done;
+ }
+ }
+
if (ikev2_childsa_negotiate(env, sa, &sa->sa_kex, &sa->sa_proposals, 1,
pfs, !csa)) {
log_debug("%s: failed to get CHILD SAs", __func__);
@@ -3005,9 +3027,16 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg)
done:
sa->sa_stateflags &= ~IKED_REQ_CHILDSA;
+ ibuf_release(sa->sa_simult);
+ sa->sa_simult = NULL;
if (ret)
ikev2_childsa_delete(env, sa, 0, 0, NULL, 1);
+ else if (csa) {
+ /* delete the rekeyed SA pair */
+ ikev2_childsa_delete(env, sa, csa->csa_saproto,
+ csa->csa_peerspi, NULL, 0);
+ }
ibuf_release(buf);
return (ret);
}
@@ -3181,7 +3210,7 @@ ikev2_ikesa_recv_delete(struct iked *env, struct iked_sa *sa)
int
ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg)
{
- struct iked_childsa *csa;
+ struct iked_childsa *csa = NULL;
struct iked_proposal *prop;
struct iked_proposals proposals;
struct iked_kex *kex, *kextmp = NULL;
@@ -3331,6 +3360,19 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg)
log_debug("%s: failed to get CHILD SAs", __func__);
goto fail;
}
+
+ if (rekeying && (sa->sa_stateflags & IKED_REQ_CHILDSA) &&
+ csa && (sa->sa_rekeyspi == csa->csa_peerspi)) {
+ log_debug("%s: simultanous rekeying for CHILD SA %s/%s",
+ __func__,
+ print_spi(rekey->spi, rekey->spi_size),
+ print_spi(sa->sa_rekeyspi, rekey->spi_size));
+ ibuf_release(sa->sa_simult);
+ if (ikev2_nonce_cmp(kex->kex_inonce, nonce) < 0)
+ sa->sa_simult = ibuf_dup(kex->kex_inonce);
+ else
+ sa->sa_simult = ibuf_dup(nonce);
+ }
}
if ((e = ibuf_static()) == NULL)
@@ -4440,6 +4482,57 @@ ikev2_sa_tag(struct iked_sa *sa, struct iked_id *id)
}
int
+ikev2_childsa_delete_proposed(struct iked *env, struct iked_sa *sa,
+ struct iked_proposals *proposals)
+{
+ struct ibuf *buf = NULL;
+ struct iked_proposal *prop;
+ struct ikev2_delete *del;
+ uint32_t spi32;
+ uint8_t protoid = 0;
+ int ret = -1, count;
+
+ if (!sa_stateok(sa, IKEV2_STATE_VALID))
+ return (-1);
+
+ count = 0;
+ TAILQ_FOREACH(prop, proposals, prop_entry) {
+ if (ikev2_valid_proposal(prop, NULL, NULL, NULL) != 0)
+ continue;
+ protoid = prop->prop_protoid;
+ count++;
+ }
+ if (count == 0)
+ return (0);
+ if ((buf = ibuf_static()) == NULL)
+ return (-1);
+ if ((del = ibuf_advance(buf, sizeof(*del))) == NULL)
+ goto done;
+ /* XXX we assume all have the same protoid */
+ del->del_protoid = protoid;
+ del->del_spisize = 4;
+ del->del_nspi = htobe16(count);
+
+ TAILQ_FOREACH(prop, proposals, prop_entry) {
+ if (ikev2_valid_proposal(prop, NULL, NULL, NULL) != 0)
+ continue;
+ spi32 = htobe32(prop->prop_localspi.spi);
+ if (ibuf_add(buf, &spi32, sizeof(spi32)))
+ goto done;
+ }
+
+ if (ikev2_send_ike_e(env, sa, buf, IKEV2_PAYLOAD_DELETE,
+ IKEV2_EXCHANGE_INFORMATIONAL, 0) == -1)
+ goto done;
+ sa->sa_stateflags |= IKED_REQ_INF;
+ ret = 0;
+ done:
+ ibuf_release(buf);
+
+ return (ret);
+}
+
+int
ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa,
struct iked_kex *kex, struct iked_proposals *proposals, int initiator,
int pfs, int acquired)
@@ -4855,7 +4948,7 @@ ikev2_ipcomp_enable(struct iked *env, struct iked_sa *sa)
int
ikev2_childsa_enable(struct iked *env, struct iked_sa *sa)
{
- struct iked_childsa *csa;
+ struct iked_childsa *csa, *ocsa;
struct iked_flow *flow, *oflow;
if (sa->sa_ipcomp && sa->sa_cpi_in && sa->sa_cpi_out &&
@@ -4873,6 +4966,16 @@ ikev2_childsa_enable(struct iked *env, struct iked_sa *sa)
return (-1);
}
+ if ((ocsa = RB_FIND(iked_activesas, &env->sc_activesas, csa))
+ != NULL) {
+ log_debug("%s: replaced CHILD SA %p with %p spi %s",
+ __func__, ocsa, csa, print_spi(ocsa->csa_spi.spi,
+ ocsa->csa_spi.spi_size));
+ ocsa->csa_loaded = 0;
+ ocsa->csa_rekey = 1; /* prevent re-loading */
+ RB_REMOVE(iked_activesas, &env->sc_activesas, ocsa);
+ }
+
RB_INSERT(iked_activesas, &env->sc_activesas, csa);
log_debug("%s: loaded CHILD SA spi %s", __func__,