On 2017/12/05 12:53, Patrick Wildt wrote:
> Hi,
>
> this diff changes the config parsing code so that we can specify
> multiple ikesa and childsa proposals by using the keywords multiple
> times. It needs the other payload parsing diff that I posted as well.
>
> Multiple proposals can be specified like this:
>
> ikesa auth hmac-sha2-256 enc aes-192 group modp2048 \
> ikesa auth hmac-sha2-256 enc aes-256 group modp2048 \
> ikesa auth hmac-sha1 enc aes-256 group modp2048 \
> childsa auth hmac-sha2-256 enc aes-192 group modp2048 \
> childsa auth hmac-sha2-256 enc aes-256 group modp2048 \
> childsa auth hmac-sha1 enc aes-256 group modp2048 \
>
> ok?
Sorry about the slow review. Code diff is OK with me, but it needs a
little change to iked.conf(5) to go with it.
> Patrick
>
> diff --git a/sbin/iked/parse.y b/sbin/iked/parse.y
> index 58b12e6d0b4..25f9360bf9c 100644
> --- a/sbin/iked/parse.y
> +++ b/sbin/iked/parse.y
> @@ -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 <v.ikemode> ikeflags ikematch ikemode ipcomp
> %type <v.ikeauth> ikeauth
> %type <v.ikekey> keyspec
> -%type <v.mode> ike_sa child_sa
> +%type <v.mode> ike_sas child_sas
> %type <v.lifetime> lifetime
> %type <v.number> byte_spec time_spec ikelifetime
> %type <v.string> 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
>