ok
2017-10-24 16:25 GMT+02:00 Patrick Wildt <[email protected]>:
> Hi,
>
> in the final RFC 5903 the computation for the DH shared secret changed.
> Instead of the full point, only the X point is included. Unfortunately
> this is a backwards incompatible change, so older ikeds won't be com-
> patible with this change is committed. Of course only if you use ECP.
> Anyway, this change makes us follow the RFC correctly.
>
> Source: https://tools.ietf.org/html/rfc5903 - 9. Changes from RFC 4753
>
> ok?
>
> Patrick
>
> diff --git a/sbin/iked/dh.c b/sbin/iked/dh.c
> index a8308eec596..a3ef5f80906 100644
> --- a/sbin/iked/dh.c
> +++ b/sbin/iked/dh.c
> @@ -38,10 +38,13 @@ int modp_create_shared(struct group *, uint8_t *, uint8_t
> *);
> /* EC2N/ECP */
> int ec_init(struct group *);
> int ec_getlen(struct group *);
> +int ec_secretlen(struct group *);
> int ec_create_exchange(struct group *, uint8_t *);
> int ec_create_shared(struct group *, uint8_t *, uint8_t *);
>
> -int ec_point2raw(struct group *, const EC_POINT *, uint8_t *, size_t);
> +#define EC_POINT2RAW_FULL 0
> +#define EC_POINT2RAW_XONLY 1
> +int ec_point2raw(struct group *, const EC_POINT *, uint8_t *, size_t,
> int);
> EC_POINT *
> ec_raw2point(struct group *, uint8_t *, size_t);
>
> @@ -293,6 +296,7 @@ group_get(uint32_t id)
> case GROUP_ECP:
> group->init = ec_init;
> group->getlen = ec_getlen;
> + group->secretlen = ec_secretlen;
> group->exchange = ec_create_exchange;
> group->shared = ec_create_shared;
> break;
> @@ -343,6 +347,15 @@ dh_getlen(struct group *group)
> return (group->getlen(group));
> }
>
> +int
> +dh_secretlen(struct group *group)
> +{
> + if (group->secretlen)
> + return (group->secretlen(group));
> + else
> + return (group->getlen(group));
> +}
> +
> int
> dh_create_exchange(struct group *group, uint8_t *buf)
> {
> @@ -450,6 +463,20 @@ ec_getlen(struct group *group)
> return ((roundup(group->spec->bits, 8) * 2) / 8);
> }
>
> +/*
> + * Note that the shared secret only includes the x value:
> + *
> + * See RFC 5903, 7. ECP Key Exchange Data Formats:
> + * The Diffie-Hellman shared secret value consists of the x value of the
> + * Diffie-Hellman common value.
> + * See also RFC 5903, 9. Changes from RFC 4753.
> + */
> +int
> +ec_secretlen(struct group *group)
> +{
> + return (ec_getlen(group) / 2);
> +}
> +
> int
> ec_create_exchange(struct group *group, uint8_t *buf)
> {
> @@ -459,7 +486,7 @@ ec_create_exchange(struct group *group, uint8_t *buf)
> bzero(buf, len);
>
> return (ec_point2raw(group, EC_KEY_get0_public_key(group->ec),
> - buf, len));
> + buf, len, EC_POINT2RAW_FULL));
> }
>
> int
> @@ -496,7 +523,8 @@ ec_create_shared(struct group *group, uint8_t *secret,
> uint8_t *exchange)
> if (!EC_POINT_mul(ecgroup, secretp, NULL, exchangep, privkey, NULL))
> goto done;
>
> - ret = ec_point2raw(group, secretp, secret, ec_getlen(group));
> + ret = ec_point2raw(group, secretp, secret, ec_secretlen(group),
> + EC_POINT2RAW_XONLY);
>
> done:
> if (exkey != NULL)
> @@ -511,7 +539,7 @@ ec_create_shared(struct group *group, uint8_t *secret,
> uint8_t *exchange)
>
> int
> ec_point2raw(struct group *group, const EC_POINT *point,
> - uint8_t *buf, size_t len)
> + uint8_t *buf, size_t len, int mode)
> {
> const EC_GROUP *ecgroup = NULL;
> BN_CTX *bnctx = NULL;
> @@ -528,9 +556,19 @@ ec_point2raw(struct group *group, const EC_POINT *point,
> goto done;
>
> eclen = ec_getlen(group);
> - if (len < eclen)
> + switch (mode) {
> + case EC_POINT2RAW_XONLY:
> + xlen = eclen / 2;
> + ylen = 0;
> + break;
> + case EC_POINT2RAW_FULL:
> + xlen = ylen = eclen / 2;
> + break;
> + default:
> + goto done;
> + }
> + if (len < xlen + ylen)
> goto done;
> - xlen = ylen = eclen / 2;
>
> if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL)
> goto done;
> @@ -551,10 +589,12 @@ ec_point2raw(struct group *group, const EC_POINT *point,
> if (!BN_bn2bin(x, buf + xoff))
> goto done;
>
> - yoff = (ylen - BN_num_bytes(y)) + xlen;
> - bzero(buf + xlen, yoff - xlen);
> - if (!BN_bn2bin(y, buf + yoff))
> - goto done;
> + if (ylen > 0) {
> + yoff = (ylen - BN_num_bytes(y)) + xlen;
> + bzero(buf + xlen, yoff - xlen);
> + if (!BN_bn2bin(y, buf + yoff))
> + goto done;
> + }
>
> ret = 0;
> done:
> diff --git a/sbin/iked/dh.h b/sbin/iked/dh.h
> index 77bb4b5ef16..7e24d4d6746 100644
> --- a/sbin/iked/dh.h
> +++ b/sbin/iked/dh.h
> @@ -46,6 +46,7 @@ struct group {
>
> int (*init)(struct group *);
> int (*getlen)(struct group *);
> + int (*secretlen)(struct group *);
> int (*exchange)(struct group *, uint8_t *);
> int (*shared)(struct group *, uint8_t *, uint8_t *);
> };
> @@ -59,6 +60,7 @@ const struct group_id
> *group_getid(uint32_t);
>
> int dh_getlen(struct group *);
> +int dh_secretlen(struct group *);
> int dh_create_exchange(struct group *, uint8_t *);
> int dh_create_shared(struct group *, uint8_t *, uint8_t *);
>
> diff --git a/sbin/iked/ikev2.c b/sbin/iked/ikev2.c
> index 045e499aaed..3b054d5c994 100644
> --- a/sbin/iked/ikev2.c
> +++ b/sbin/iked/ikev2.c
> @@ -4290,19 +4290,24 @@ ikev2_sa_keys(struct iked *env, struct iked_sa *sa,
> struct ibuf *key)
> /*
> * Generate g^ir
> */
> - if ((dhsecret = ibuf_new(NULL, dh_getlen(group))) == NULL) {
> + if ((dhsecret = ibuf_new(NULL, dh_secretlen(group))) == NULL) {
> log_debug("%s: failed to alloc dh secret", __func__);
> goto done;
> }
> if (dh_create_shared(group, dhsecret->buf,
> sa->sa_dhpeer->buf) == -1) {
> log_debug("%s: failed to get dh secret"
> - " group %d len %d secret %zu exchange %zu", __func__,
> - group->id, dh_getlen(group), ibuf_length(dhsecret),
> - ibuf_length(sa->sa_dhpeer));
> + " group %d len %d secretlen %d secret %zu exchange %zu",
> + __func__,
> + group->id, dh_getlen(group), dh_secretlen(group),
> + ibuf_length(dhsecret), ibuf_length(sa->sa_dhpeer));
> goto done;
> }
>
> + log_debug("%s: DHSECRET with %zu bytes", __func__,
> + ibuf_length(dhsecret));
> + print_hex(dhsecret->buf, 0, ibuf_length(dhsecret));
> +
> if (!key) {
> /*
> * Set PRF key to generate SKEEYSEED = prf(Ni | Nr, g^ir)
> @@ -4725,15 +4730,16 @@ ikev2_childsa_negotiate(struct iked *env, struct
> iked_sa *sa,
> log_debug("%s: no dh group for pfs", __func__);
> goto done;
> }
> - if ((dhsecret = ibuf_new(NULL, dh_getlen(group))) == NULL) {
> + if ((dhsecret = ibuf_new(NULL, dh_secretlen(group))) == NULL)
> {
> log_debug("%s: failed to alloc dh secret", __func__);
> goto done;
> }
> if (dh_create_shared(group, dhsecret->buf,
> kex->kex_dhpeer->buf) == -1) {
> log_debug("%s: failed to get dh secret"
> - " group %d len %d secret %zu exchange %zu",
> - __func__, group->id, dh_getlen(group),
> + " group %d len %d secretlen %d secret %zu"
> + " exchange %zu", __func__, group->id,
> + dh_getlen(group), dh_secretlen(group),
> ibuf_length(dhsecret),
> ibuf_length(kex->kex_dhpeer));
> goto done;
>