diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c index e49aaf8c7..c28b56d62 100644 --- a/src/eap_common/eap_pwd_common.c +++ b/src/eap_common/eap_pwd_common.c @@ -428,3 +428,109 @@ int compute_keys(EAP_PWD_group *grp, const struct crypto_bignum *k, return 1; } + + +static int eap_pwd_element_coord_ok(const struct crypto_bignum *prime, + const u8 *buf, size_t len) +{ + struct crypto_bignum *val; + int ok = 1; + + val = crypto_bignum_init_set(buf, len); + if (!val || crypto_bignum_is_zero(val) || + crypto_bignum_cmp(val, prime) >= 0) + ok = 0; + crypto_bignum_deinit(val, 0); + return ok; +} + + +struct crypto_ec_point * eap_pwd_get_element(EAP_PWD_group *group, + const u8 *buf) +{ + struct crypto_ec_point *element; + const struct crypto_bignum *prime; + size_t prime_len; + struct crypto_bignum *cofactor = NULL; + + prime = crypto_ec_get_prime(group->group); + prime_len = crypto_ec_prime_len(group->group); + + /* RFC 5931, 2.8.5.2.2: 0 < x,y < p */ + if (!eap_pwd_element_coord_ok(prime, buf, prime_len) || + !eap_pwd_element_coord_ok(prime, buf + prime_len, prime_len)) { + wpa_printf(MSG_INFO, "EAP-pwd: Invalid coordinate in element"); + return NULL; + } + + element = crypto_ec_point_from_bin(group->group, buf); + if (!element) { + wpa_printf(MSG_INFO, "EAP-pwd: EC point from element failed"); + return NULL; + } + + /* RFC 5931, 2.8.5.2.2: on curve and not the point at infinity */ + if (!crypto_ec_point_is_on_curve(group->group, element) || + crypto_ec_point_is_at_infinity(group->group, element)) { + wpa_printf(MSG_INFO, "EAP-pwd: Invalid element"); + goto fail; + } + + cofactor = crypto_bignum_init(); + if (!cofactor || crypto_ec_cofactor(group->group, cofactor) < 0) { + wpa_printf(MSG_INFO, + "EAP-pwd: Unable to get cofactor for curve"); + goto fail; + } + + if (!crypto_bignum_is_one(cofactor)) { + struct crypto_ec_point *point; + int ok = 1; + + /* check to ensure peer's element is not in a small sub-group */ + point = crypto_ec_point_init(group->group); + if (!point || + crypto_ec_point_mul(group->group, element, + cofactor, point) != 0 || + crypto_ec_point_is_at_infinity(group->group, point)) + ok = 0; + crypto_ec_point_deinit(point, 0); + + if (!ok) { + wpa_printf(MSG_INFO, + "EAP-pwd: Small sub-group check on peer element failed"); + goto fail; + } + } + +out: + crypto_bignum_deinit(cofactor, 0); + return element; +fail: + crypto_ec_point_deinit(element, 0); + element = NULL; + goto out; +} + + +struct crypto_bignum * eap_pwd_get_scalar(EAP_PWD_group *group, const u8 *buf) +{ + struct crypto_bignum *scalar; + const struct crypto_bignum *order; + size_t order_len; + + order = crypto_ec_get_order(group->group); + order_len = crypto_ec_order_len(group->group); + + /* RFC 5931, 2.8.5.2: 1 < scalar < r */ + scalar = crypto_bignum_init_set(buf, order_len); + if (!scalar || crypto_bignum_is_zero(scalar) || + crypto_bignum_is_one(scalar) || + crypto_bignum_cmp(scalar, order) >= 0) { + wpa_printf(MSG_INFO, "EAP-pwd: received scalar is invalid"); + crypto_bignum_deinit(scalar, 0); + scalar = NULL; + } + + return scalar; +} diff --git a/src/eap_common/eap_pwd_common.h b/src/eap_common/eap_pwd_common.h index 6b07cf8f7..2387e59a2 100644 --- a/src/eap_common/eap_pwd_common.h +++ b/src/eap_common/eap_pwd_common.h @@ -67,5 +67,8 @@ int compute_keys(EAP_PWD_group *grp, const struct crypto_bignum *k, struct crypto_hash * eap_pwd_h_init(void); void eap_pwd_h_update(struct crypto_hash *hash, const u8 *data, size_t len); void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest); +struct crypto_ec_point * eap_pwd_get_element(EAP_PWD_group *group, + const u8 *buf); +struct crypto_bignum * eap_pwd_get_scalar(EAP_PWD_group *group, const u8 *buf); #endif /* EAP_PWD_COMMON_H */ diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c index 5a05e5432..f37b974eb 100644 --- a/src/eap_peer/eap_pwd.c +++ b/src/eap_peer/eap_pwd.c @@ -308,7 +308,7 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data, const struct wpabuf *reqData, const u8 *payload, size_t payload_len) { - struct crypto_ec_point *K = NULL, *point = NULL; + struct crypto_ec_point *K = NULL; struct crypto_bignum *mask = NULL, *cofactor = NULL; const u8 *ptr = payload; u8 *scalar = NULL, *element = NULL; @@ -572,63 +572,27 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data, /* process the request */ data->k = crypto_bignum_init(); K = crypto_ec_point_init(data->grp->group); - point = crypto_ec_point_init(data->grp->group); - if (!data->k || !K || !point) { + if (!data->k || !K) { wpa_printf(MSG_INFO, "EAP-PWD (peer): peer data allocation " "fail"); goto fin; } /* element, x then y, followed by scalar */ - data->server_element = crypto_ec_point_from_bin(data->grp->group, ptr); + data->server_element = eap_pwd_get_element(data->grp, ptr); if (!data->server_element) { wpa_printf(MSG_INFO, "EAP-PWD (peer): setting peer element " "fail"); goto fin; } ptr += prime_len * 2; - data->server_scalar = crypto_bignum_init_set(ptr, order_len); + data->server_scalar = eap_pwd_get_scalar(data->grp, ptr); if (!data->server_scalar) { wpa_printf(MSG_INFO, "EAP-PWD (peer): setting peer scalar fail"); goto fin; } - /* verify received scalar */ - if (crypto_bignum_is_zero(data->server_scalar) || - crypto_bignum_is_one(data->server_scalar) || - crypto_bignum_cmp(data->server_scalar, - crypto_ec_get_order(data->grp->group)) >= 0) { - wpa_printf(MSG_INFO, - "EAP-PWD (peer): received scalar is invalid"); - goto fin; - } - - /* verify received element */ - if (!crypto_ec_point_is_on_curve(data->grp->group, - data->server_element) || - crypto_ec_point_is_at_infinity(data->grp->group, - data->server_element)) { - wpa_printf(MSG_INFO, - "EAP-PWD (peer): received element is invalid"); - goto fin; - } - - /* check to ensure server's element is not in a small sub-group */ - if (!crypto_bignum_is_one(cofactor)) { - if (crypto_ec_point_mul(data->grp->group, data->server_element, - cofactor, point) < 0) { - wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply " - "server element by order!\n"); - goto fin; - } - if (crypto_ec_point_is_at_infinity(data->grp->group, point)) { - wpa_printf(MSG_INFO, "EAP-PWD (peer): server element " - "is at infinity!\n"); - goto fin; - } - } - /* compute the shared key, k */ if (crypto_ec_point_mul(data->grp->group, data->grp->pwe, data->server_scalar, K) < 0 || @@ -702,7 +666,6 @@ fin: crypto_bignum_deinit(mask, 1); crypto_bignum_deinit(cofactor, 1); crypto_ec_point_deinit(K, 1); - crypto_ec_point_deinit(point, 1); if (data->outbuf == NULL) eap_pwd_state(data, FAILURE); else diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c index 16057e94f..f6c75cf80 100644 --- a/src/eap_server/eap_server_pwd.c +++ b/src/eap_server/eap_server_pwd.c @@ -669,7 +669,7 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data, { const u8 *ptr; struct crypto_bignum *cofactor = NULL; - struct crypto_ec_point *K = NULL, *point = NULL; + struct crypto_ec_point *K = NULL; int res = 0; size_t prime_len, order_len; @@ -688,9 +688,8 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data, data->k = crypto_bignum_init(); cofactor = crypto_bignum_init(); - point = crypto_ec_point_init(data->grp->group); K = crypto_ec_point_init(data->grp->group); - if (!data->k || !cofactor || !point || !K) { + if (!data->k || !cofactor || !K) { wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation " "fail"); goto fin; @@ -704,55 +703,20 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data, /* element, x then y, followed by scalar */ ptr = payload; - data->peer_element = crypto_ec_point_from_bin(data->grp->group, ptr); + data->peer_element = eap_pwd_get_element(data->grp, ptr); if (!data->peer_element) { wpa_printf(MSG_INFO, "EAP-PWD (server): setting peer element " "fail"); goto fin; } ptr += prime_len * 2; - data->peer_scalar = crypto_bignum_init_set(ptr, order_len); + data->peer_scalar = eap_pwd_get_scalar(data->grp, ptr); if (!data->peer_scalar) { wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation " "fail"); goto fin; } - /* verify received scalar */ - if (crypto_bignum_is_zero(data->peer_scalar) || - crypto_bignum_is_one(data->peer_scalar) || - crypto_bignum_cmp(data->peer_scalar, - crypto_ec_get_order(data->grp->group)) >= 0) { - wpa_printf(MSG_INFO, - "EAP-PWD (server): received scalar is invalid"); - goto fin; - } - - /* verify received element */ - if (!crypto_ec_point_is_on_curve(data->grp->group, - data->peer_element) || - crypto_ec_point_is_at_infinity(data->grp->group, - data->peer_element)) { - wpa_printf(MSG_INFO, - "EAP-PWD (server): received element is invalid"); - goto fin; - } - - /* check to ensure peer's element is not in a small sub-group */ - if (!crypto_bignum_is_one(cofactor)) { - if (crypto_ec_point_mul(data->grp->group, data->peer_element, - cofactor, point) != 0) { - wpa_printf(MSG_INFO, "EAP-PWD (server): cannot " - "multiply peer element by order"); - goto fin; - } - if (crypto_ec_point_is_at_infinity(data->grp->group, point)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): peer element " - "is at infinity!\n"); - goto fin; - } - } - /* detect reflection attacks */ if (crypto_bignum_cmp(data->my_scalar, data->peer_scalar) == 0 || crypto_ec_point_cmp(data->grp->group, data->my_element, @@ -804,7 +768,6 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data, fin: crypto_ec_point_deinit(K, 1); - crypto_ec_point_deinit(point, 1); crypto_bignum_deinit(cofactor, 1); if (res)