diff --git a/CVE-2019-9495-pre1.patch b/CVE-2019-9495-pre1.patch new file mode 100644 index 0000000000000000000000000000000000000000..6d08673259bdb38f3dab54ba7a0f2ecf583cfddb --- /dev/null +++ b/CVE-2019-9495-pre1.patch @@ -0,0 +1,1501 @@ +diff -Nur orig-wpa_supplicant-2.6/src/eap_common/eap_pwd_common.c wpa_supplicant-2.6/src/eap_common/eap_pwd_common.c +--- orig-wpa_supplicant-2.6/src/eap_common/eap_pwd_common.c 2020-02-03 20:08:29.435861644 +0800 ++++ wpa_supplicant-2.6/src/eap_common/eap_pwd_common.c 2020-02-03 21:55:58.180291376 +0800 +@@ -91,91 +91,33 @@ + const u8 *id_peer, size_t id_peer_len, + const u8 *token) + { +- BIGNUM *x_candidate = NULL, *rnd = NULL, *cofactor = NULL; + struct crypto_hash *hash; + unsigned char pwe_digest[SHA256_MAC_LEN], *prfbuf = NULL, ctr; +- int nid, is_odd, ret = 0; ++ int is_odd, ret = 0; + size_t primebytelen, primebitlen; +- +- switch (num) { /* from IANA registry for IKE D-H groups */ +- case 19: +- nid = NID_X9_62_prime256v1; +- break; +- case 20: +- nid = NID_secp384r1; +- break; +- case 21: +- nid = NID_secp521r1; +- break; +-#ifndef OPENSSL_IS_BORINGSSL +- case 25: +- nid = NID_X9_62_prime192v1; +- break; +-#endif /* OPENSSL_IS_BORINGSSL */ +- case 26: +- nid = NID_secp224r1; +- break; +-#ifdef NID_brainpoolP224r1 +- case 27: +- nid = NID_brainpoolP224r1; +- break; +-#endif /* NID_brainpoolP224r1 */ +-#ifdef NID_brainpoolP256r1 +- case 28: +- nid = NID_brainpoolP256r1; +- break; +-#endif /* NID_brainpoolP256r1 */ +-#ifdef NID_brainpoolP384r1 +- case 29: +- nid = NID_brainpoolP384r1; +- break; +-#endif /* NID_brainpoolP384r1 */ +-#ifdef NID_brainpoolP512r1 +- case 30: +- nid = NID_brainpoolP512r1; +- break; +-#endif /* NID_brainpoolP512r1 */ +- default: +- wpa_printf(MSG_INFO, "EAP-pwd: unsupported group %d", num); +- return -1; +- } ++ struct crypto_bignum *x_candidate = NULL, *rnd = NULL, *cofactor = NULL; + + grp->pwe = NULL; +- grp->order = NULL; +- grp->prime = NULL; +- +- if ((grp->group = EC_GROUP_new_by_curve_name(nid)) == NULL) { +- wpa_printf(MSG_INFO, "EAP-pwd: unable to create EC_GROUP"); ++ grp->group = crypto_ec_init(num); ++ if (!grp->group) { ++ wpa_printf(MSG_INFO, "EAP-pwd: unable to create EC group"); + goto fail; + } + +- if (((rnd = BN_new()) == NULL) || +- ((cofactor = BN_new()) == NULL) || +- ((grp->pwe = EC_POINT_new(grp->group)) == NULL) || +- ((grp->order = BN_new()) == NULL) || +- ((grp->prime = BN_new()) == NULL) || +- ((x_candidate = BN_new()) == NULL)) { ++ cofactor = crypto_bignum_init(); ++ grp->pwe = crypto_ec_point_init(grp->group); ++ if (!cofactor || !grp->pwe) { + wpa_printf(MSG_INFO, "EAP-pwd: unable to create bignums"); + goto fail; + } + +- if (!EC_GROUP_get_curve_GFp(grp->group, grp->prime, NULL, NULL, NULL)) +- { +- wpa_printf(MSG_INFO, "EAP-pwd: unable to get prime for GFp " +- "curve"); +- goto fail; +- } +- if (!EC_GROUP_get_order(grp->group, grp->order, NULL)) { +- wpa_printf(MSG_INFO, "EAP-pwd: unable to get order for curve"); +- goto fail; +- } +- if (!EC_GROUP_get_cofactor(grp->group, cofactor, NULL)) { ++ if (crypto_ec_cofactor(grp->group, cofactor) < 0) { + wpa_printf(MSG_INFO, "EAP-pwd: unable to get cofactor for " + "curve"); + goto fail; + } +- primebitlen = BN_num_bits(grp->prime); +- primebytelen = BN_num_bytes(grp->prime); ++ primebitlen = crypto_ec_prime_len_bits(grp->group); ++ primebytelen = crypto_ec_prime_len(grp->group); + if ((prfbuf = os_malloc(primebytelen)) == NULL) { + wpa_printf(MSG_INFO, "EAP-pwd: unable to malloc space for prf " + "buffer"); +@@ -207,15 +149,25 @@ + eap_pwd_h_update(hash, &ctr, sizeof(ctr)); + eap_pwd_h_final(hash, pwe_digest); + +- BN_bin2bn(pwe_digest, SHA256_MAC_LEN, rnd); +- ++ crypto_bignum_deinit(rnd, 1); ++ rnd = crypto_bignum_init_set(pwe_digest, SHA256_MAC_LEN); ++ if (!rnd) { ++ wpa_printf(MSG_INFO, "EAP-pwd: unable to create rnd"); ++ goto fail; ++ } + if (eap_pwd_kdf(pwe_digest, SHA256_MAC_LEN, + (u8 *) "EAP-pwd Hunting And Pecking", + os_strlen("EAP-pwd Hunting And Pecking"), + prfbuf, primebitlen) < 0) + goto fail; + +- BN_bin2bn(prfbuf, primebytelen, x_candidate); ++ crypto_bignum_deinit(x_candidate, 1); ++ x_candidate = crypto_bignum_init_set(prfbuf, primebytelen); ++ if (!x_candidate) { ++ wpa_printf(MSG_INFO, ++ "EAP-pwd: unable to create x_candidate"); ++ goto fail; ++ } + + /* + * eap_pwd_kdf() returns a string of bits 0..primebitlen but +@@ -224,11 +176,14 @@ + * then excessive bits-- those _after_ primebitlen-- so now + * we have to shift right the amount we masked off. + */ +- if (primebitlen % 8) +- BN_rshift(x_candidate, x_candidate, +- (8 - (primebitlen % 8))); ++ if ((primebitlen % 8) && ++ crypto_bignum_rshift(x_candidate, ++ (8 - (primebitlen % 8)), ++ x_candidate) < 0) ++ goto fail; + +- if (BN_ucmp(x_candidate, grp->prime) >= 0) ++ if (crypto_bignum_cmp(x_candidate, ++ crypto_ec_get_prime(grp->group)) >= 0) + continue; + + wpa_hexdump(MSG_DEBUG, "EAP-pwd: x_candidate", +@@ -238,40 +193,38 @@ + * need to unambiguously identify the solution, if there is + * one... + */ +- if (BN_is_odd(rnd)) +- is_odd = 1; +- else +- is_odd = 0; ++ is_odd = crypto_bignum_is_odd(rnd); + + /* + * solve the quadratic equation, if it's not solvable then we + * don't have a point + */ +- if (!EC_POINT_set_compressed_coordinates_GFp(grp->group, +- grp->pwe, +- x_candidate, +- is_odd, NULL)) ++ if (crypto_ec_point_solve_y_coord(grp->group, grp->pwe, ++ x_candidate, is_odd) != 0) { ++ wpa_printf(MSG_INFO, "EAP-pwd: Could not solve for y"); + continue; ++ } + /* + * If there's a solution to the equation then the point must be + * on the curve so why check again explicitly? OpenSSL code + * says this is required by X9.62. We're not X9.62 but it can't + * hurt just to be sure. + */ +- if (!EC_POINT_is_on_curve(grp->group, grp->pwe, NULL)) { ++ if (!crypto_ec_point_is_on_curve(grp->group, grp->pwe)) { + wpa_printf(MSG_INFO, "EAP-pwd: point is not on curve"); + continue; + } + +- if (BN_cmp(cofactor, BN_value_one())) { ++ if (!crypto_bignum_is_one(cofactor)) { + /* make sure the point is not in a small sub-group */ +- if (!EC_POINT_mul(grp->group, grp->pwe, NULL, grp->pwe, +- cofactor, NULL)) { ++ if (crypto_ec_point_mul(grp->group, grp->pwe, ++ cofactor, grp->pwe) != 0) { + wpa_printf(MSG_INFO, "EAP-pwd: cannot " + "multiply generator by order"); + continue; + } +- if (EC_POINT_is_at_infinity(grp->group, grp->pwe)) { ++ if (crypto_ec_point_is_at_infinity(grp->group, ++ grp->pwe)) { + wpa_printf(MSG_INFO, "EAP-pwd: point is at " + "infinity"); + continue; +@@ -284,37 +237,38 @@ + grp->group_num = num; + if (0) { + fail: +- EC_GROUP_free(grp->group); ++ crypto_ec_deinit(grp->group); + grp->group = NULL; +- EC_POINT_clear_free(grp->pwe); ++ crypto_ec_point_deinit(grp->pwe, 1); + grp->pwe = NULL; +- BN_clear_free(grp->order); +- grp->order = NULL; +- BN_clear_free(grp->prime); +- grp->prime = NULL; + ret = 1; + } + /* cleanliness and order.... */ +- BN_clear_free(cofactor); +- BN_clear_free(x_candidate); +- BN_clear_free(rnd); ++ crypto_bignum_deinit(cofactor, 1); ++ crypto_bignum_deinit(x_candidate, 1); ++ crypto_bignum_deinit(rnd, 1); + os_free(prfbuf); + + return ret; + } + + +-int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const BIGNUM *k, +- const BIGNUM *peer_scalar, const BIGNUM *server_scalar, ++int compute_keys(EAP_PWD_group *grp, const struct crypto_bignum *k, ++ const struct crypto_bignum *peer_scalar, ++ const struct crypto_bignum *server_scalar, + const u8 *confirm_peer, const u8 *confirm_server, + const u32 *ciphersuite, u8 *msk, u8 *emsk, u8 *session_id) + { + struct crypto_hash *hash; + u8 mk[SHA256_MAC_LEN], *cruft; + u8 msk_emsk[EAP_MSK_LEN + EAP_EMSK_LEN]; +- int offset; ++ size_t prime_len, order_len; ++ ++ prime_len = crypto_ec_prime_len(grp->group); ++ order_len = crypto_ec_order_len(grp->group); + +- if ((cruft = os_malloc(BN_num_bytes(grp->prime))) == NULL) ++ cruft = os_malloc(prime_len); ++ if (!cruft) + return -1; + + /* +@@ -328,14 +282,10 @@ + return -1; + } + eap_pwd_h_update(hash, (const u8 *) ciphersuite, sizeof(u32)); +- offset = BN_num_bytes(grp->order) - BN_num_bytes(peer_scalar); +- os_memset(cruft, 0, BN_num_bytes(grp->prime)); +- BN_bn2bin(peer_scalar, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->order)); +- offset = BN_num_bytes(grp->order) - BN_num_bytes(server_scalar); +- os_memset(cruft, 0, BN_num_bytes(grp->prime)); +- BN_bn2bin(server_scalar, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->order)); ++ crypto_bignum_to_bin(peer_scalar, cruft, order_len, order_len); ++ eap_pwd_h_update(hash, cruft, order_len); ++ crypto_bignum_to_bin(server_scalar, cruft, order_len, order_len); ++ eap_pwd_h_update(hash, cruft, order_len); + eap_pwd_h_final(hash, &session_id[1]); + + /* then compute MK = H(k | confirm-peer | confirm-server) */ +@@ -344,10 +294,8 @@ + os_free(cruft); + return -1; + } +- offset = BN_num_bytes(grp->prime) - BN_num_bytes(k); +- os_memset(cruft, 0, BN_num_bytes(grp->prime)); +- BN_bn2bin(k, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->prime)); ++ crypto_bignum_to_bin(k, cruft, prime_len, prime_len); ++ eap_pwd_h_update(hash, cruft, prime_len); + os_free(cruft); + eap_pwd_h_update(hash, confirm_peer, SHA256_MAC_LEN); + eap_pwd_h_update(hash, confirm_server, SHA256_MAC_LEN); +diff -Nur orig-wpa_supplicant-2.6/src/eap_common/eap_pwd_common.h wpa_supplicant-2.6/src/eap_common/eap_pwd_common.h +--- orig-wpa_supplicant-2.6/src/eap_common/eap_pwd_common.h 2020-02-03 20:08:29.435861644 +0800 ++++ wpa_supplicant-2.6/src/eap_common/eap_pwd_common.h 2020-02-03 21:59:06.462756520 +0800 +@@ -9,20 +9,14 @@ + #ifndef EAP_PWD_COMMON_H + #define EAP_PWD_COMMON_H + +-#include +-#include +-#include +- + /* + * definition of a finite cyclic group + * TODO: support one based on a prime field + */ + typedef struct group_definition_ { + u16 group_num; +- EC_GROUP *group; +- EC_POINT *pwe; +- BIGNUM *order; +- BIGNUM *prime; ++ struct crypto_ec *group; ++ struct crypto_ec_point *pwe; + } EAP_PWD_group; + + /* +@@ -61,8 +55,9 @@ + const u8 *id_server, size_t id_server_len, + const u8 *id_peer, size_t id_peer_len, + const u8 *token); +-int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const BIGNUM *k, +- const BIGNUM *peer_scalar, const BIGNUM *server_scalar, ++int compute_keys(EAP_PWD_group *grp, const struct crypto_bignum *k, ++ const struct crypto_bignum *peer_scalar, ++ const struct crypto_bignum *server_scalar, + const u8 *confirm_peer, const u8 *confirm_server, + const u32 *ciphersuite, u8 *msk, u8 *emsk, u8 *session_id); + struct crypto_hash * eap_pwd_h_init(void); +diff -Nur orig-wpa_supplicant-2.6/src/eap_peer/eap_pwd.c wpa_supplicant-2.6/src/eap_peer/eap_pwd.c +--- orig-wpa_supplicant-2.6/src/eap_peer/eap_pwd.c 2020-02-03 20:08:29.435861644 +0800 ++++ wpa_supplicant-2.6/src/eap_peer/eap_pwd.c 2020-02-03 22:52:49.695035831 +0800 +@@ -11,6 +11,7 @@ + #include "common.h" + #include "crypto/sha256.h" + #include "crypto/ms_funcs.h" ++#include "crypto/crypto.h" + #include "eap_peer/eap_i.h" + #include "eap_common/eap_pwd_common.h" + +@@ -36,18 +37,16 @@ + size_t out_frag_pos; + size_t mtu; + +- BIGNUM *k; +- BIGNUM *private_value; +- BIGNUM *server_scalar; +- BIGNUM *my_scalar; +- EC_POINT *my_element; +- EC_POINT *server_element; ++ struct crypto_bignum *k; ++ struct crypto_bignum *private_value; ++ struct crypto_bignum *server_scalar; ++ struct crypto_bignum *my_scalar; ++ struct crypto_ec_point *my_element; ++ struct crypto_ec_point *server_element; + + u8 msk[EAP_MSK_LEN]; + u8 emsk[EAP_EMSK_LEN]; + u8 session_id[1 + SHA256_MAC_LEN]; +- +- BN_CTX *bnctx; + }; + + +@@ -107,15 +106,8 @@ + return NULL; + } + +- if ((data->bnctx = BN_CTX_new()) == NULL) { +- wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail"); +- os_free(data); +- return NULL; +- } +- + if ((data->id_peer = os_malloc(identity_len)) == NULL) { + wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail"); +- BN_CTX_free(data->bnctx); + os_free(data); + return NULL; + } +@@ -125,7 +117,6 @@ + + if ((data->password = os_malloc(password_len)) == NULL) { + wpa_printf(MSG_INFO, "EAP-PWD: memory allocation psk fail"); +- BN_CTX_free(data->bnctx); + bin_clear_free(data->id_peer, data->id_peer_len); + os_free(data); + return NULL; +@@ -152,21 +143,18 @@ + { + struct eap_pwd_data *data = priv; + +- BN_clear_free(data->private_value); +- BN_clear_free(data->server_scalar); +- BN_clear_free(data->my_scalar); +- BN_clear_free(data->k); +- BN_CTX_free(data->bnctx); +- EC_POINT_clear_free(data->my_element); +- EC_POINT_clear_free(data->server_element); ++ crypto_bignum_deinit(data->private_value, 1); ++ crypto_bignum_deinit(data->server_scalar, 1); ++ crypto_bignum_deinit(data->my_scalar, 1); ++ crypto_bignum_deinit(data->k, 1); ++ crypto_ec_point_deinit(data->my_element, 1); ++ crypto_ec_point_deinit(data->server_element, 1); + bin_clear_free(data->id_peer, data->id_peer_len); + bin_clear_free(data->id_server, data->id_server_len); + bin_clear_free(data->password, data->password_len); + if (data->grp) { +- EC_GROUP_free(data->grp->group); +- EC_POINT_clear_free(data->grp->pwe); +- BN_clear_free(data->grp->order); +- BN_clear_free(data->grp->prime); ++ crypto_ec_deinit(data->grp->group); ++ crypto_ec_point_deinit(data->grp->pwe, 1); + os_free(data->grp); + } + wpabuf_free(data->inbuf); +@@ -333,7 +321,7 @@ + } + + wpa_printf(MSG_DEBUG, "EAP-PWD (peer): computed %d bit PWE...", +- BN_num_bits(data->grp->prime)); ++ (int) crypto_ec_prime_len_bits(data->grp->group)); + + data->outbuf = wpabuf_alloc(sizeof(struct eap_pwd_id) + + data->id_peer_len); +@@ -358,10 +346,10 @@ + const struct wpabuf *reqData, + const u8 *payload, size_t payload_len) + { +- EC_POINT *K = NULL; +- BIGNUM *mask = NULL, *x = NULL, *y = NULL, *cofactor = NULL; +- u16 offset; +- u8 *ptr, *scalar = NULL, *element = NULL; ++ struct crypto_ec_point *K = NULL, *point = NULL; ++ struct crypto_bignum *mask = NULL, *cofactor = NULL; ++ const u8 *ptr; ++ u8 *scalar = NULL, *element = NULL; + size_t prime_len, order_len; + + if (data->state != PWD_Commit_Req) { +@@ -369,8 +357,8 @@ + goto fin; + } + +- prime_len = BN_num_bytes(data->grp->prime); +- order_len = BN_num_bytes(data->grp->order); ++ prime_len = crypto_ec_prime_len(data->grp->group); ++ order_len = crypto_ec_order_len(data->grp->group); + + if (payload_len != 2 * prime_len + order_len) { + wpa_printf(MSG_INFO, +@@ -380,76 +368,75 @@ + goto fin; + } + +- if (((data->private_value = BN_new()) == NULL) || +- ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) || +- ((cofactor = BN_new()) == NULL) || +- ((data->my_scalar = BN_new()) == NULL) || +- ((mask = BN_new()) == NULL)) { ++ data->private_value = crypto_bignum_init(); ++ data->my_element = crypto_ec_point_init(data->grp->group); ++ cofactor = crypto_bignum_init(); ++ data->my_scalar = crypto_bignum_init(); ++ mask = crypto_bignum_init(); ++ if (!data->private_value || !data->my_element || !cofactor || ++ !data->my_scalar || !mask) { + wpa_printf(MSG_INFO, "EAP-PWD (peer): scalar allocation fail"); + goto fin; + } + +- if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) { ++ if (crypto_ec_cofactor(data->grp->group, cofactor) < 0) { + wpa_printf(MSG_INFO, "EAP-pwd (peer): unable to get cofactor " + "for curve"); + goto fin; + } + +- if (BN_rand_range(data->private_value, data->grp->order) != 1 || +- BN_rand_range(mask, data->grp->order) != 1 || +- BN_add(data->my_scalar, data->private_value, mask) != 1 || +- BN_mod(data->my_scalar, data->my_scalar, data->grp->order, +- data->bnctx) != 1) { ++ if (crypto_bignum_rand(data->private_value, ++ crypto_ec_get_order(data->grp->group)) < 0 || ++ crypto_bignum_rand(mask, ++ crypto_ec_get_order(data->grp->group)) < 0 || ++ crypto_bignum_add(data->private_value, mask, ++ data->my_scalar) < 0 || ++ crypto_bignum_mod(data->my_scalar, ++ crypto_ec_get_order(data->grp->group), ++ data->my_scalar) < 0) { + wpa_printf(MSG_INFO, + "EAP-pwd (peer): unable to get randomness"); + goto fin; + } + +- if (!EC_POINT_mul(data->grp->group, data->my_element, NULL, +- data->grp->pwe, mask, data->bnctx)) { ++ if (crypto_ec_point_mul(data->grp->group, data->grp->pwe, mask, ++ data->my_element) < 0) { + wpa_printf(MSG_INFO, "EAP-PWD (peer): element allocation " + "fail"); + eap_pwd_state(data, FAILURE); + goto fin; + } + +- if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx)) +- { ++ if (crypto_ec_point_invert(data->grp->group, data->my_element) < 0) { + wpa_printf(MSG_INFO, "EAP-PWD (peer): element inversion fail"); + goto fin; + } + +- if (((x = BN_new()) == NULL) || +- ((y = BN_new()) == NULL)) { +- wpa_printf(MSG_INFO, "EAP-PWD (peer): point allocation fail"); +- goto fin; +- } +- + /* process the request */ +- if (((data->server_scalar = BN_new()) == NULL) || +- ((data->k = BN_new()) == NULL) || +- ((K = EC_POINT_new(data->grp->group)) == NULL) || +- ((data->server_element = EC_POINT_new(data->grp->group)) == NULL)) +- { ++ 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) { + wpa_printf(MSG_INFO, "EAP-PWD (peer): peer data allocation " + "fail"); + goto fin; + } + + /* element, x then y, followed by scalar */ +- ptr = (u8 *) payload; +- BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x); +- ptr += BN_num_bytes(data->grp->prime); +- BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y); +- ptr += BN_num_bytes(data->grp->prime); +- BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->server_scalar); +- if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group, +- data->server_element, x, y, +- data->bnctx)) { ++ ptr = payload; ++ data->server_element = crypto_ec_point_from_bin(data->grp->group, 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); ++ 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) || +@@ -472,21 +459,20 @@ + } + + /* compute the shared key, k */ +- if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe, +- data->server_scalar, data->bnctx)) || +- (!EC_POINT_add(data->grp->group, K, K, data->server_element, +- data->bnctx)) || +- (!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value, +- data->bnctx))) { ++ if (crypto_ec_point_mul(data->grp->group, data->grp->pwe, ++ data->server_scalar, K) < 0 || ++ crypto_ec_point_add(data->grp->group, K, data->server_element, ++ K) < 0 || ++ crypto_ec_point_mul(data->grp->group, K, data->private_value, ++ K) < 0) { + wpa_printf(MSG_INFO, "EAP-PWD (peer): computing shared key " + "fail"); + goto fin; + } + + /* ensure that the shared key isn't in a small sub-group */ +- if (BN_cmp(cofactor, BN_value_one())) { +- if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor, +- NULL)) { ++ if (!crypto_bignum_is_one(cofactor)) { ++ if (crypto_ec_point_mul(data->grp->group, K, cofactor, K) < 0) { + wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply " + "shared key point by order"); + goto fin; +@@ -499,30 +485,22 @@ + * never going to happen it is a simple and safe check "just to be + * sure" so let's be safe. + */ +- if (EC_POINT_is_at_infinity(data->grp->group, K)) { ++ if (crypto_ec_point_is_at_infinity(data->grp->group, K)) { + wpa_printf(MSG_INFO, "EAP-PWD (peer): shared key point is at " + "infinity!\n"); + goto fin; + } + +- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k, +- NULL, data->bnctx)) { ++ if (crypto_ec_point_x(data->grp->group, K, data->k) < 0) { + wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to extract " + "shared secret from point"); + goto fin; + } + + /* now do the response */ +- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, +- data->my_element, x, y, +- data->bnctx)) { +- wpa_printf(MSG_INFO, "EAP-PWD (peer): point assignment fail"); +- goto fin; +- } +- +- if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) || +- ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) == +- NULL)) { ++ scalar = os_zalloc(order_len); ++ element = os_zalloc(prime_len * 2); ++ if (!scalar || !element) { + wpa_printf(MSG_INFO, "EAP-PWD (peer): data allocation fail"); + goto fin; + } +@@ -532,35 +510,28 @@ + * sufficiently smaller than the prime or order might need pre-pending + * with zeros. + */ +- os_memset(scalar, 0, BN_num_bytes(data->grp->order)); +- os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2); +- offset = BN_num_bytes(data->grp->order) - +- BN_num_bytes(data->my_scalar); +- BN_bn2bin(data->my_scalar, scalar + offset); +- +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); +- BN_bn2bin(x, element + offset); +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); +- BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset); ++ crypto_bignum_to_bin(data->my_scalar, scalar, order_len, order_len); ++ if (crypto_ec_point_to_bin(data->grp->group, data->my_element, element, ++ element + prime_len) != 0) { ++ wpa_printf(MSG_INFO, "EAP-PWD (peer): point assignment fail"); ++ goto fin; ++ } + +- data->outbuf = wpabuf_alloc(BN_num_bytes(data->grp->order) + +- 2 * BN_num_bytes(data->grp->prime)); ++ data->outbuf = wpabuf_alloc(order_len + 2 * prime_len); + if (data->outbuf == NULL) + goto fin; + + /* we send the element as (x,y) follwed by the scalar */ +- wpabuf_put_data(data->outbuf, element, +- 2 * BN_num_bytes(data->grp->prime)); +- wpabuf_put_data(data->outbuf, scalar, BN_num_bytes(data->grp->order)); ++ wpabuf_put_data(data->outbuf, element, 2 * prime_len); ++ wpabuf_put_data(data->outbuf, scalar, order_len); + + fin: + os_free(scalar); + os_free(element); +- BN_clear_free(x); +- BN_clear_free(y); +- BN_clear_free(mask); +- BN_clear_free(cofactor); +- EC_POINT_clear_free(K); ++ 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 +@@ -574,12 +545,11 @@ + const struct wpabuf *reqData, + const u8 *payload, size_t payload_len) + { +- BIGNUM *x = NULL, *y = NULL; + struct crypto_hash *hash; + u32 cs; + u16 grp; + u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr; +- int offset; ++ size_t prime_len = 0, order_len = 0; + + if (data->state != PWD_Confirm_Req) { + ret->ignore = TRUE; +@@ -593,6 +563,9 @@ + goto fin; + } + ++ prime_len = crypto_ec_prime_len(data->grp->group); ++ order_len = crypto_ec_order_len(data->grp->group); ++ + /* + * first build up the ciphersuite which is group | random_function | + * prf +@@ -605,9 +578,9 @@ + ptr += sizeof(u8); + *ptr = EAP_PWD_DEFAULT_PRF; + +- /* each component of the cruft will be at most as big as the prime */ +- if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) || +- ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) { ++ /* each component of the point will be at most as big as the prime */ ++ cruft = os_malloc(prime_len * 2); ++ if (!cruft) { + wpa_printf(MSG_INFO, "EAP-PWD (server): confirm allocation " + "fail"); + goto fin; +@@ -625,59 +598,35 @@ + * zero the memory each time because this is mod prime math and some + * value may start with a few zeros and the previous one did not. + */ +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k); +- BN_bn2bin(data->k, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); ++ crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len); ++ eap_pwd_h_update(hash, cruft, prime_len); + + /* server element: x, y */ +- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, +- data->server_element, x, y, +- data->bnctx)) { ++ if (crypto_ec_point_to_bin(data->grp->group, data->server_element, ++ cruft, cruft + prime_len) != 0) { + wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " + "assignment fail"); + goto fin; + } +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); +- BN_bn2bin(x, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); +- BN_bn2bin(y, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); ++ eap_pwd_h_update(hash, cruft, prime_len * 2); + + /* server scalar */ +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->order) - +- BN_num_bytes(data->server_scalar); +- BN_bn2bin(data->server_scalar, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order)); ++ crypto_bignum_to_bin(data->server_scalar, cruft, order_len, order_len); ++ eap_pwd_h_update(hash, cruft, order_len); + + /* my element: x, y */ +- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, +- data->my_element, x, y, +- data->bnctx)) { ++ if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft, ++ cruft + prime_len) != 0) { + wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " + "assignment fail"); + goto fin; + } + +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); +- BN_bn2bin(x, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); +- BN_bn2bin(y, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); ++ eap_pwd_h_update(hash, cruft, prime_len * 2); + + /* my scalar */ +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->order) - +- BN_num_bytes(data->my_scalar); +- BN_bn2bin(data->my_scalar, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order)); ++ crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len); ++ eap_pwd_h_update(hash, cruft, order_len); + + /* the ciphersuite */ + eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32)); +@@ -703,58 +652,34 @@ + goto fin; + + /* k */ +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k); +- BN_bn2bin(data->k, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); ++ crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len); ++ eap_pwd_h_update(hash, cruft, prime_len); + + /* my element */ +- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, +- data->my_element, x, y, +- data->bnctx)) { ++ if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft, ++ cruft + prime_len) != 0) { + wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point " + "assignment fail"); + goto fin; + } +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); +- BN_bn2bin(x, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); +- BN_bn2bin(y, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); ++ eap_pwd_h_update(hash, cruft, prime_len * 2); + + /* my scalar */ +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->order) - +- BN_num_bytes(data->my_scalar); +- BN_bn2bin(data->my_scalar, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order)); ++ crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len); ++ eap_pwd_h_update(hash, cruft, order_len); + + /* server element: x, y */ +- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, +- data->server_element, x, y, +- data->bnctx)) { ++ if (crypto_ec_point_to_bin(data->grp->group, data->server_element, ++ cruft, cruft + prime_len) != 0) { + wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point " + "assignment fail"); + goto fin; + } +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); +- BN_bn2bin(x, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); +- BN_bn2bin(y, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); ++ eap_pwd_h_update(hash, cruft, prime_len * 2); + + /* server scalar */ +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->order) - +- BN_num_bytes(data->server_scalar); +- BN_bn2bin(data->server_scalar, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order)); ++ crypto_bignum_to_bin(data->server_scalar, cruft, order_len, order_len); ++ eap_pwd_h_update(hash, cruft, order_len); + + /* the ciphersuite */ + eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32)); +@@ -762,7 +687,7 @@ + /* all done */ + eap_pwd_h_final(hash, conf); + +- if (compute_keys(data->grp, data->bnctx, data->k, ++ if (compute_keys(data->grp, data->k, + data->my_scalar, data->server_scalar, conf, ptr, + &cs, data->msk, data->emsk, data->session_id) < 0) { + wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute MSK | " +@@ -777,10 +702,7 @@ + wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN); + + fin: +- if (data->grp) +- bin_clear_free(cruft, BN_num_bytes(data->grp->prime)); +- BN_clear_free(x); +- BN_clear_free(y); ++ bin_clear_free(cruft, prime_len * 2); + if (data->outbuf == NULL) { + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; +diff -Nur orig-wpa_supplicant-2.6/src/eap_server/eap_server_pwd.c wpa_supplicant-2.6/src/eap_server/eap_server_pwd.c +--- orig-wpa_supplicant-2.6/src/eap_server/eap_server_pwd.c 2020-02-03 20:08:29.425861513 +0800 ++++ wpa_supplicant-2.6/src/eap_server/eap_server_pwd.c 2020-02-03 23:57:15.626097442 +0800 +@@ -11,6 +11,7 @@ + #include "common.h" + #include "crypto/sha256.h" + #include "crypto/ms_funcs.h" ++#include "crypto/crypto.h" + #include "eap_server/eap_i.h" + #include "eap_common/eap_pwd_common.h" + +@@ -36,20 +37,18 @@ + size_t out_frag_pos; + size_t mtu; + +- BIGNUM *k; +- BIGNUM *private_value; +- BIGNUM *peer_scalar; +- BIGNUM *my_scalar; +- EC_POINT *my_element; +- EC_POINT *peer_element; ++ struct crypto_bignum *k; ++ struct crypto_bignum *private_value; ++ struct crypto_bignum *peer_scalar; ++ struct crypto_bignum *my_scalar; ++ struct crypto_ec_point *my_element; ++ struct crypto_ec_point *peer_element; + + u8 my_confirm[SHA256_MAC_LEN]; + + u8 msk[EAP_MSK_LEN]; + u8 emsk[EAP_EMSK_LEN]; + u8 session_id[1 + SHA256_MAC_LEN]; +- +- BN_CTX *bnctx; + }; + + +@@ -116,15 +115,6 @@ + os_memcpy(data->password, sm->user->password, data->password_len); + data->password_hash = sm->user->password_hash; + +- data->bnctx = BN_CTX_new(); +- if (data->bnctx == NULL) { +- wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail"); +- bin_clear_free(data->password, data->password_len); +- bin_clear_free(data->id_server, data->id_server_len); +- os_free(data); +- return NULL; +- } +- + data->in_frag_pos = data->out_frag_pos = 0; + data->inbuf = data->outbuf = NULL; + /* use default MTU from RFC 5931 if not configured otherwise */ +@@ -138,21 +128,18 @@ + { + struct eap_pwd_data *data = priv; + +- BN_clear_free(data->private_value); +- BN_clear_free(data->peer_scalar); +- BN_clear_free(data->my_scalar); +- BN_clear_free(data->k); +- BN_CTX_free(data->bnctx); +- EC_POINT_clear_free(data->my_element); +- EC_POINT_clear_free(data->peer_element); ++ crypto_bignum_deinit(data->private_value, 1); ++ crypto_bignum_deinit(data->peer_scalar, 1); ++ crypto_bignum_deinit(data->my_scalar, 1); ++ crypto_bignum_deinit(data->k, 1); ++ crypto_ec_point_deinit(data->my_element, 1); ++ crypto_ec_point_deinit(data->peer_element, 1); + bin_clear_free(data->id_peer, data->id_peer_len); + bin_clear_free(data->id_server, data->id_server_len); + bin_clear_free(data->password, data->password_len); + if (data->grp) { +- EC_GROUP_free(data->grp->group); +- EC_POINT_clear_free(data->grp->pwe); +- BN_clear_free(data->grp->order); +- BN_clear_free(data->grp->prime); ++ crypto_ec_deinit(data->grp->group); ++ crypto_ec_point_deinit(data->grp->pwe, 1); + os_free(data->grp); + } + wpabuf_free(data->inbuf); +@@ -198,9 +185,9 @@ + static void eap_pwd_build_commit_req(struct eap_sm *sm, + struct eap_pwd_data *data, u8 id) + { +- BIGNUM *mask = NULL, *x = NULL, *y = NULL; ++ struct crypto_bignum *mask = NULL; + u8 *scalar = NULL, *element = NULL; +- u16 offset; ++ size_t prime_len, order_len; + + wpa_printf(MSG_DEBUG, "EAP-pwd: Commit/Request"); + /* +@@ -210,93 +197,75 @@ + if (data->out_frag_pos) + return; + +- if (((data->private_value = BN_new()) == NULL) || +- ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) || +- ((data->my_scalar = BN_new()) == NULL) || +- ((mask = BN_new()) == NULL)) { ++ prime_len = crypto_ec_prime_len(data->grp->group); ++ order_len = crypto_ec_order_len(data->grp->group); ++ ++ data->private_value = crypto_bignum_init(); ++ data->my_element = crypto_ec_point_init(data->grp->group); ++ data->my_scalar = crypto_bignum_init(); ++ mask = crypto_bignum_init(); ++ if (!data->private_value || !data->my_element || !data->my_scalar || ++ !mask) { + wpa_printf(MSG_INFO, "EAP-PWD (server): scalar allocation " + "fail"); + goto fin; + } + +- if (BN_rand_range(data->private_value, data->grp->order) != 1 || +- BN_rand_range(mask, data->grp->order) != 1 || +- BN_add(data->my_scalar, data->private_value, mask) != 1 || +- BN_mod(data->my_scalar, data->my_scalar, data->grp->order, +- data->bnctx) != 1) { ++ if (crypto_bignum_rand(data->private_value, ++ crypto_ec_get_order(data->grp->group)) < 0 || ++ crypto_bignum_rand(mask, ++ crypto_ec_get_order(data->grp->group)) < 0 || ++ crypto_bignum_add(data->private_value, mask, data->my_scalar) < 0 || ++ crypto_bignum_mod(data->my_scalar, ++ crypto_ec_get_order(data->grp->group), ++ data->my_scalar) < 0) { ++ + wpa_printf(MSG_INFO, + "EAP-pwd (server): unable to get randomness"); + goto fin; + } + +- if (!EC_POINT_mul(data->grp->group, data->my_element, NULL, +- data->grp->pwe, mask, data->bnctx)) { ++ if (crypto_ec_point_mul(data->grp->group, data->grp->pwe, mask, ++ data->my_element) < 0) { + wpa_printf(MSG_INFO, "EAP-PWD (server): element allocation " + "fail"); + eap_pwd_state(data, FAILURE); + goto fin; + } + +- if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx)) +- { ++ if (crypto_ec_point_invert(data->grp->group, data->my_element) < 0) { + wpa_printf(MSG_INFO, "EAP-PWD (server): element inversion " + "fail"); + goto fin; + } +- BN_clear_free(mask); +- +- if (((x = BN_new()) == NULL) || +- ((y = BN_new()) == NULL)) { +- wpa_printf(MSG_INFO, "EAP-PWD (server): point allocation " +- "fail"); ++ scalar = os_malloc(order_len); ++ element = os_malloc(prime_len * 2); ++ if (!scalar || !element) { ++ wpa_printf(MSG_INFO, "EAP-PWD (server): data allocation fail"); + goto fin; + } +- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, +- data->my_element, x, y, +- data->bnctx)) { ++ ++ if (crypto_ec_point_to_bin(data->grp->group, data->my_element, element, ++ element + prime_len) < 0) { + wpa_printf(MSG_INFO, "EAP-PWD (server): point assignment " + "fail"); + goto fin; + } + +- if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) || +- ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) == +- NULL)) { +- wpa_printf(MSG_INFO, "EAP-PWD (server): data allocation fail"); +- goto fin; +- } +- +- /* +- * bignums occupy as little memory as possible so one that is +- * sufficiently smaller than the prime or order might need pre-pending +- * with zeros. +- */ +- os_memset(scalar, 0, BN_num_bytes(data->grp->order)); +- os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2); +- offset = BN_num_bytes(data->grp->order) - +- BN_num_bytes(data->my_scalar); +- BN_bn2bin(data->my_scalar, scalar + offset); +- +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); +- BN_bn2bin(x, element + offset); +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); +- BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset); ++ crypto_bignum_to_bin(data->my_scalar, scalar, order_len, order_len); + +- data->outbuf = wpabuf_alloc(2 * BN_num_bytes(data->grp->prime) + +- BN_num_bytes(data->grp->order)); ++ data->outbuf = wpabuf_alloc(2 * prime_len + order_len); + if (data->outbuf == NULL) + goto fin; + + /* We send the element as (x,y) followed by the scalar */ +- wpabuf_put_data(data->outbuf, element, +- 2 * BN_num_bytes(data->grp->prime)); +- wpabuf_put_data(data->outbuf, scalar, BN_num_bytes(data->grp->order)); ++ wpabuf_put_data(data->outbuf, element, 2 * prime_len); ++ wpabuf_put_data(data->outbuf, scalar, order_len); + + fin: ++ crypto_bignum_deinit(mask, 1); + os_free(scalar); + os_free(element); +- BN_clear_free(x); +- BN_clear_free(y); + if (data->outbuf == NULL) + eap_pwd_state(data, FAILURE); + } +@@ -305,11 +274,10 @@ + static void eap_pwd_build_confirm_req(struct eap_sm *sm, + struct eap_pwd_data *data, u8 id) + { +- BIGNUM *x = NULL, *y = NULL; + struct crypto_hash *hash; + u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr; + u16 grp; +- int offset; ++ size_t prime_len, order_len; + + wpa_printf(MSG_DEBUG, "EAP-pwd: Confirm/Request"); + /* +@@ -319,9 +287,12 @@ + if (data->out_frag_pos) + return; + ++ prime_len = crypto_ec_prime_len(data->grp->group); ++ order_len = crypto_ec_order_len(data->grp->group); ++ + /* Each component of the cruft will be at most as big as the prime */ +- if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) || +- ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) { ++ cruft = os_malloc(prime_len * 2); ++ if (!cruft) { + wpa_printf(MSG_INFO, "EAP-PWD (server): debug allocation " + "fail"); + goto fin; +@@ -341,64 +312,39 @@ + * + * First is k + */ +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k); +- BN_bn2bin(data->k, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); ++ crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len); ++ eap_pwd_h_update(hash, cruft, prime_len); + + /* server element: x, y */ +- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, +- data->my_element, x, y, +- data->bnctx)) { ++ if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft, ++ cruft + prime_len) < 0) { + wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " + "assignment fail"); + goto fin; + } + +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); +- BN_bn2bin(x, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); +- BN_bn2bin(y, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); ++ eap_pwd_h_update(hash, cruft, prime_len * 2); + + /* server scalar */ +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->order) - +- BN_num_bytes(data->my_scalar); +- BN_bn2bin(data->my_scalar, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order)); ++ crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len); ++ eap_pwd_h_update(hash, cruft, order_len); + + /* peer element: x, y */ +- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, +- data->peer_element, x, y, +- data->bnctx)) { ++ if (crypto_ec_point_to_bin(data->grp->group, data->peer_element, cruft, ++ cruft + prime_len) < 0) { + wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " + "assignment fail"); + goto fin; + } +- +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); +- BN_bn2bin(x, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); +- BN_bn2bin(y, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); ++ eap_pwd_h_update(hash, cruft, prime_len * 2); + + /* peer scalar */ +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->order) - +- BN_num_bytes(data->peer_scalar); +- BN_bn2bin(data->peer_scalar, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order)); ++ crypto_bignum_to_bin(data->peer_scalar, cruft, order_len, order_len); ++ eap_pwd_h_update(hash, cruft, order_len); + + /* ciphersuite */ + grp = htons(data->group_num); +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); ++ os_memset(cruft, 0, prime_len); + ptr = cruft; + os_memcpy(ptr, &grp, sizeof(u16)); + ptr += sizeof(u16); +@@ -419,9 +365,7 @@ + wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN); + + fin: +- bin_clear_free(cruft, BN_num_bytes(data->grp->prime)); +- BN_clear_free(x); +- BN_clear_free(y); ++ bin_clear_free(cruft, prime_len * 2); + if (data->outbuf == NULL) + eap_pwd_state(data, FAILURE); + } +@@ -647,7 +591,7 @@ + return; + } + wpa_printf(MSG_DEBUG, "EAP-PWD (server): computed %d bit PWE...", +- BN_num_bits(data->grp->prime)); ++ (int) crypto_ec_prime_len_bits(data->grp->group)); + + eap_pwd_state(data, PWD_Commit_Req); + } +@@ -657,16 +601,16 @@ + eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data, + const u8 *payload, size_t payload_len) + { +- u8 *ptr; +- BIGNUM *x = NULL, *y = NULL, *cofactor = NULL; +- EC_POINT *K = NULL; ++ const u8 *ptr; ++ struct crypto_bignum *cofactor = NULL; ++ struct crypto_ec_point *K = NULL, *point = NULL; + int res = 0; + size_t prime_len, order_len; + + wpa_printf(MSG_DEBUG, "EAP-pwd: Received commit response"); + +- prime_len = BN_num_bytes(data->grp->prime); +- order_len = BN_num_bytes(data->grp->order); ++ prime_len = crypto_ec_prime_len(data->grp->group); ++ order_len = crypto_ec_order_len(data->grp->group); + + if (payload_len != 2 * prime_len + order_len) { + wpa_printf(MSG_INFO, +@@ -676,34 +620,26 @@ + goto fin; + } + +- if (((data->peer_scalar = BN_new()) == NULL) || +- ((data->k = BN_new()) == NULL) || +- ((cofactor = BN_new()) == NULL) || +- ((x = BN_new()) == NULL) || +- ((y = BN_new()) == NULL) || +- ((K = EC_POINT_new(data->grp->group)) == NULL) || +- ((data->peer_element = EC_POINT_new(data->grp->group)) == NULL)) { ++ 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) { + wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation " + "fail"); + goto fin; + } + +- if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) { ++ if (crypto_ec_cofactor(data->grp->group, cofactor) < 0) { + wpa_printf(MSG_INFO, "EAP-PWD (server): unable to get " + "cofactor for curve"); + goto fin; + } + + /* element, x then y, followed by scalar */ +- ptr = (u8 *) payload; +- BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x); +- ptr += BN_num_bytes(data->grp->prime); +- BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y); +- ptr += BN_num_bytes(data->grp->prime); +- BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->peer_scalar); +- if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group, +- data->peer_element, x, y, +- data->bnctx)) { ++ ptr = payload; ++ data->peer_element = crypto_ec_point_from_bin(data->grp->group, ptr); ++ if (!data->peer_element) { + wpa_printf(MSG_INFO, "EAP-PWD (server): setting peer element " + "fail"); + goto fin; +@@ -719,21 +655,21 @@ + } + + /* compute the shared key, k */ +- if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe, +- data->peer_scalar, data->bnctx)) || +- (!EC_POINT_add(data->grp->group, K, K, data->peer_element, +- data->bnctx)) || +- (!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value, +- data->bnctx))) { ++ if ((crypto_ec_point_mul(data->grp->group, data->grp->pwe, ++ data->peer_scalar, K) < 0) || ++ (crypto_ec_point_add(data->grp->group, K, data->peer_element, ++ K) < 0) || ++ (crypto_ec_point_mul(data->grp->group, K, data->private_value, ++ K) < 0)) { + wpa_printf(MSG_INFO, "EAP-PWD (server): computing shared key " + "fail"); + goto fin; + } + + /* ensure that the shared key isn't in a small sub-group */ +- if (BN_cmp(cofactor, BN_value_one())) { +- if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor, +- NULL)) { ++ if (!crypto_bignum_is_one(cofactor)) { ++ if (crypto_ec_point_mul(data->grp->group, K, cofactor, ++ K) != 0) { + wpa_printf(MSG_INFO, "EAP-PWD (server): cannot " + "multiply shared key point by order!\n"); + goto fin; +@@ -746,13 +682,12 @@ + * never going to happen it is a simple and safe check "just to be + * sure" so let's be safe. + */ +- if (EC_POINT_is_at_infinity(data->grp->group, K)) { ++ if (crypto_ec_point_is_at_infinity(data->grp->group, K)) { + wpa_printf(MSG_INFO, "EAP-PWD (server): shared key point is " + "at infinity"); + goto fin; + } +- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k, +- NULL, data->bnctx)) { ++ if (crypto_ec_point_x(data->grp->group, K, data->k)) { + wpa_printf(MSG_INFO, "EAP-PWD (server): unable to extract " + "shared secret from secret point"); + goto fin; +@@ -760,10 +695,9 @@ + res = 1; + + fin: +- EC_POINT_clear_free(K); +- BN_clear_free(cofactor); +- BN_clear_free(x); +- BN_clear_free(y); ++ crypto_ec_point_deinit(K, 1); ++ crypto_ec_point_deinit(point, 1); ++ crypto_bignum_deinit(cofactor, 1); + + if (res) + eap_pwd_state(data, PWD_Confirm_Req); +@@ -776,12 +710,14 @@ + eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data, + const u8 *payload, size_t payload_len) + { +- BIGNUM *x = NULL, *y = NULL; + struct crypto_hash *hash; + u32 cs; + u16 grp; + u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr; +- int offset; ++ size_t prime_len, order_len; ++ ++ prime_len = crypto_ec_prime_len(data->grp->group); ++ order_len = crypto_ec_order_len(data->grp->group); + + if (payload_len != SHA256_MAC_LEN) { + wpa_printf(MSG_INFO, +@@ -800,8 +736,8 @@ + *ptr = EAP_PWD_DEFAULT_PRF; + + /* each component of the cruft will be at most as big as the prime */ +- if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) || +- ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) { ++ cruft = os_malloc(prime_len * 2); ++ if (!cruft) { + wpa_printf(MSG_INFO, "EAP-PWD (peer): allocation fail"); + goto fin; + } +@@ -815,62 +751,36 @@ + goto fin; + + /* k */ +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k); +- BN_bn2bin(data->k, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); ++ crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len); ++ eap_pwd_h_update(hash, cruft, prime_len); + + /* peer element: x, y */ +- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, +- data->peer_element, x, y, +- data->bnctx)) { ++ if (crypto_ec_point_to_bin(data->grp->group, data->peer_element, cruft, ++ cruft + prime_len) < 0) { + wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " + "assignment fail"); + goto fin; + } +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); +- BN_bn2bin(x, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); +- BN_bn2bin(y, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); ++ eap_pwd_h_update(hash, cruft, prime_len * 2); + + /* peer scalar */ +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->order) - +- BN_num_bytes(data->peer_scalar); +- BN_bn2bin(data->peer_scalar, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order)); ++ crypto_bignum_to_bin(data->peer_scalar, cruft, order_len, order_len); ++ eap_pwd_h_update(hash, cruft, order_len); + + /* server element: x, y */ +- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, +- data->my_element, x, y, +- data->bnctx)) { ++ if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft, ++ cruft + prime_len) < 0) { + wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " + "assignment fail"); + goto fin; + } +- +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); +- BN_bn2bin(x, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); +- BN_bn2bin(y, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); ++ eap_pwd_h_update(hash, cruft, prime_len * 2); + + /* server scalar */ +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); +- offset = BN_num_bytes(data->grp->order) - +- BN_num_bytes(data->my_scalar); +- BN_bn2bin(data->my_scalar, cruft + offset); +- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order)); ++ crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len); ++ eap_pwd_h_update(hash, cruft, order_len); + + /* ciphersuite */ +- os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); + eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32)); + + /* all done */ +@@ -884,7 +794,7 @@ + } + + wpa_printf(MSG_DEBUG, "EAP-pwd (server): confirm verified"); +- if (compute_keys(data->grp, data->bnctx, data->k, ++ if (compute_keys(data->grp, data->k, + data->peer_scalar, data->my_scalar, conf, + data->my_confirm, &cs, data->msk, data->emsk, + data->session_id) < 0) +@@ -893,9 +803,7 @@ + eap_pwd_state(data, SUCCESS); + + fin: +- bin_clear_free(cruft, BN_num_bytes(data->grp->prime)); +- BN_clear_free(x); +- BN_clear_free(y); ++ bin_clear_free(cruft, prime_len * 2); + } + + +diff -Nur orig-wpa_supplicant-2.6/wpa_supplicant/Android.mk wpa_supplicant-2.6/wpa_supplicant/Android.mk +--- orig-wpa_supplicant-2.6/wpa_supplicant/Android.mk 2020-02-03 20:08:29.445861775 +0800 ++++ wpa_supplicant-2.6/wpa_supplicant/Android.mk 2020-02-04 00:02:05.699930804 +0800 +@@ -640,6 +640,7 @@ + OBJS += src/eap_peer/eap_pwd.c src/eap_common/eap_pwd_common.c + CONFIG_IEEE8021X_EAPOL=y + NEED_SHA256=y ++NEED_ECC=y + endif + + ifdef CONFIG_EAP_EKE +diff -Nur orig-wpa_supplicant-2.6/wpa_supplicant/Makefile wpa_supplicant-2.6/wpa_supplicant/Makefile +--- orig-wpa_supplicant-2.6/wpa_supplicant/Makefile 2020-02-03 20:08:29.445861775 +0800 ++++ wpa_supplicant-2.6/wpa_supplicant/Makefile 2020-02-04 00:03:21.960938436 +0800 +@@ -669,6 +669,7 @@ + OBJS += ../src/eap_peer/eap_pwd.o ../src/eap_common/eap_pwd_common.o + CONFIG_IEEE8021X_EAPOL=y + NEED_SHA256=y ++NEED_ECC=y + endif + + ifdef CONFIG_EAP_EKE diff --git a/CVE-2019-9495-pre2.patch b/CVE-2019-9495-pre2.patch new file mode 100644 index 0000000000000000000000000000000000000000..19176e23a598cfbbabc5a0843e9d9f48300bd80c --- /dev/null +++ b/CVE-2019-9495-pre2.patch @@ -0,0 +1,92 @@ +diff -Nur orig-wpa_supplicant-2.6/src/eap_common/eap_pwd_common.c wpa_supplicant-2.6/src/eap_common/eap_pwd_common.c +--- orig-wpa_supplicant-2.6/src/eap_common/eap_pwd_common.c 2020-02-04 00:21:51.805643103 +0800 ++++ wpa_supplicant-2.6/src/eap_common/eap_pwd_common.c 2020-02-04 00:30:16.612332185 +0800 +@@ -80,6 +80,26 @@ + return 0; + } + ++EAP_PWD_group * get_eap_pwd_group(u16 num) ++{ ++ EAP_PWD_group *grp; ++ ++ grp = os_zalloc(sizeof(EAP_PWD_group)); ++ if (!grp) ++ return NULL; ++ grp->group = crypto_ec_init(num); ++ if (!grp->group) { ++ wpa_printf(MSG_INFO, "EAP-pwd: unable to create EC group"); ++ os_free(grp); ++ return NULL; ++ } ++ ++ grp->group_num = num; ++ wpa_printf(MSG_INFO, "EAP-pwd: provisioned group %d", num); ++ ++ return grp; ++} +++ + + /* + * compute a "random" secret point on an elliptic curve based +@@ -97,12 +117,8 @@ + size_t primebytelen, primebitlen; + struct crypto_bignum *x_candidate = NULL, *rnd = NULL, *cofactor = NULL; + +- grp->pwe = NULL; +- grp->group = crypto_ec_init(num); +- if (!grp->group) { +- wpa_printf(MSG_INFO, "EAP-pwd: unable to create EC group"); +- goto fail; +- } ++ if (grp->pwe) ++ return -1; + + cofactor = crypto_bignum_init(); + grp->pwe = crypto_ec_point_init(grp->group); +@@ -234,11 +250,8 @@ + break; + } + wpa_printf(MSG_DEBUG, "EAP-pwd: found a PWE in %d tries", ctr); +- grp->group_num = num; + if (0) { + fail: +- crypto_ec_deinit(grp->group); +- grp->group = NULL; + crypto_ec_point_deinit(grp->pwe, 1); + grp->pwe = NULL; + ret = 1; +diff -Nur orig-wpa_supplicant-2.6/src/eap_common/eap_pwd_common.h wpa_supplicant-2.6/src/eap_common/eap_pwd_common.h +--- orig-wpa_supplicant-2.6/src/eap_common/eap_pwd_common.h 2020-02-04 00:21:51.805643103 +0800 ++++ wpa_supplicant-2.6/src/eap_common/eap_pwd_common.h 2020-02-04 00:31:51.873594123 +0800 +@@ -50,6 +50,7 @@ + } STRUCT_PACKED; + + /* common routines */ ++EAP_PWD_group * get_eap_pwd_group(u16 num); + int compute_password_element(EAP_PWD_group *grp, u16 num, + const u8 *password, size_t password_len, + const u8 *id_server, size_t id_server_len, +diff -Nur orig-wpa_supplicant-2.6/src/eap_peer/eap_pwd.c wpa_supplicant-2.6/src/eap_peer/eap_pwd.c +--- orig-wpa_supplicant-2.6/src/eap_peer/eap_pwd.c 2020-02-04 00:21:51.805643103 +0800 ++++ wpa_supplicant-2.6/src/eap_peer/eap_pwd.c 2020-02-04 00:33:35.694969340 +0800 +@@ -267,7 +267,7 @@ + wpa_hexdump_ascii(MSG_INFO, "EAP-PWD (peer): server sent id of", + data->id_server, data->id_server_len); + +- data->grp = os_zalloc(sizeof(EAP_PWD_group)); ++ data->grp = get_eap_pwd_group(data->group_num); + if (data->grp == NULL) { + wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for " + "group"); +diff -Nur orig-wpa_supplicant-2.6/src/eap_server/eap_server_pwd.c wpa_supplicant-2.6/src/eap_server/eap_server_pwd.c +--- orig-wpa_supplicant-2.6/src/eap_server/eap_server_pwd.c 2020-02-04 00:21:51.805643103 +0800 ++++ wpa_supplicant-2.6/src/eap_server/eap_server_pwd.c 2020-02-04 00:34:34.975754518 +0800 +@@ -561,7 +561,7 @@ + wpa_hexdump_ascii(MSG_DEBUG, "EAP-PWD (server): peer sent id of", + data->id_peer, data->id_peer_len); + +- data->grp = os_zalloc(sizeof(EAP_PWD_group)); ++ data->grp = get_eap_pwd_group(data->group_num); + if (data->grp == NULL) { + wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for " + "group"); diff --git a/CVE-2019-9495-pre3.patch b/CVE-2019-9495-pre3.patch new file mode 100644 index 0000000000000000000000000000000000000000..a1f928ef536c76cdbc2ae50c66843cf52af31ec2 --- /dev/null +++ b/CVE-2019-9495-pre3.patch @@ -0,0 +1,236 @@ +diff -Nur orig-wpa_supplicant-2.6/src/eap_common/eap_pwd_common.c wpa_supplicant-2.6/src/eap_common/eap_pwd_common.c +--- orig-wpa_supplicant-2.6/src/eap_common/eap_pwd_common.c 2020-02-04 00:39:56.190008362 +0800 ++++ wpa_supplicant-2.6/src/eap_common/eap_pwd_common.c 2020-02-04 01:06:55.651509904 +0800 +@@ -111,18 +111,25 @@ + const u8 *id_peer, size_t id_peer_len, + const u8 *token) + { ++ struct crypto_bignum *qr = NULL, *qnr = NULL, *one = NULL; ++ struct crypto_bignum *tmp1 = NULL, *tmp2 = NULL, *pm1 = NULL; + struct crypto_hash *hash; + unsigned char pwe_digest[SHA256_MAC_LEN], *prfbuf = NULL, ctr; +- int is_odd, ret = 0; ++ int is_odd, ret = 0, check, found = 0; + size_t primebytelen, primebitlen; + struct crypto_bignum *x_candidate = NULL, *rnd = NULL, *cofactor = NULL; ++ const struct crypto_bignum *prime; + + if (grp->pwe) + return -1; + ++ prime = crypto_ec_get_prime(grp->group); + cofactor = crypto_bignum_init(); + grp->pwe = crypto_ec_point_init(grp->group); +- if (!cofactor || !grp->pwe) { ++ tmp1 = crypto_bignum_init(); ++ pm1 = crypto_bignum_init(); ++ one = crypto_bignum_init_set((const u8 *) "\x01", 1); ++ if (!cofactor || !grp->pwe || !tmp1 || !pm1 || !one) { + wpa_printf(MSG_INFO, "EAP-pwd: unable to create bignums"); + goto fail; + } +@@ -139,15 +146,36 @@ + "buffer"); + goto fail; + } +- os_memset(prfbuf, 0, primebytelen); +- ctr = 0; +- while (1) { +- if (ctr > 30) { +- wpa_printf(MSG_INFO, "EAP-pwd: unable to find random " +- "point on curve for group %d, something's " +- "fishy", num); ++ if (crypto_bignum_sub(prime, one, pm1) < 0) ++ goto fail; ++ ++ /* get a random quadratic residue and nonresidue */ ++ while (!qr || !qnr) { ++ int res; ++ ++ if (crypto_bignum_rand(tmp1, prime) < 0) + goto fail; ++ res = crypto_bignum_legendre(tmp1, prime); ++ if (!qr && res == 1) { ++ qr = tmp1; ++ tmp1 = crypto_bignum_init(); ++ } else if (!qnr && res == -1) { ++ qnr = tmp1; ++ tmp1 = crypto_bignum_init(); + } ++ if (!tmp1) ++ goto fail; ++ } ++ ++ os_memset(prfbuf, 0, primebytelen); ++ ctr = 0; ++ ++ /* ++ * Run through the hunting-and-pecking loop 40 times to mask the time ++ * necessary to find PWE. The odds of PWE not being found in 40 loops is ++ * roughly 1 in 1 trillion. ++ */ ++ while (ctr < 40) { + ctr++; + + /* +@@ -198,58 +226,118 @@ + x_candidate) < 0) + goto fail; + +- if (crypto_bignum_cmp(x_candidate, +- crypto_ec_get_prime(grp->group)) >= 0) ++ if (crypto_bignum_cmp(x_candidate, prime) >= 0) + continue; + + wpa_hexdump(MSG_DEBUG, "EAP-pwd: x_candidate", + prfbuf, primebytelen); + + /* +- * need to unambiguously identify the solution, if there is +- * one... ++ * compute y^2 using the equation of the curve ++ * ++ * y^2 = x^3 + ax + b ++ */ ++ tmp2 = crypto_ec_point_compute_y_sqr(grp->group, x_candidate); ++ if (!tmp2) ++ goto fail; ++ ++ /* ++ * mask tmp2 so doing legendre won't leak timing info ++ * ++ * tmp1 is a random number between 1 and p-1 + */ +- is_odd = crypto_bignum_is_odd(rnd); ++ if (crypto_bignum_rand(tmp1, pm1) < 0 || ++ crypto_bignum_mulmod(tmp2, tmp1, prime, tmp2) < 0 || ++ crypto_bignum_mulmod(tmp2, tmp1, prime, tmp2) < 0) ++ goto fail; + + /* +- * solve the quadratic equation, if it's not solvable then we +- * don't have a point ++ * Now tmp2 (y^2) is masked, all values between 1 and p-1 ++ * are equally probable. Multiplying by r^2 does not change ++ * whether or not tmp2 is a quadratic residue, just masks it. ++ * ++ * Flip a coin, multiply by the random quadratic residue or the ++ * random quadratic nonresidue and record heads or tails. + */ + if (crypto_ec_point_solve_y_coord(grp->group, grp->pwe, + x_candidate, is_odd) != 0) { + wpa_printf(MSG_INFO, "EAP-pwd: Could not solve for y"); + continue; + } ++ if (crypto_bignum_is_odd(tmp1)) { ++ crypto_bignum_mulmod(tmp2, qr, prime, tmp2); ++ check = 1; ++ } else { ++ crypto_bignum_mulmod(tmp2, qnr, prime, tmp2); ++ check = -1; ++ } ++ + /* +- * If there's a solution to the equation then the point must be +- * on the curve so why check again explicitly? OpenSSL code +- * says this is required by X9.62. We're not X9.62 but it can't +- * hurt just to be sure. ++ * Now it's safe to do legendre, if check is 1 then it's ++ * a straightforward test (multiplying by qr does not ++ * change result), if check is -1 then it's the opposite test ++ * (multiplying a qr by qnr would make a qnr). + */ +- if (!crypto_ec_point_is_on_curve(grp->group, grp->pwe)) { +- wpa_printf(MSG_INFO, "EAP-pwd: point is not on curve"); +- continue; +- } +- +- if (!crypto_bignum_is_one(cofactor)) { +- /* make sure the point is not in a small sub-group */ +- if (crypto_ec_point_mul(grp->group, grp->pwe, +- cofactor, grp->pwe) != 0) { +- wpa_printf(MSG_INFO, "EAP-pwd: cannot " +- "multiply generator by order"); ++ if (crypto_bignum_legendre(tmp2, prime) == check) { ++ if (found == 1) ++ continue; ++ ++ /* need to unambiguously identify the solution */ ++ is_odd = crypto_bignum_is_odd(rnd); ++ ++ /* ++ * We know x_candidate is a quadratic residue so set ++ * it here. ++ */ ++ if (crypto_ec_point_solve_y_coord(grp->group, grp->pwe, ++ x_candidate, ++ is_odd) != 0) { ++ wpa_printf(MSG_INFO, ++ "EAP-pwd: Could not solve for y"); + continue; + } +- if (crypto_ec_point_is_at_infinity(grp->group, +- grp->pwe)) { +- wpa_printf(MSG_INFO, "EAP-pwd: point is at " +- "infinity"); ++ ++ /* ++ * If there's a solution to the equation then the point ++ * must be on the curve so why check again explicitly? ++ * OpenSSL code says this is required by X9.62. We're ++ * not X9.62 but it can't hurt just to be sure. ++ */ ++ if (!crypto_ec_point_is_on_curve(grp->group, ++ grp->pwe)) { ++ wpa_printf(MSG_INFO, ++ "EAP-pwd: point is not on curve"); + continue; + } ++ ++ if (!crypto_bignum_is_one(cofactor)) { ++ /* make sure the point is not in a small ++ * sub-group */ ++ if (crypto_ec_point_mul(grp->group, grp->pwe, ++ cofactor, ++ grp->pwe) != 0) { ++ wpa_printf(MSG_INFO, ++ "EAP-pwd: cannot multiply generator by order"); ++ continue; ++ } ++ if (crypto_ec_point_is_at_infinity(grp->group, ++ grp->pwe)) { ++ wpa_printf(MSG_INFO, ++ "EAP-pwd: point is at infinity"); ++ continue; ++ } ++ } ++ wpa_printf(MSG_DEBUG, ++ "EAP-pwd: found a PWE in %d tries", ctr); ++ found = 1; + } +- /* if we got here then we have a new generator. */ +- break; + } +- wpa_printf(MSG_DEBUG, "EAP-pwd: found a PWE in %d tries", ctr); ++ if (found == 0) { ++ wpa_printf(MSG_INFO, ++ "EAP-pwd: unable to find random point on curve for group %d, something's fishy", ++ num); ++ goto fail; ++ } + if (0) { + fail: + crypto_ec_point_deinit(grp->pwe, 1); +@@ -260,6 +348,12 @@ + crypto_bignum_deinit(cofactor, 1); + crypto_bignum_deinit(x_candidate, 1); + crypto_bignum_deinit(rnd, 1); ++ crypto_bignum_deinit(pm1, 0); ++ crypto_bignum_deinit(tmp1, 1); ++ crypto_bignum_deinit(tmp2, 1); ++ crypto_bignum_deinit(qr, 1); ++ crypto_bignum_deinit(qnr, 1); ++ crypto_bignum_deinit(one, 0); + os_free(prfbuf); + + return ret; diff --git a/CVE-2019-9495.patch b/CVE-2019-9495.patch new file mode 100644 index 0000000000000000000000000000000000000000..17cd8fb5804e55dc88b9fe18561bfa332ddf0006 --- /dev/null +++ b/CVE-2019-9495.patch @@ -0,0 +1,296 @@ +diff -Nur orig-wpa_supplicant-2.6/src/eap_common/eap_pwd_common.c wpa_supplicant-2.6/src/eap_common/eap_pwd_common.c +--- orig-wpa_supplicant-2.6/src/eap_common/eap_pwd_common.c 2020-02-04 01:25:30.586304407 +0800 ++++ wpa_supplicant-2.6/src/eap_common/eap_pwd_common.c 2020-02-04 01:58:33.502654599 +0800 +@@ -8,11 +8,15 @@ + + #include "includes.h" + #include "common.h" ++#include "utils/const_time.h" + #include "crypto/sha256.h" + #include "crypto/crypto.h" + #include "eap_defs.h" + #include "eap_pwd_common.h" + ++#define MAX_ECC_PRIME_LEN 66 ++ ++ + /* The random function H(x) = HMAC-SHA256(0^32, x) */ + struct crypto_hash * eap_pwd_h_init(void) + { +@@ -99,7 +103,16 @@ + + return grp; + } +-+ ++ ++ ++static void buf_shift_right(u8 *buf, size_t len, size_t bits) ++{ ++ size_t i; ++ for (i = len - 1; i > 0; i--) ++ buf[i] = (buf[i - 1] << (8 - bits)) | (buf[i] >> bits); ++ buf[0] >>= bits; ++} ++ + + /* + * compute a "random" secret point on an elliptic curve based +@@ -112,17 +125,27 @@ + const u8 *token) + { + struct crypto_bignum *qr = NULL, *qnr = NULL, *one = NULL; ++ struct crypto_bignum *qr_or_qnr = NULL; ++ u8 qr_bin[MAX_ECC_PRIME_LEN]; ++ u8 qnr_bin[MAX_ECC_PRIME_LEN]; ++ u8 qr_or_qnr_bin[MAX_ECC_PRIME_LEN]; ++ u8 x_bin[MAX_ECC_PRIME_LEN]; + struct crypto_bignum *tmp1 = NULL, *tmp2 = NULL, *pm1 = NULL; + struct crypto_hash *hash; + unsigned char pwe_digest[SHA256_MAC_LEN], *prfbuf = NULL, ctr; +- int is_odd, ret = 0, check, found = 0; +- size_t primebytelen, primebitlen; +- struct crypto_bignum *x_candidate = NULL, *rnd = NULL, *cofactor = NULL; ++ int ret = 0, check, res; ++ u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_* ++ * mask */ ++ size_t primebytelen = 0, primebitlen; ++ struct crypto_bignum *x_candidate = NULL, *cofactor = NULL; + const struct crypto_bignum *prime; ++ u8 mask, found_ctr = 0, is_odd = 0; + + if (grp->pwe) + return -1; + ++ os_memset(x_bin, 0, sizeof(x_bin)); ++ + prime = crypto_ec_get_prime(grp->group); + cofactor = crypto_bignum_init(); + grp->pwe = crypto_ec_point_init(grp->group); +@@ -151,8 +174,6 @@ + + /* get a random quadratic residue and nonresidue */ + while (!qr || !qnr) { +- int res; +- + if (crypto_bignum_rand(tmp1, prime) < 0) + goto fail; + res = crypto_bignum_legendre(tmp1, prime); +@@ -166,6 +187,11 @@ + if (!tmp1) + goto fail; + } ++ if (crypto_bignum_to_bin(qr, qr_bin, sizeof(qr_bin), ++ primebytelen) < 0 || ++ crypto_bignum_to_bin(qnr, qnr_bin, sizeof(qnr_bin), ++ primebytelen) < 0) ++ goto fail; + + os_memset(prfbuf, 0, primebytelen); + ctr = 0; +@@ -193,17 +219,16 @@ + eap_pwd_h_update(hash, &ctr, sizeof(ctr)); + eap_pwd_h_final(hash, pwe_digest); + +- crypto_bignum_deinit(rnd, 1); +- rnd = crypto_bignum_init_set(pwe_digest, SHA256_MAC_LEN); +- if (!rnd) { +- wpa_printf(MSG_INFO, "EAP-pwd: unable to create rnd"); +- goto fail; +- } ++ is_odd = const_time_select_u8( ++ found, is_odd, pwe_digest[SHA256_MAC_LEN - 1] & 0x01); + if (eap_pwd_kdf(pwe_digest, SHA256_MAC_LEN, + (u8 *) "EAP-pwd Hunting And Pecking", + os_strlen("EAP-pwd Hunting And Pecking"), + prfbuf, primebitlen) < 0) + goto fail; ++ if (primebitlen % 8) ++ buf_shift_right(prfbuf, primebytelen, ++ 8 - primebitlen % 8); + + crypto_bignum_deinit(x_candidate, 1); + x_candidate = crypto_bignum_init_set(prfbuf, primebytelen); +@@ -213,24 +238,13 @@ + goto fail; + } + +- /* +- * eap_pwd_kdf() returns a string of bits 0..primebitlen but +- * BN_bin2bn will treat that string of bits as a big endian +- * number. If the primebitlen is not an even multiple of 8 +- * then excessive bits-- those _after_ primebitlen-- so now +- * we have to shift right the amount we masked off. +- */ +- if ((primebitlen % 8) && +- crypto_bignum_rshift(x_candidate, +- (8 - (primebitlen % 8)), +- x_candidate) < 0) +- goto fail; +- + if (crypto_bignum_cmp(x_candidate, prime) >= 0) + continue; + +- wpa_hexdump(MSG_DEBUG, "EAP-pwd: x_candidate", +- prfbuf, primebytelen); ++ wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: x_candidate", ++ prfbuf, primebytelen); ++ const_time_select_bin(found, x_bin, prfbuf, primebytelen, ++ x_bin); + + /* + * compute y^2 using the equation of the curve +@@ -264,13 +278,15 @@ + wpa_printf(MSG_INFO, "EAP-pwd: Could not solve for y"); + continue; + } +- if (crypto_bignum_is_odd(tmp1)) { +- crypto_bignum_mulmod(tmp2, qr, prime, tmp2); +- check = 1; +- } else { +- crypto_bignum_mulmod(tmp2, qnr, prime, tmp2); +- check = -1; +- } ++ mask = const_time_eq_u8(crypto_bignum_is_odd(tmp1), 1); ++ check = const_time_select_s8(mask, 1, -1); ++ const_time_select_bin(mask, qr_bin, qnr_bin, primebytelen, ++ qr_or_qnr_bin); ++ crypto_bignum_deinit(qr_or_qnr, 1); ++ qr_or_qnr = crypto_bignum_init_set(qr_or_qnr_bin, primebytelen); ++ if (!qr_or_qnr || ++ crypto_bignum_mulmod(tmp2, qr_or_qnr, prime, tmp2) < 0) ++ goto fail; + + /* + * Now it's safe to do legendre, if check is 1 then it's +@@ -278,59 +294,12 @@ + * change result), if check is -1 then it's the opposite test + * (multiplying a qr by qnr would make a qnr). + */ +- if (crypto_bignum_legendre(tmp2, prime) == check) { +- if (found == 1) +- continue; +- +- /* need to unambiguously identify the solution */ +- is_odd = crypto_bignum_is_odd(rnd); +- +- /* +- * We know x_candidate is a quadratic residue so set +- * it here. +- */ +- if (crypto_ec_point_solve_y_coord(grp->group, grp->pwe, +- x_candidate, +- is_odd) != 0) { +- wpa_printf(MSG_INFO, +- "EAP-pwd: Could not solve for y"); +- continue; +- } +- +- /* +- * If there's a solution to the equation then the point +- * must be on the curve so why check again explicitly? +- * OpenSSL code says this is required by X9.62. We're +- * not X9.62 but it can't hurt just to be sure. +- */ +- if (!crypto_ec_point_is_on_curve(grp->group, +- grp->pwe)) { +- wpa_printf(MSG_INFO, +- "EAP-pwd: point is not on curve"); +- continue; +- } +- +- if (!crypto_bignum_is_one(cofactor)) { +- /* make sure the point is not in a small +- * sub-group */ +- if (crypto_ec_point_mul(grp->group, grp->pwe, +- cofactor, +- grp->pwe) != 0) { +- wpa_printf(MSG_INFO, +- "EAP-pwd: cannot multiply generator by order"); +- continue; +- } +- if (crypto_ec_point_is_at_infinity(grp->group, +- grp->pwe)) { +- wpa_printf(MSG_INFO, +- "EAP-pwd: point is at infinity"); +- continue; +- } +- } +- wpa_printf(MSG_DEBUG, +- "EAP-pwd: found a PWE in %d tries", ctr); +- found = 1; +- } ++ res = crypto_bignum_legendre(tmp2, prime); ++ if (res == -2) ++ goto fail; ++ mask = const_time_eq(res, check); ++ found_ctr = const_time_select_u8(found, found_ctr, ctr); ++ found |= mask; + } + if (found == 0) { + wpa_printf(MSG_INFO, +@@ -338,6 +307,44 @@ + num); + goto fail; + } ++ ++ /* ++ * We know x_candidate is a quadratic residue so set it here. ++ */ ++ crypto_bignum_deinit(x_candidate, 1); ++ x_candidate = crypto_bignum_init_set(x_bin, primebytelen); ++ if (!x_candidate || ++ crypto_ec_point_solve_y_coord(grp->group, grp->pwe, x_candidate, ++ is_odd) != 0) { ++ wpa_printf(MSG_INFO, "EAP-pwd: Could not solve for y"); ++ goto fail; ++ } ++ ++ /* ++ * If there's a solution to the equation then the point must be on the ++ * curve so why check again explicitly? OpenSSL code says this is ++ * required by X9.62. We're not X9.62 but it can't hurt just to be sure. ++ */ ++ if (!crypto_ec_point_is_on_curve(grp->group, grp->pwe)) { ++ wpa_printf(MSG_INFO, "EAP-pwd: point is not on curve"); ++ goto fail; ++ } ++ ++ if (!crypto_bignum_is_one(cofactor)) { ++ /* make sure the point is not in a small sub-group */ ++ if (crypto_ec_point_mul(grp->group, grp->pwe, cofactor, ++ grp->pwe) != 0) { ++ wpa_printf(MSG_INFO, ++ "EAP-pwd: cannot multiply generator by order"); ++ goto fail; ++ } ++ if (crypto_ec_point_is_at_infinity(grp->group, grp->pwe)) { ++ wpa_printf(MSG_INFO, "EAP-pwd: point is at infinity"); ++ goto fail; ++ } ++ } ++ wpa_printf(MSG_DEBUG, "EAP-pwd: found a PWE in %02d tries", found_ctr); ++ + if (0) { + fail: + crypto_ec_point_deinit(grp->pwe, 1); +@@ -347,14 +354,18 @@ + /* cleanliness and order.... */ + crypto_bignum_deinit(cofactor, 1); + crypto_bignum_deinit(x_candidate, 1); +- crypto_bignum_deinit(rnd, 1); + crypto_bignum_deinit(pm1, 0); + crypto_bignum_deinit(tmp1, 1); + crypto_bignum_deinit(tmp2, 1); + crypto_bignum_deinit(qr, 1); + crypto_bignum_deinit(qnr, 1); ++ crypto_bignum_deinit(qr_or_qnr, 1); + crypto_bignum_deinit(one, 0); +- os_free(prfbuf); ++ bin_clear_free(prfbuf, primebytelen); ++ os_memset(qr_bin, 0, sizeof(qr_bin)); ++ os_memset(qnr_bin, 0, sizeof(qnr_bin)); ++ os_memset(qr_or_qnr_bin, 0, sizeof(qr_or_qnr_bin)); ++ os_memset(pwe_digest, 0, sizeof(pwe_digest)); + + return ret; + } diff --git a/wpa_supplicant.spec b/wpa_supplicant.spec index dffe18d64c6fa3402c15b8dbd085d662fdbb36d7..e810efe66f9cbb06c090ed933fe0b08a4b2605c8 100644 --- a/wpa_supplicant.spec +++ b/wpa_supplicant.spec @@ -1,7 +1,7 @@ Name: wpa_supplicant Epoch: 1 Version: 2.6 -Release: 25 +Release: 26 Summary: A WPA Supplicant with support for WPA and WPA2 (IEEE 802.11i / RSN) License: BSD Url: https://w1.fi/wpa_supplicant/ @@ -83,6 +83,10 @@ Patch6066: CVE-2019-11555-1.patch Patch6067: CVE-2019-11555-2.patch Patch6068: https://w1.fi/security/2018-1/rebased-v2.6-0001-WPA-Ignore-unauthenticated-encrypted-EAPOL-Key-data.patch Patch6069: CVE-2019-9499.patch +Patch6070: CVE-2019-9495-pre1.patch +Patch6071: CVE-2019-9495-pre2.patch +Patch6072: CVE-2019-9495-pre3.patch +Patch6073: CVE-2019-9495.patch Patch9000: add-options-of-wpa_supplicant-service.patch Patch9001: allow-to-override-names-of-qt4-tools.patch @@ -179,6 +183,12 @@ install -m644 %{name}/doc/docbook/*.5 %{buildroot}%{_mandir}/man5 %{_mandir}/man5/* %changelog +* Tue Feb 04 2020 zhouyihang - 1:2.6-26 +- Type:cves +- ID: CVE-2019-9495 +- SUG:restart +- DESC: fix CVE-2019-9495 + * Mon Feb 03 2020 zhouyihang - 1:2.6-25 - Type:cves - ID: CVE-2019-9499