123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331 |
- From 16d4f1069118aa19bfce013493e1ac5783f92f1d Mon Sep 17 00:00:00 2001
- From: Jouni Malinen <jouni@codeaurora.org>
- Date: Fri, 5 Apr 2019 02:12:50 +0300
- Subject: [PATCH 14/14] EAP-pwd: Check element x,y coordinates explicitly
- This adds an explicit check for 0 < x,y < prime based on RFC 5931,
- 2.8.5.2.2 requirement. The earlier checks might have covered this
- implicitly, but it is safer to avoid any dependency on implicit checks
- and specific crypto library behavior. (CVE-2019-9498 and CVE-2019-9499)
- Furthermore, this moves the EAP-pwd element and scalar parsing and
- validation steps into shared helper functions so that there is no need
- to maintain two separate copies of this common functionality between the
- server and peer implementations.
- Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
- ---
- src/eap_common/eap_pwd_common.c | 106 ++++++++++++++++++++++++++++++++++++++++
- src/eap_common/eap_pwd_common.h | 3 ++
- src/eap_peer/eap_pwd.c | 45 ++---------------
- src/eap_server/eap_server_pwd.c | 45 ++---------------
- 4 files changed, 117 insertions(+), 82 deletions(-)
- diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
- index e49aaf8..c28b56d 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 6b07cf8..2387e59 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 5a05e54..f37b974 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 16057e9..f6c75cf 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)
- --
- 2.7.4
|