From ebfe4fe0f31a7e48b3252ff6d0f05e812ce32e1f Mon Sep 17 00:00:00 2001 From: patrick Date: Wed, 24 Jan 2018 17:01:52 +0000 Subject: [PATCH] Implement support for specifying multiple proposals. This means we can have a higher flexibility in negotiating with other peers, or even ease migration from one proposal to a more secure one. ok sthen@ --- sbin/iked/iked.conf.5 | 12 +- sbin/iked/parse.y | 280 ++++++++++++++++++++++++++---------------- 2 files changed, 186 insertions(+), 106 deletions(-) diff --git a/sbin/iked/iked.conf.5 b/sbin/iked/iked.conf.5 index 2cf778599b4..8ee77f4d24b 100644 --- a/sbin/iked/iked.conf.5 +++ b/sbin/iked/iked.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: iked.conf.5,v 1.51 2017/11/27 18:39:35 patrick Exp $ +.\" $OpenBSD: iked.conf.5,v 1.52 2018/01/24 17:01:52 patrick Exp $ .\" .\" Copyright (c) 2010 - 2014 Reyk Floeter .\" Copyright (c) 2004 Mathieu Sauve-Frankel All rights reserved. @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: November 27 2017 $ +.Dd $Mdocdate: January 24 2018 $ .Dt IKED.CONF 5 .Os .Sh NAME @@ -385,6 +385,9 @@ and the default proposals are described below in If omitted, .Xr iked 8 will use the default proposals for the IKEv2 protocol. +To specify multiple IKE SA proposals, the keyword can be used more +than once. +The order of the proposals depend on the order in the configuration. .It Xo .Ic childsa .Ic auth Ar algorithm @@ -407,6 +410,9 @@ and the default proposals are described below in If omitted, .Xr iked 8 will use the default proposals for the ESP or AH protocol. +To specify multiple Child SA proposals, the keyword can be used more +than once. +The order of the proposals depend on the order in the configuration. The .Ic group option will only be used to enable Perfect Forward Secrecy (PFS) @@ -885,7 +891,9 @@ ikev2 "big test" \e from 10.0.0.0/8 port 23 to 20.0.0.0/8 port 40 \e from 192.168.1.1 to 192.168.2.2 \e peer any local any \e + ikesa enc 3des auth hmac-sha2-256 group modp1024 \e ikesa enc 3des auth hmac-sha1 group modp1024 \e + childsa enc aes-128 auth hmac-sha2-256 \e childsa enc aes-128 auth hmac-sha1 \e srcid host.example.com \e dstid 192.168.0.254 \e diff --git a/sbin/iked/parse.y b/sbin/iked/parse.y index 58b12e6d0b4..1be751b1dae 100644 --- a/sbin/iked/parse.y +++ b/sbin/iked/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.68 2017/12/01 20:19:05 patrick Exp $ */ +/* $OpenBSD: parse.y,v 1.69 2018/01/24 17:01:52 patrick Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -120,8 +120,8 @@ struct ipsec_transforms { }; struct ipsec_mode { - struct ipsec_transforms *xfs; - uint8_t ike_exch; + struct ipsec_transforms **xfs; + unsigned int nxfs; }; struct iked_transform ikev2_default_ike_transforms[] = { @@ -329,9 +329,8 @@ const struct ipsec_xf *parse_xf(const char *, unsigned int, const char *print_xf(unsigned int, unsigned int, const struct ipsec_xf *); void copy_transforms(unsigned int, const struct ipsec_xf *, - const struct ipsec_xf *, - struct iked_transform *, size_t, - unsigned int *, struct iked_transform *, size_t); + struct iked_transform **, unsigned int *, + struct iked_transform *, size_t); int create_ike(char *, int, uint8_t, struct ipsec_hosts *, struct ipsec_hosts *, struct ipsec_mode *, struct ipsec_mode *, uint8_t, @@ -347,6 +346,7 @@ int parsekeyfile(char *, struct iked_auth *); struct ipsec_transforms *ipsec_transforms; struct ipsec_filters *ipsec_filters; +struct ipsec_mode *ipsec_mode; typedef struct { union { @@ -405,7 +405,7 @@ typedef struct { %type ikeflags ikematch ikemode ipcomp %type ikeauth %type keyspec -%type ike_sa child_sa +%type ike_sas child_sas %type lifetime %type byte_spec time_spec ikelifetime %type name @@ -463,7 +463,7 @@ user : USER STRING STRING { ; ikev2rule : IKEV2 name ikeflags satype af proto hosts_list peers - ike_sa child_sa ids ikelifetime lifetime ikeauth ikecfg + ike_sas child_sas ids ikelifetime lifetime ikeauth ikecfg filters { if (create_ike($2, $5, $6, $7, &$8, $9, $10, $4, $3, $11.srcid, $11.dstid, $12, &$13, &$14, @@ -774,27 +774,61 @@ transform : AUTHXF STRING { } ; -ike_sa : /* empty */ { +ike_sas : { + if ((ipsec_mode = calloc(1, + sizeof(struct ipsec_mode))) == NULL) + err(1, "ike_sas: calloc"); + } + ike_sas_l { + $$ = ipsec_mode; + } + | /* empty */ { $$ = NULL; } - | IKESA { + ; + +ike_sas_l : ike_sas_l ike_sa + | ike_sa + ; + +ike_sa : IKESA { + if ((ipsec_mode->xfs = recallocarray(ipsec_mode->xfs, + ipsec_mode->nxfs, ipsec_mode->nxfs + 1, + sizeof(struct ipsec_transforms *))) == NULL) + err(1, "ike_sa: recallocarray"); + ipsec_mode->nxfs++; encxfs = ikeencxfs; } transforms { - if (($$ = calloc(1, sizeof(*$$))) == NULL) - err(1, "ike_sa: calloc"); - $$->xfs = $3; + ipsec_mode->xfs[ipsec_mode->nxfs - 1] = $3; } ; -child_sa : /* empty */ { +child_sas : { + if ((ipsec_mode = calloc(1, + sizeof(struct ipsec_mode))) == NULL) + err(1, "child_sas: calloc"); + } + child_sas_l { + $$ = ipsec_mode; + } + | /* empty */ { $$ = NULL; } - | CHILDSA { + ; + +child_sas_l : child_sas_l child_sa + | child_sa + ; + +child_sa : CHILDSA { + if ((ipsec_mode->xfs = recallocarray(ipsec_mode->xfs, + ipsec_mode->nxfs, ipsec_mode->nxfs + 1, + sizeof(struct ipsec_transforms *))) == NULL) + err(1, "child_sa: recallocarray"); + ipsec_mode->nxfs++; encxfs = ipsecencxfs; } transforms { - if (($$ = calloc(1, sizeof(*$$))) == NULL) - err(1, "child_sa: calloc"); - $$->xfs = $3; + ipsec_mode->xfs[ipsec_mode->nxfs - 1] = $3; } ; @@ -2544,17 +2578,18 @@ print_policy(struct iked_policy *pol) void copy_transforms(unsigned int type, const struct ipsec_xf *xf, - const struct ipsec_xf *xfs, - struct iked_transform *dst, size_t ndst, - unsigned int *n, struct iked_transform *src, size_t nsrc) + struct iked_transform **dst, unsigned int *ndst, + struct iked_transform *src, size_t nsrc) { unsigned int i; struct iked_transform *a, *b; if (xf != NULL) { - if (*n >= ndst) - return; - b = dst + (*n)++; + *dst = recallocarray(*dst, *ndst, + *ndst + 1, sizeof(struct iked_transform)); + if (*dst == NULL) + err(1, "copy_transforms: recallocarray"); + b = *dst + (*ndst)++; b->xform_type = type; b->xform_id = xf->id; @@ -2567,9 +2602,11 @@ copy_transforms(unsigned int type, const struct ipsec_xf *xf, a = src + i; if (a->xform_type != type) continue; - if (*n >= ndst) - return; - b = dst + (*n)++; + *dst = recallocarray(*dst, *ndst, + *ndst + 1, sizeof(struct iked_transform)); + if (*dst == NULL) + err(1, "copy_transforms: recallocarray"); + b = *dst + (*ndst)++; memcpy(b, a, sizeof(*b)); } } @@ -2587,18 +2624,16 @@ create_ike(char *name, int af, uint8_t ipproto, struct ipsec_hosts *hosts, unsigned int idtype = IKEV2_ID_NONE; struct ipsec_addr_wrap *ipa, *ipb, *ippn; struct iked_policy pol; - struct iked_proposal prop[2]; - unsigned int j; + struct iked_proposal *p, *ptmp; + struct iked_transform *xf; + unsigned int i, j, xfi; unsigned int ikepropid = 1, ipsecpropid = 1; - struct iked_transform ikexforms[64], ipsecxforms[64]; struct iked_flow flows[64]; static unsigned int policy_id = 0; struct iked_cfg *cfg; + int ret = -1; bzero(&pol, sizeof(pol)); - bzero(&prop, sizeof(prop)); - bzero(&ikexforms, sizeof(ikexforms)); - bzero(&ipsecxforms, sizeof(ipsecxforms)); bzero(&flows, sizeof(flows)); bzero(idstr, sizeof(idstr)); @@ -2720,79 +2755,106 @@ create_ike(char *name, int af, uint8_t ipproto, struct ipsec_hosts *hosts, TAILQ_INIT(&pol.pol_proposals); RB_INIT(&pol.pol_flows); - prop[0].prop_id = ikepropid++; - prop[0].prop_protoid = IKEV2_SAPROTO_IKE; - if (ike_sa == NULL || ike_sa->xfs == NULL) { - prop[0].prop_nxforms = ikev2_default_nike_transforms; - prop[0].prop_xforms = ikev2_default_ike_transforms; - } else { - j = 0; - copy_transforms(IKEV2_XFORMTYPE_INTEGR, - ike_sa->xfs->authxf, authxfs, - ikexforms, nitems(ikexforms), &j, - ikev2_default_ike_transforms, - ikev2_default_nike_transforms); - copy_transforms(IKEV2_XFORMTYPE_ENCR, - ike_sa->xfs->encxf, ikeencxfs, - ikexforms, nitems(ikexforms), &j, - ikev2_default_ike_transforms, - ikev2_default_nike_transforms); - copy_transforms(IKEV2_XFORMTYPE_DH, - ike_sa->xfs->groupxf, groupxfs, - ikexforms, nitems(ikexforms), &j, - ikev2_default_ike_transforms, - ikev2_default_nike_transforms); - copy_transforms(IKEV2_XFORMTYPE_PRF, - ike_sa->xfs->prfxf, prfxfs, - ikexforms, nitems(ikexforms), &j, - ikev2_default_ike_transforms, - ikev2_default_nike_transforms); - prop[0].prop_nxforms = j; - prop[0].prop_xforms = ikexforms; - } - TAILQ_INSERT_TAIL(&pol.pol_proposals, &prop[0], prop_entry); - pol.pol_nproposals++; - - prop[1].prop_id = ipsecpropid++; - prop[1].prop_protoid = saproto; - if (ipsec_sa == NULL || ipsec_sa->xfs == NULL) { - prop[1].prop_nxforms = ikev2_default_nesp_transforms; - prop[1].prop_xforms = ikev2_default_esp_transforms; + if (ike_sa == NULL || ike_sa->nxfs == 0) { + if ((p = calloc(1, sizeof(*p))) == NULL) + err(1, "create_ike: calloc"); + p->prop_id = ikepropid++; + p->prop_protoid = IKEV2_SAPROTO_IKE; + p->prop_nxforms = ikev2_default_nike_transforms; + p->prop_xforms = ikev2_default_ike_transforms; + TAILQ_INSERT_TAIL(&pol.pol_proposals, p, prop_entry); + pol.pol_nproposals++; } else { - j = 0; - if (ipsec_sa->xfs->encxf && ipsec_sa->xfs->encxf->noauth && - ipsec_sa->xfs->authxf) { - yyerror("authentication is implicit for %s", - ipsec_sa->xfs->encxf->name); - return (-1); - } - if (ipsec_sa->xfs->encxf == NULL || - (ipsec_sa->xfs->encxf && !ipsec_sa->xfs->encxf->noauth)) + for (i = 0; i < ike_sa->nxfs; i++) { + if ((p = calloc(1, sizeof(*p))) == NULL) + err(1, "create_ike: calloc"); + + xf = NULL; + xfi = 0; copy_transforms(IKEV2_XFORMTYPE_INTEGR, - ipsec_sa->xfs->authxf, authxfs, - ipsecxforms, nitems(ipsecxforms), &j, + ike_sa->xfs[i]->authxf, &xf, &xfi, + ikev2_default_ike_transforms, + ikev2_default_nike_transforms); + copy_transforms(IKEV2_XFORMTYPE_ENCR, + ike_sa->xfs[i]->encxf, &xf, &xfi, + ikev2_default_ike_transforms, + ikev2_default_nike_transforms); + copy_transforms(IKEV2_XFORMTYPE_DH, + ike_sa->xfs[i]->groupxf, &xf, &xfi, + ikev2_default_ike_transforms, + ikev2_default_nike_transforms); + copy_transforms(IKEV2_XFORMTYPE_PRF, + ike_sa->xfs[i]->prfxf, &xf, &xfi, + ikev2_default_ike_transforms, + ikev2_default_nike_transforms); + free(ike_sa->xfs[i]); + + p->prop_id = ikepropid++; + p->prop_protoid = IKEV2_SAPROTO_IKE; + p->prop_xforms = xf; + p->prop_nxforms = xfi; + TAILQ_INSERT_TAIL(&pol.pol_proposals, p, prop_entry); + pol.pol_nproposals++; + } + free(ike_sa->xfs); + } + free(ike_sa); + + if (ipsec_sa == NULL || ipsec_sa->nxfs == 0) { + if ((p = calloc(1, sizeof(*p))) == NULL) + err(1, "create_ike: calloc"); + p->prop_id = ipsecpropid++; + p->prop_protoid = saproto; + p->prop_nxforms = ikev2_default_nesp_transforms; + p->prop_xforms = ikev2_default_esp_transforms; + TAILQ_INSERT_TAIL(&pol.pol_proposals, p, prop_entry); + pol.pol_nproposals++; + } else { + for (i = 0; i < ipsec_sa->nxfs; i++) { + if (ipsec_sa->xfs[i]->encxf && + ipsec_sa->xfs[i]->encxf->noauth && + ipsec_sa->xfs[i]->authxf) { + yyerror("authentication is implicit for %s", + ipsec_sa->xfs[i]->encxf->name); + return (-1); + } + + if ((p = calloc(1, sizeof(*p))) == NULL) + err(1, "create_ike: calloc"); + + xf = NULL; + xfi = 0; + if (ipsec_sa->xfs[i]->encxf == NULL || + (ipsec_sa->xfs[i]->encxf && + !ipsec_sa->xfs[i]->encxf->noauth)) + copy_transforms(IKEV2_XFORMTYPE_INTEGR, + ipsec_sa->xfs[i]->authxf, &xf, &xfi, + ikev2_default_esp_transforms, + ikev2_default_nesp_transforms); + copy_transforms(IKEV2_XFORMTYPE_ENCR, + ipsec_sa->xfs[i]->encxf, &xf, &xfi, ikev2_default_esp_transforms, ikev2_default_nesp_transforms); - copy_transforms(IKEV2_XFORMTYPE_ENCR, - ipsec_sa->xfs->encxf, ipsecencxfs, - ipsecxforms, nitems(ipsecxforms), &j, - ikev2_default_esp_transforms, - ikev2_default_nesp_transforms); - copy_transforms(IKEV2_XFORMTYPE_DH, - ipsec_sa->xfs->groupxf, groupxfs, - ipsecxforms, nitems(ipsecxforms), &j, - ikev2_default_esp_transforms, - ikev2_default_nesp_transforms); - copy_transforms(IKEV2_XFORMTYPE_ESN, - NULL, NULL, - ipsecxforms, nitems(ipsecxforms), &j, - ikev2_default_esp_transforms, - ikev2_default_nesp_transforms); - prop[1].prop_nxforms = j; - prop[1].prop_xforms = ipsecxforms; - } - TAILQ_INSERT_TAIL(&pol.pol_proposals, &prop[1], prop_entry); - pol.pol_nproposals++; + copy_transforms(IKEV2_XFORMTYPE_DH, + ipsec_sa->xfs[i]->groupxf, &xf, &xfi, + ikev2_default_esp_transforms, + ikev2_default_nesp_transforms); + copy_transforms(IKEV2_XFORMTYPE_ESN, + NULL, &xf, &xfi, + ikev2_default_esp_transforms, + ikev2_default_nesp_transforms); + free(ipsec_sa->xfs[i]); + + p->prop_id = ipsecpropid++; + p->prop_protoid = saproto; + p->prop_xforms = xf; + p->prop_nxforms = xfi; + TAILQ_INSERT_TAIL(&pol.pol_proposals, p, prop_entry); + pol.pol_nproposals++; + } + free(ipsec_sa->xfs); + } + free(ipsec_sa); if (hosts == NULL || hosts->src == NULL || hosts->dst == NULL) fatalx("create_ike: no traffic selectors/flows"); @@ -2871,14 +2933,24 @@ create_ike(char *name, int af, uint8_t ipproto, struct ipsec_hosts *hosts, /* Make sure that we know how to authenticate this peer */ if (idtype && set_policy(idstr, idtype, &pol) < 0) { log_debug("%s: set_policy failed", __func__); - return (-1); + goto done; } config_setpolicy(env, &pol, PROC_IKEV2); config_setflow(env, &pol, PROC_IKEV2); rules++; - return (0); + ret = 0; + +done: + TAILQ_FOREACH_SAFE(p, &pol.pol_proposals, prop_entry, ptmp) { + if (p->prop_xforms != ikev2_default_ike_transforms && + p->prop_xforms != ikev2_default_esp_transforms) + free(p->prop_xforms); + free(p); + } + + return (ret); } int -- 2.20.1