259 lines
8.8 KiB
Diff
259 lines
8.8 KiB
Diff
|
|
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: 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>
|
||
|
|
backport addr https://w1.fi/cgit/hostap/patch/?id=16d4f1069118aa19bfce013493e1ac5783f92f1d
|
||
|
|
https://w1.fi/cgit/hostap/patch/?id=70ff850e89fbc8bc7da515321b4d15b5eef70581
|
||
|
|
https://w1.fi/cgit/hostap/patch/?id=8ad8585f91823ddcc3728155e288e0f9f872e31a
|
||
|
|
---
|
||
|
|
src/eap_common/eap_pwd_common.c | 106 ++++++++++++++++++++++++++++++++
|
||
|
|
src/eap_common/eap_pwd_common.h | 3 +
|
||
|
|
src/eap_peer/eap_pwd.c | 19 +-----
|
||
|
|
src/eap_server/eap_server_pwd.c | 19 +-----
|
||
|
|
4 files changed, 111 insertions(+), 36 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
|
||
|
|
index 67f8f70..ef47db1 100644
|
||
|
|
--- a/src/eap_common/eap_pwd_common.c
|
||
|
|
+++ b/src/eap_common/eap_pwd_common.c
|
||
|
|
@@ -365,3 +365,109 @@ int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const 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 a0d717e..01f43eb 100644
|
||
|
|
--- a/src/eap_common/eap_pwd_common.h
|
||
|
|
+++ b/src/eap_common/eap_pwd_common.h
|
||
|
|
@@ -68,5 +68,8 @@ int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const 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 d2bc981..bbe9b40 100644
|
||
|
|
--- a/src/eap_peer/eap_pwd.c
|
||
|
|
+++ b/src/eap_peer/eap_pwd.c
|
||
|
|
@@ -358,7 +358,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)
|
||
|
|
{
|
||
|
|
- EC_POINT *K = NULL, *point = NULL;
|
||
|
|
+ EC_POINT *K = NULL;
|
||
|
|
BIGNUM *mask = NULL, *x = NULL, *y = NULL, *cofactor = NULL;
|
||
|
|
u16 offset;
|
||
|
|
u8 *ptr, *scalar = NULL, *element = NULL;
|
||
|
|
@@ -429,7 +429,6 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
|
||
|
|
if (((data->server_scalar = BN_new()) == NULL) ||
|
||
|
|
((data->k = BN_new()) == NULL) ||
|
||
|
|
((K = EC_POINT_new(data->grp->group)) == NULL) ||
|
||
|
|
- ((point = EC_POINT_new(data->grp->group)) == NULL) ||
|
||
|
|
((data->server_element = EC_POINT_new(data->grp->group)) == NULL))
|
||
|
|
{
|
||
|
|
wpa_printf(MSG_INFO, "EAP-PWD (peer): peer data allocation "
|
||
|
|
@@ -452,21 +451,6 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
|
||
|
|
goto fin;
|
||
|
|
}
|
||
|
|
|
||
|
|
- /* check to ensure server's element is not in a small sub-group */
|
||
|
|
- if (BN_cmp(cofactor, BN_value_one())) {
|
||
|
|
- if (!EC_POINT_mul(data->grp->group, point, NULL,
|
||
|
|
- data->server_element, cofactor, NULL)) {
|
||
|
|
- wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply "
|
||
|
|
- "server element by order!\n");
|
||
|
|
- goto fin;
|
||
|
|
- }
|
||
|
|
- if (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 ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe,
|
||
|
|
data->server_scalar, data->bnctx)) ||
|
||
|
|
@@ -557,7 +541,6 @@ fin:
|
||
|
|
BN_clear_free(mask);
|
||
|
|
BN_clear_free(cofactor);
|
||
|
|
EC_POINT_clear_free(K);
|
||
|
|
- EC_POINT_clear_free(point);
|
||
|
|
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 cb5f682..275bdf8 100644
|
||
|
|
--- a/src/eap_server/eap_server_pwd.c
|
||
|
|
+++ b/src/eap_server/eap_server_pwd.c
|
||
|
|
@@ -659,7 +659,7 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
|
||
|
|
{
|
||
|
|
u8 *ptr;
|
||
|
|
BIGNUM *x = NULL, *y = NULL, *cofactor = NULL;
|
||
|
|
- EC_POINT *K = NULL, *point = NULL;
|
||
|
|
+ EC_POINT *K = NULL;
|
||
|
|
int res = 0;
|
||
|
|
size_t prime_len, order_len;
|
||
|
|
|
||
|
|
@@ -681,7 +681,6 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
|
||
|
|
((cofactor = BN_new()) == NULL) ||
|
||
|
|
((x = BN_new()) == NULL) ||
|
||
|
|
((y = BN_new()) == NULL) ||
|
||
|
|
- ((point = EC_POINT_new(data->grp->group)) == NULL) ||
|
||
|
|
((K = EC_POINT_new(data->grp->group)) == NULL) ||
|
||
|
|
((data->peer_element = EC_POINT_new(data->grp->group)) == NULL)) {
|
||
|
|
wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation "
|
||
|
|
@@ -710,21 +709,6 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
|
||
|
|
goto fin;
|
||
|
|
}
|
||
|
|
|
||
|
|
- /* check to ensure peer's element is not in a small sub-group */
|
||
|
|
- if (BN_cmp(cofactor, BN_value_one())) {
|
||
|
|
- if (!EC_POINT_mul(data->grp->group, point, NULL,
|
||
|
|
- data->peer_element, cofactor, NULL)) {
|
||
|
|
- wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
|
||
|
|
- "multiply peer element by order");
|
||
|
|
- goto fin;
|
||
|
|
- }
|
||
|
|
- if (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,
|
||
|
|
@@ -777,7 +761,6 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
|
||
|
|
|
||
|
|
fin:
|
||
|
|
EC_POINT_clear_free(K);
|
||
|
|
- EC_POINT_clear_free(point);
|
||
|
|
BN_clear_free(cofactor);
|
||
|
|
BN_clear_free(x);
|
||
|
|
BN_clear_free(y);
|
||
|
|
--
|
||
|
|
2.19.1
|
||
|
|
|