diff options
author | tobhe <tobhe@cvs.openbsd.org> | 2020-03-10 18:54:53 +0000 |
---|---|---|
committer | tobhe <tobhe@cvs.openbsd.org> | 2020-03-10 18:54:53 +0000 |
commit | b874ea54931b57bbdad778db396825933357c74d (patch) | |
tree | 8ffdb0fddcaca69ad9b5d150d22799b634f891de /sbin | |
parent | 89ed148f5add72062812c42d299ecd4683dacf44 (diff) |
Relookup policy based on received cryptographic parameter proposal.
The IKEv2 responder does not know which policy is negotiated until
the ID payload is received in the IKE_AUTH exchange.
iked therefore chooses a default policy until the final policy is
selected. This change adds a policy relookup during the IKE_SA_INIT.
If the received proposal is not compatible with the default policy
we switch to the next highest ranked policy that is compatible
with the received proposal.
ok kn@ markus@
Diffstat (limited to 'sbin')
-rw-r--r-- | sbin/iked/iked.h | 5 | ||||
-rw-r--r-- | sbin/iked/ikev2.c | 32 | ||||
-rw-r--r-- | sbin/iked/policy.c | 10 |
3 files changed, 36 insertions, 11 deletions
diff --git a/sbin/iked/iked.h b/sbin/iked/iked.h index dec990e965e..785d6039c77 100644 --- a/sbin/iked/iked.h +++ b/sbin/iked/iked.h @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.h,v 1.135 2020/03/01 19:17:58 tobhe Exp $ */ +/* $OpenBSD: iked.h,v 1.136 2020/03/10 18:54:52 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de> @@ -777,7 +777,8 @@ int config_getnattport(struct iked *, struct imsg *); /* policy.c */ void policy_init(struct iked *); -int policy_lookup(struct iked *, struct iked_message *); +int policy_lookup(struct iked *, struct iked_message *, + struct iked_proposals *proposals); struct iked_policy * policy_test(struct iked *, struct iked_policy *); int policy_generate_ts(struct iked_policy *); diff --git a/sbin/iked/ikev2.c b/sbin/iked/ikev2.c index 60f7f971ea9..2dd2b2c648d 100644 --- a/sbin/iked/ikev2.c +++ b/sbin/iked/ikev2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.c,v 1.194 2020/03/10 10:19:22 tobhe Exp $ */ +/* $OpenBSD: ikev2.c,v 1.195 2020/03/10 18:54:52 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de> @@ -444,7 +444,7 @@ ikev2_recv(struct iked *env, struct iked_message *msg) betoh64(hdr->ike_ispi), betoh64(hdr->ike_rspi), initiator); msg->msg_msgid = betoh32(hdr->ike_msgid); - if (policy_lookup(env, msg) != 0) + if (policy_lookup(env, msg, NULL) != 0) return; log_info("%srecv %s %s %u peer %s local %s, %ld bytes, policy '%s'", @@ -633,7 +633,7 @@ ikev2_ike_auth_recv(struct iked *env, struct iked_sa *sa, struct iked_policy *old = sa->sa_policy; sa->sa_policy = NULL; - if (policy_lookup(env, msg) == 0 && msg->msg_policy && + if (policy_lookup(env, msg, &sa->sa_proposals) == 0 && msg->msg_policy && msg->msg_policy != old) { /* move sa to new policy */ policy = sa->sa_policy = msg->msg_policy; @@ -4618,6 +4618,7 @@ ikev2_sa_responder(struct iked *env, struct iked_sa *sa, struct iked_sa *osa, struct iked_message *msg) { struct iked_transform *xform; + struct iked_policy *old; sa_state(env, sa, IKEV2_STATE_SA_INIT); @@ -4641,12 +4642,31 @@ ikev2_sa_responder(struct iked *env, struct iked_sa *sa, struct iked_sa *osa, } /* XXX we need a better way to get this */ - if (proposals_negotiate(&sa->sa_proposals, - &msg->msg_policy->pol_proposals, &msg->msg_proposals, 0) != 0) { + old = sa->sa_policy; + sa->sa_policy = NULL; + if (policy_lookup(env, msg, &msg->msg_proposals) != 0 || msg->msg_policy == NULL) { + sa->sa_policy = old; log_info("%s: no proposal chosen", __func__); msg->msg_error = IKEV2_N_NO_PROPOSAL_CHOSEN; return (-1); - } else if (sa_stateok(sa, IKEV2_STATE_SA_INIT)) + } + sa->sa_policy = msg->msg_policy; + /* move sa to new policy */ + sa->sa_policy = msg->msg_policy; + TAILQ_REMOVE(&old->pol_sapeers, sa, sa_peer_entry); + TAILQ_INSERT_TAIL(&sa->sa_policy->pol_sapeers, + sa, sa_peer_entry); + if (old->pol_flags & IKED_POLICY_REFCNT) + policy_unref(env, old); + if (sa->sa_policy->pol_flags & IKED_POLICY_REFCNT) + policy_ref(env, sa->sa_policy); + + if (proposals_negotiate(&sa->sa_proposals, + &msg->msg_policy->pol_proposals, &msg->msg_proposals, 0) != 0) { + log_info("%s: proposals_negotiate", __func__); + return (-1); + } + if (sa_stateok(sa, IKEV2_STATE_SA_INIT)) sa_stateflags(sa, IKED_REQ_SA); if (sa->sa_encr == NULL) { diff --git a/sbin/iked/policy.c b/sbin/iked/policy.c index 6c9baa9b619..67d0b8baa31 100644 --- a/sbin/iked/policy.c +++ b/sbin/iked/policy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: policy.c,v 1.56 2020/03/09 11:50:43 tobhe Exp $ */ +/* $OpenBSD: policy.c,v 1.57 2020/03/10 18:54:52 tobhe Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -64,12 +64,15 @@ policy_init(struct iked *env) * Lookup an iked policy matching the IKE_AUTH message msg * and store a pointer to the found policy in msg. If no policy * matches a pointer to the default policy is stored in msg. + * If 'proposals' is not NULL policy_lookup only returns policies + * compatible with 'proposals'. * * Returns 0 on success and -1 if no matching policy was * found and no default exists. */ int -policy_lookup(struct iked *env, struct iked_message *msg) +policy_lookup(struct iked *env, struct iked_message *msg, + struct iked_proposals *proposals) { struct iked_policy pol; char *s, idstr[IKED_ID_SIZE]; @@ -82,13 +85,14 @@ policy_lookup(struct iked *env, struct iked_message *msg) } bzero(&pol, sizeof(pol)); + if (proposals != NULL) + pol.pol_proposals = *proposals; pol.pol_af = msg->msg_peer.ss_family; memcpy(&pol.pol_peer.addr, &msg->msg_peer, sizeof(msg->msg_peer)); memcpy(&pol.pol_local.addr, &msg->msg_local, sizeof(msg->msg_local)); if (msg->msg_id.id_type && ikev2_print_id(&msg->msg_id, idstr, IKED_ID_SIZE) == 0 && (s = strchr(idstr, '/')) != NULL) { - pol.pol_proposals = msg->msg_sa->sa_proposals; pol.pol_peerid.id_type = msg->msg_id.id_type; pol.pol_peerid.id_length = strlen(s+1); strlcpy(pol.pol_peerid.id_data, s+1, |