@@ -417,6 +417,13 @@ int __must_check crypto_public_key_decrypt_pkcs1(
struct crypto_public_key *key, const u8 *crypt, size_t crypt_len,
u8 *plain, size_t *plain_len);
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+ u8 *pubkey);
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+ const u8 *privkey, size_t privkey_len,
+ const u8 *pubkey, size_t pubkey_len,
+ u8 *secret, size_t *len);
+
/**
* crypto_global_init - Initialize crypto wrapper
*
@@ -529,6 +536,14 @@ int crypto_bignum_to_bin(const struct crypto_bignum *a,
u8 *buf, size_t buflen, size_t padlen);
/**
+ * crypto_bignum_rand - Create random number in range of modulus.
+ * @r: Bignum; random value
+ * @m: Bignum; Modulus
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m);
+
+/**
* crypto_bignum_add - c = a + b
* @a: Bignum
* @b: Bignum
@@ -610,6 +625,16 @@ int crypto_bignum_mulmod(const struct crypto_bignum *a,
struct crypto_bignum *d);
/**
+ * crypto_bugnum_rshift - r = a >> n
+ * @a: Bignum
+ * @n: Number of bits
+ * @r: Bignum; used to store thr result of a >> n
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bugnum_rshift(const struct crypto_bignum *a, int n,
+ struct crypto_bignum *r);
+
+/**
* crypto_bignum_cmp - Compare two bignums
* @a: Bignum
* @b: Bignum
@@ -640,6 +665,13 @@ int crypto_bignum_is_zero(const struct crypto_bignum *a);
int crypto_bignum_is_one(const struct crypto_bignum *a);
/**
+ * crypto_bignum_is_odd - Is the given bignum odd
+ * @a: Bignum
+ * Returns: 1 if @a is odd or 0 if not
+ */
+int crypto_bignum_is_odd(const struct crypto_bignum *a);
+
+/**
* crypto_bignum_legendre - Compute the Legendre symbol (a/p)
* @a: Bignum
* @p: Bignum
@@ -671,6 +703,14 @@ struct crypto_ec * crypto_ec_init(int group);
void crypto_ec_deinit(struct crypto_ec *e);
/**
+ * crypto_ec_cofactor - Set the cofactor into the big number.
+ * @e: EC context from crypto_ec_init()
+ * @cofactor: Cofactor of curve.
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_ec_cofactor(struct crypto_ec* e, struct crypto_bignum* cofactor);
+
+/**
* crypto_ec_prime_len - Get length of the prime in octets
* @e: EC context from crypto_ec_init()
* Returns: Length of the prime defining the group
@@ -685,6 +725,13 @@ size_t crypto_ec_prime_len(struct crypto_ec *e);
size_t crypto_ec_prime_len_bits(struct crypto_ec *e);
/**
+ * crypto_ec_order_len - Get length of the order in octets
+ * @e: EC context from crypto_ec_init()
+ * Returns: Length of the order defining the group
+ */
+size_t crypto_ec_order_len(struct crypto_ec *e);
+
+/**
* crypto_ec_get_prime - Get prime defining an EC group
* @e: EC context from crypto_ec_init()
* Returns: Prime (bignum) defining the group
@@ -721,6 +768,14 @@ struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e);
void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear);
/**
+ * crypto_ec_point_x - Copies the x-ordinate point into big number
+ * @p: EC point data.
+ * @x; Big number copy of x-ordinate.
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_ec_point_x(const struct crypto_ec_point *p, struct crypto_bignum *x);
+
+/**
* crypto_ec_point_to_bin - Write EC point value as binary data
* @e: EC context from crypto_ec_init()
* @p: EC point data from crypto_ec_point_init()
@@ -749,7 +804,7 @@ struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
const u8 *val);
/**
- * crypto_bignum_add - c = a + b
+ * crypto_ec_point_add - c = a + b
* @e: EC context from crypto_ec_init()
* @a: Bignum
* @b: Bignum
@@ -761,7 +816,7 @@ int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
struct crypto_ec_point *c);
/**
- * crypto_bignum_mul - res = b * p
+ * crypto_ec_point_mul - res = b * p
* @e: EC context from crypto_ec_init()
* @p: EC point
* @b: Bignum
@@ -1190,6 +1190,43 @@ const struct dh_group * dh_groups_get(int id)
* @priv: Pointer for returning Diffie-Hellman private key
* Returns: Diffie-Hellman public value
*/
+#ifdef CRYPTO_ABSTRACT_API
+struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv)
+{
+ struct wpabuf *pv;
+ size_t pv_len;
+
+ if (dh == NULL)
+ return NULL;
+
+ wpabuf_clear_free(*priv);
+ *priv = wpabuf_alloc(dh->prime_len);
+ if (*priv == NULL)
+ return NULL;
+
+ pv_len = dh->prime_len;
+ pv = wpabuf_alloc(pv_len);
+ if (pv == NULL) {
+ wpabuf_clear_free(*priv);
+ *priv = NULL;
+ return NULL;
+ }
+ if (crypto_dh_init(*dh->generator, dh->prime, dh->prime_len,
+ wpabuf_mhead(*priv), wpabuf_mhead(pv)) < 0) {
+ wpabuf_clear_free(pv);
+ wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
+ wpabuf_clear_free(*priv);
+ *priv = NULL;
+ return NULL;
+ }
+ wpabuf_put(*priv, dh->prime_len);
+ wpabuf_put(pv, dh->prime_len);
+ wpa_hexdump_buf_key(MSG_DEBUG, "DH: private value", *priv);
+ wpa_hexdump_buf(MSG_DEBUG, "DH: public value", pv);
+
+ return pv;
+}
+#else
struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv)
{
struct wpabuf *pv;
@@ -1238,6 +1275,7 @@ struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv)
return pv;
}
+#endif
/**
@@ -1247,6 +1285,37 @@ struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv)
* @dh: Selected Diffie-Hellman group
* Returns: Diffie-Hellman shared key
*/
+#ifdef CRYPTO_ABSTRACT_API
+struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public,
+ const struct wpabuf *own_private,
+ const struct dh_group *dh)
+{
+ struct wpabuf *shared;
+ size_t shared_len;
+
+ if (dh == NULL || peer_public == NULL || own_private == NULL)
+ return NULL;
+
+ shared_len = dh->prime_len;
+ shared = wpabuf_alloc(shared_len);
+ if (shared == NULL)
+ return NULL;
+ if (crypto_dh_derive_secret(*dh->generator, dh->prime, dh->prime_len,
+ wpabuf_head(own_private),
+ wpabuf_len(own_private),
+ wpabuf_head(peer_public),
+ wpabuf_len(peer_public),
+ wpabuf_mhead(shared), &shared_len) < 0) {
+ wpabuf_clear_free(shared);
+ wpa_printf(MSG_INFO, "DH: crypto_dh_derive_secret failed");
+ return NULL;
+ }
+ wpabuf_put(shared, shared_len);
+ wpa_hexdump_buf_key(MSG_DEBUG, "DH: shared key", shared);
+
+ return shared;
+}
+#else
struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public,
const struct wpabuf *own_private,
const struct dh_group *dh)
@@ -1274,3 +1343,4 @@ struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public,
return shared;
}
+#endif
@@ -155,7 +155,30 @@ static int eap_eke_auth_len(u8 prf)
return -1;
}
+#ifdef CRYPTO_ABSTRACT_API
+int eap_eke_dh_init(u8 group, u8 *ret_priv, u8 *ret_pub)
+{
+ int generator;
+ u8 gen;
+ const struct dh_group *dh;
+ generator = eap_eke_dh_generator(group);
+ dh = eap_eke_dh_group(group);
+ if (generator < 0 || generator > 255 || !dh)
+ return -1;
+ gen = generator;
+
+ if (crypto_dh_init(gen, dh->prime, dh->prime_len, ret_priv,
+ ret_pub) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: DH private value",
+ ret_priv, dh->prime_len);
+ wpa_hexdump(MSG_DEBUG, "EAP-EKE: DH public value",
+ ret_pub, dh->prime_len);
+
+ return 0;
+}
+#else
int eap_eke_dh_init(u8 group, u8 *ret_priv, u8 *ret_pub)
{
int generator;
@@ -201,6 +224,7 @@ int eap_eke_dh_init(u8 group, u8 *ret_priv, u8 *ret_pub)
return 0;
}
+#endif
static int eap_eke_prf(u8 prf, const u8 *key, size_t key_len, const u8 *data,
@@ -397,6 +421,51 @@ int eap_eke_dhcomp(struct eap_eke_session *sess, const u8 *key, const u8 *dhpub,
}
+#ifdef CRYPTO_ABSTRACT_API
+int eap_eke_shared_secret(struct eap_eke_session *sess, const u8 *key,
+ const u8 *dhpriv, const u8 *peer_dhcomp)
+{
+ u8 zeros[EAP_EKE_MAX_HASH_LEN];
+ u8 peer_pub[EAP_EKE_MAX_DH_LEN];
+ u8 modexp[EAP_EKE_MAX_DH_LEN];
+ size_t len;
+ const struct dh_group *dh;
+
+ dh = eap_eke_dh_group(sess->dhgroup);
+ if (sess->encr != EAP_EKE_ENCR_AES128_CBC || !dh)
+ return -1;
+
+ /* Decrypt peer DHComponent */
+ os_memcpy(peer_pub, peer_dhcomp + AES_BLOCK_SIZE, dh->prime_len);
+ if (aes_128_cbc_decrypt(key, peer_dhcomp, peer_pub, dh->prime_len) < 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt DHComponent");
+ return -1;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Decrypted peer DH pubkey",
+ peer_pub, dh->prime_len);
+
+ /* SharedSecret = prf(0+, g ^ (x_s * x_p) (mod p)) */
+ len = dh->prime_len;
+ if (crypto_dh_derive_secret(*dh->generator, dh->prime, dh->prime_len,
+ dhpriv, dh->prime_len, peer_pub,
+ dh->prime_len, modexp, &len) < 0)
+ return -1;
+ if (len < dh->prime_len) {
+ size_t pad = dh->prime_len - len;
+ os_memmove(modexp + pad, modexp, len);
+ os_memset(modexp, 0, pad);
+ }
+
+ os_memset(zeros, 0, sess->auth_len);
+ if (eap_eke_prf(sess->prf, zeros, sess->auth_len, modexp, dh->prime_len,
+ NULL, 0, sess->shared_secret) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: SharedSecret",
+ sess->shared_secret, sess->auth_len);
+
+ return 0;
+}
+#else
int eap_eke_shared_secret(struct eap_eke_session *sess, const u8 *key,
const u8 *dhpriv, const u8 *peer_dhcomp)
{
@@ -439,6 +508,7 @@ int eap_eke_shared_secret(struct eap_eke_session *sess, const u8 *key,
return 0;
}
+#endif
int eap_eke_derive_ke_ki(struct eap_eke_session *sess,
@@ -81,6 +81,186 @@ static int eap_pwd_kdf(const u8 *key, size_t keylen, const u8 *label,
}
+#ifdef CRYPTO_ABSTRACT_API
+/*
+ * compute a "random" secret point on an elliptic curve based
+ * on the password and identities.
+ */
+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,
+ const u8 *id_peer, size_t id_peer_len,
+ const u8 *token)
+{
+ struct crypto_hash *hash;
+ unsigned char pwe_digest[SHA256_MAC_LEN], *prfbuf = NULL, ctr;
+ int is_odd, ret = 0;
+ size_t primebytelen, primebitlen;
+ struct crypto_bignum *x_candidate = NULL, *rnd = NULL, *cofactor = NULL;
+
+ grp->pwe = NULL;
+ if ((grp->group = crypto_ec_init(num)) == NULL) {
+ wpa_printf(MSG_INFO, "EAP-pwd: unable to create EC_GROUP");
+ goto fail;
+ }
+
+ if (((cofactor = crypto_bignum_init()) == NULL) ||
+ ((grp->pwe = crypto_ec_point_init(grp->group)) == NULL)) {
+ wpa_printf(MSG_INFO, "EAP-pwd: unable to create bignums");
+ goto fail;
+ }
+
+ if (crypto_ec_cofactor(grp->group, cofactor) != 0) {
+ wpa_printf(MSG_INFO, "EAP-pwd: unable to get cofactor for "
+ "curve");
+ goto fail;
+ }
+ 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");
+ 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);
+ goto fail;
+ }
+ ctr++;
+
+ /*
+ * compute counter-mode password value and stretch to prime
+ * pwd-seed = H(token | peer-id | server-id | password |
+ * counter)
+ */
+ hash = eap_pwd_h_init();
+ if (hash == NULL)
+ goto fail;
+ eap_pwd_h_update(hash, token, sizeof(u32));
+ eap_pwd_h_update(hash, id_peer, id_peer_len);
+ eap_pwd_h_update(hash, id_server, id_server_len);
+ eap_pwd_h_update(hash, password, password_len);
+ eap_pwd_h_update(hash, &ctr, sizeof(ctr));
+ eap_pwd_h_final(hash, pwe_digest);
+
+ if ((rnd = crypto_bignum_init_set(pwe_digest,
+ SHA256_MAC_LEN)) == NULL) {
+ wpa_printf(MSG_INFO, "EAP-pwd: unable to create "
+ "bignums");
+ 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;
+
+ if ((x_candidate = crypto_bignum_init_set(prfbuf,
+ primebytelen)) == NULL) {
+ wpa_printf(MSG_INFO, "EAP-pwd: unable to create "
+ "bignums");
+ 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_bugnum_rshift(x_candidate,
+ (8 - (primebitlen % 8)),
+ x_candidate);
+ }
+
+ if (crypto_bignum_cmp(x_candidate,
+ crypto_ec_get_prime(grp->group)) >= 0) {
+ crypto_bignum_deinit(x_candidate, 1);
+ crypto_bignum_deinit(rnd, 1);
+ continue;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "EAP-pwd: x_candidate",
+ prfbuf, primebytelen);
+
+ /*
+ * need to unambiguously identify the solution, if there is
+ * one...
+ */
+ is_odd = crypto_bignum_is_odd(rnd);
+
+ /*
+ * solve the quadratic equation, if it's not solvable then we
+ * don't have a point
+ */
+ 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");
+ crypto_bignum_deinit(x_candidate, 1);
+ crypto_bignum_deinit(rnd, 1);
+ 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");
+ crypto_bignum_deinit(x_candidate, 1);
+ crypto_bignum_deinit(rnd, 1);
+ 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");
+ crypto_bignum_deinit(x_candidate, 1);
+ crypto_bignum_deinit(rnd, 1);
+ continue;
+ }
+ if (crypto_ec_point_is_at_infinity(grp->group,
+ grp->pwe)) {
+ wpa_printf(MSG_INFO, "EAP-pwd: point is at "
+ "infinity");
+ crypto_bignum_deinit(x_candidate, 1);
+ crypto_bignum_deinit(rnd, 1);
+ continue;
+ }
+ }
+ /* if we got here then we have a new generator. */
+ 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;
+ }
+ /* cleanliness and order.... */
+ crypto_bignum_deinit(cofactor, 1);
+ crypto_bignum_deinit(x_candidate, 1);
+ crypto_bignum_deinit(rnd, 1);
+ os_free(prfbuf);
+
+ return ret;
+}
+#else
/*
* compute a "random" secret point on an elliptic curve based
* on the password and identities.
@@ -97,6 +277,7 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
int nid, 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;
@@ -302,8 +483,70 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
return ret;
}
+#endif
+
+
+#ifdef CRYPTO_ABSTRACT_API
+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 prime_len, order_len;
+
+ prime_len = crypto_ec_prime_len(grp->group);
+ order_len = crypto_ec_order_len(grp->group);
+
+ if ((cruft = os_malloc(prime_len)) == NULL)
+ return -1;
+
+ /*
+ * first compute the session-id = TypeCode | H(ciphersuite | scal_p |
+ * scal_s)
+ */
+ session_id[0] = EAP_TYPE_PWD;
+ hash = eap_pwd_h_init();
+ if (hash == NULL) {
+ os_free(cruft);
+ return -1;
+ }
+ eap_pwd_h_update(hash, (const u8 *) ciphersuite, sizeof(u32));
+ 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) */
+ hash = eap_pwd_h_init();
+ if (hash == NULL) {
+ os_free(cruft);
+ return -1;
+ }
+ 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);
+ eap_pwd_h_final(hash, mk);
+
+ /* stretch the mk with the session-id to get MSK | EMSK */
+ if (eap_pwd_kdf(mk, SHA256_MAC_LEN,
+ session_id, SHA256_MAC_LEN + 1,
+ msk_emsk, (EAP_MSK_LEN + EAP_EMSK_LEN) * 8) < 0) {
+ return -1;
+ }
+ os_memcpy(msk, msk_emsk, EAP_MSK_LEN);
+ os_memcpy(emsk, msk_emsk + EAP_MSK_LEN, EAP_EMSK_LEN);
+
+ return 1;
+}
+#else
int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const BIGNUM *k,
const BIGNUM *peer_scalar, const BIGNUM *server_scalar,
const u8 *confirm_peer, const u8 *confirm_server,
@@ -365,3 +608,4 @@ int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const BIGNUM *k,
return 1;
}
+#endif
@@ -9,9 +9,13 @@
#ifndef EAP_PWD_COMMON_H
#define EAP_PWD_COMMON_H
+#ifdef CRYPTO_ABSTRACT_API
+#include "crypto/crypto.h"
+#else
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/evp.h>
+#endif
/*
* definition of a finite cyclic group
@@ -19,10 +23,15 @@
*/
typedef struct group_definition_ {
u16 group_num;
+#ifdef CRYPTO_ABSTRACT_API
+ struct crypto_ec *group;
+ struct crypto_ec_point *pwe;
+#else
EC_GROUP *group;
EC_POINT *pwe;
BIGNUM *order;
BIGNUM *prime;
+#endif
} EAP_PWD_group;
/*
@@ -61,10 +70,18 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
const u8 *id_server, size_t id_server_len,
const u8 *id_peer, size_t id_peer_len,
const u8 *token);
+#ifdef CRYPTO_ABSTRACT_API
+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);
+#else
int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const BIGNUM *k,
const BIGNUM *peer_scalar, const BIGNUM *server_scalar,
const u8 *confirm_peer, const u8 *confirm_server,
const u32 *ciphersuite, u8 *msk, u8 *emsk, u8 *session_id);
+#endif
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);
@@ -13,6 +13,9 @@
#include "crypto/ms_funcs.h"
#include "eap_peer/eap_i.h"
#include "eap_common/eap_pwd_common.h"
+#ifdef CRYPTO_ABSTRACT_API
+#include "crypto/crypto.h"
+#endif
struct eap_pwd_data {
@@ -36,18 +39,29 @@ struct eap_pwd_data {
size_t out_frag_pos;
size_t mtu;
+#ifdef CRYPTO_ABSTRACT_API
+ 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;
+#else
BIGNUM *k;
BIGNUM *private_value;
BIGNUM *server_scalar;
BIGNUM *my_scalar;
EC_POINT *my_element;
EC_POINT *server_element;
+#endif
u8 msk[EAP_MSK_LEN];
u8 emsk[EAP_EMSK_LEN];
u8 session_id[1 + SHA256_MAC_LEN];
+#ifndef CRYPTO_ABSTRACT_API
BN_CTX *bnctx;
+#endif
};
@@ -107,15 +121,19 @@ static void * eap_pwd_init(struct eap_sm *sm)
return NULL;
}
+#ifndef CRYPTO_ABSTRACT_API
if ((data->bnctx = BN_CTX_new()) == NULL) {
wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail");
os_free(data);
return NULL;
}
+#endif
if ((data->id_peer = os_malloc(identity_len)) == NULL) {
wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
+#ifndef CRYPTO_ABSTRACT_API
BN_CTX_free(data->bnctx);
+#endif
os_free(data);
return NULL;
}
@@ -125,7 +143,9 @@ static void * eap_pwd_init(struct eap_sm *sm)
if ((data->password = os_malloc(password_len)) == NULL) {
wpa_printf(MSG_INFO, "EAP-PWD: memory allocation psk fail");
+#ifndef CRYPTO_ABSTRACT_API
BN_CTX_free(data->bnctx);
+#endif
bin_clear_free(data->id_peer, data->id_peer_len);
os_free(data);
return NULL;
@@ -148,6 +168,30 @@ static void * eap_pwd_init(struct eap_sm *sm)
}
+#ifdef CRYPTO_ABSTRACT_API
+static void eap_pwd_deinit(struct eap_sm *sm, void *priv)
+{
+ struct eap_pwd_data *data = priv;
+
+ 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) {
+ crypto_ec_deinit(data->grp->group);
+ crypto_ec_point_deinit(data->grp->pwe, 1);
+ os_free(data->grp);
+ }
+ wpabuf_free(data->inbuf);
+ wpabuf_free(data->outbuf);
+ bin_clear_free(data, sizeof(*data));
+}
+#else
static void eap_pwd_deinit(struct eap_sm *sm, void *priv)
{
struct eap_pwd_data *data = priv;
@@ -173,6 +217,7 @@ static void eap_pwd_deinit(struct eap_sm *sm, void *priv)
wpabuf_free(data->outbuf);
bin_clear_free(data, sizeof(*data));
}
+#endif
static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len)
@@ -330,8 +375,13 @@ eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
return;
}
+#ifdef CRYPTO_ABSTRACT_API
+ wpa_printf(MSG_DEBUG, "EAP-PWD (peer): computed %d bit PWE...",
+ (int)crypto_ec_prime_len_bits(data->grp->group));
+#else
wpa_printf(MSG_DEBUG, "EAP-PWD (peer): computed %d bit PWE...",
BN_num_bits(data->grp->prime));
+#endif
data->outbuf = wpabuf_alloc(sizeof(struct eap_pwd_id) +
data->id_peer_len);
@@ -350,6 +400,199 @@ eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
}
+#ifdef CRYPTO_ABSTRACT_API
+static void
+eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
+ struct eap_method_ret *ret,
+ const struct wpabuf *reqData,
+ const u8 *payload, size_t payload_len)
+{
+ struct crypto_ec_point *K = NULL, *point = NULL;
+ struct crypto_bignum *mask = NULL, *x = NULL, *y = NULL,
+ *cofactor = NULL;
+ u8 *ptr, *scalar = NULL, *element = NULL;
+ size_t prime_len, order_len;
+
+ if (data->state != PWD_Commit_Req) {
+ ret->ignore = TRUE;
+ goto fin;
+ }
+
+ 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,
+ "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
+ (unsigned int) payload_len,
+ (unsigned int) (2 * prime_len + order_len));
+ goto fin;
+ }
+
+ if (((data->private_value = crypto_bignum_init()) == NULL) ||
+ ((data->my_element = crypto_ec_point_init(data->grp->group)) == NULL) ||
+ ((cofactor = crypto_bignum_init()) == NULL) ||
+ ((data->my_scalar = crypto_bignum_init()) == NULL) ||
+ ((mask = crypto_bignum_init()) == NULL)) {
+ wpa_printf(MSG_INFO, "EAP-PWD (peer): scalar allocation fail");
+ goto fin;
+ }
+
+ 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 (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 (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 (crypto_ec_point_invert(data->grp->group, data->my_element) != 0) {
+ wpa_printf(MSG_INFO, "EAP-PWD (peer): element inversion fail");
+ goto fin;
+ }
+
+ /* process the request */
+ if (((data->k = crypto_bignum_init()) == NULL) ||
+ ((K = crypto_ec_point_init(data->grp->group)) == NULL) ||
+ ((point = crypto_ec_point_init(data->grp->group)) == NULL)) {
+ wpa_printf(MSG_INFO, "EAP-PWD (peer): peer data allocation "
+ "fail");
+ goto fin;
+ }
+
+ /* element, x then y, followed by scalar */
+ ptr = (u8 *) payload;
+ if ((data->server_element = crypto_ec_point_from_bin(data->grp->group,
+ ptr)) == NULL) {
+ wpa_printf(MSG_INFO, "EAP-PWD (peer): point allocation fail");
+ goto fin;
+ }
+ ptr += prime_len * 2;
+ if ((data->server_scalar = crypto_bignum_init_set(ptr,
+ order_len)) == NULL) {
+ wpa_printf(MSG_INFO, "EAP-PWD (peer): point allocation fail");
+ 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) ||
+ (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 (!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;
+ }
+ }
+
+ /*
+ * This check is strictly speaking just for the case above where
+ * co-factor > 1 but it was suggested that even though this is probably
+ * never going to happen it is a simple and safe check "just to be
+ * sure" so let's be safe.
+ */
+ 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 (crypto_ec_point_x(K, data->k) != 0) {
+ wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to extract "
+ "shared secret from point");
+ goto fin;
+ }
+
+ if (((scalar = os_malloc(order_len)) == NULL) ||
+ ((element = os_malloc(prime_len * 2)) == NULL)) {
+ wpa_printf(MSG_INFO, "EAP-PWD (peer): 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, order_len);
+ os_memset(element, 0, prime_len * 2);
+ crypto_bignum_to_bin(data->my_scalar, scalar, order_len, order_len);
+ /* now do the response */
+ 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(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 * prime_len);
+ wpabuf_put_data(data->outbuf, scalar, order_len);
+
+fin:
+ os_free(scalar);
+ os_free(element);
+ crypto_bignum_deinit(x, 1);
+ crypto_bignum_deinit(y, 1);
+ 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
+ eap_pwd_state(data, PWD_Confirm_Req);
+}
+#else
static void
eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
struct eap_method_ret *ret,
@@ -561,8 +804,185 @@ fin:
else
eap_pwd_state(data, PWD_Confirm_Req);
}
+#endif
+
+
+#ifdef CRYPTO_ABSTRACT_API
+static void
+eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
+ struct eap_method_ret *ret,
+ const struct wpabuf *reqData,
+ const u8 *payload, size_t payload_len)
+{
+ struct crypto_hash *hash;
+ u32 cs;
+ u16 grp;
+ u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
+ int prime_len = 0;
+ int order_len = 0;
+
+ if (data->state != PWD_Confirm_Req) {
+ ret->ignore = TRUE;
+ goto fin;
+ }
+
+ if (payload_len != SHA256_MAC_LEN) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd: Unexpected Confirm payload length %u "
+ "(expected %u)", (unsigned int) payload_len,
+ SHA256_MAC_LEN);
+ 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
+ */
+ grp = htons(data->group_num);
+ ptr = (u8 *) &cs;
+ os_memcpy(ptr, &grp, sizeof(u16));
+ ptr += sizeof(u16);
+ *ptr = EAP_PWD_DEFAULT_RAND_FUNC;
+ ptr += sizeof(u8);
+ *ptr = EAP_PWD_DEFAULT_PRF;
+
+ /* each component of the point will be at most as big as the prime */
+ if ((cruft = os_malloc(prime_len * 2)) == NULL) {
+ wpa_printf(MSG_INFO, "EAP-PWD (server): confirm allocation "
+ "fail");
+ goto fin;
+ }
+
+ /*
+ * server's commit is H(k | server_element | server_scalar |
+ * peer_element | peer_scalar | ciphersuite)
+ */
+ hash = eap_pwd_h_init();
+ if (hash == NULL)
+ goto fin;
+
+ /*
+ * 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.
+ */
+ crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len);
+ eap_pwd_h_update(hash, cruft, prime_len);
+
+ /* server element: x, y */
+ 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;
+ }
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
+
+ /* server scalar */
+ 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 (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;
+ }
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
+ /* my scalar */
+ 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));
+
+ /* random function fin */
+ eap_pwd_h_final(hash, conf);
+
+ ptr = (u8 *) payload;
+ if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) {
+ wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm did not verify");
+ goto fin;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-pwd (peer): confirm verified");
+
+ /*
+ * compute confirm:
+ * H(k | peer_element | peer_scalar | server_element | server_scalar |
+ * ciphersuite)
+ */
+ hash = eap_pwd_h_init();
+ if (hash == NULL)
+ goto fin;
+
+ /* k */
+ crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len);
+ eap_pwd_h_update(hash, cruft, prime_len);
+
+ /* my element */
+ 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;
+ }
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
+
+ /* my scalar */
+ 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 (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;
+ }
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
+
+ /* server scalar */
+ 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));
+
+ /* all done */
+ eap_pwd_h_final(hash, conf);
+
+ 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 | "
+ "EMSK");
+ goto fin;
+ }
+
+ data->outbuf = wpabuf_alloc(SHA256_MAC_LEN);
+ if (data->outbuf == NULL)
+ goto fin;
+
+ wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
+
+fin:
+ if (data->grp)
+ bin_clear_free(cruft, prime_len * 2);
+ if (data->outbuf == NULL) {
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ eap_pwd_state(data, FAILURE);
+ } else {
+ eap_pwd_state(data, SUCCESS_ON_FRAG_COMPLETION);
+ }
+}
+#else
static void
eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
struct eap_method_ret *ret,
@@ -784,6 +1204,7 @@ fin:
eap_pwd_state(data, SUCCESS_ON_FRAG_COMPLETION);
}
}
+#endif
static struct wpabuf *
@@ -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,12 +37,21 @@ struct eap_pwd_data {
size_t out_frag_pos;
size_t mtu;
+#ifdef CRYPTO_ABSTRACT_API
+ 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;
+#else
BIGNUM *k;
BIGNUM *private_value;
BIGNUM *peer_scalar;
BIGNUM *my_scalar;
EC_POINT *my_element;
EC_POINT *peer_element;
+#endif
u8 my_confirm[SHA256_MAC_LEN];
@@ -49,7 +59,9 @@ struct eap_pwd_data {
u8 emsk[EAP_EMSK_LEN];
u8 session_id[1 + SHA256_MAC_LEN];
+#ifndef CRYPTO_ABSTRACT_API
BN_CTX *bnctx;
+#endif
};
@@ -116,6 +128,7 @@ static void * eap_pwd_init(struct eap_sm *sm)
os_memcpy(data->password, sm->user->password, data->password_len);
data->password_hash = sm->user->password_hash;
+#ifndef CRYPTO_ABSTRACT_API
data->bnctx = BN_CTX_new();
if (data->bnctx == NULL) {
wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail");
@@ -124,6 +137,7 @@ static void * eap_pwd_init(struct eap_sm *sm)
os_free(data);
return NULL;
}
+#endif
data->in_frag_pos = data->out_frag_pos = 0;
data->inbuf = data->outbuf = NULL;
@@ -134,6 +148,30 @@ static void * eap_pwd_init(struct eap_sm *sm)
}
+#ifdef CRYPTO_ABSTRACT_API
+static void eap_pwd_reset(struct eap_sm *sm, void *priv)
+{
+ struct eap_pwd_data *data = priv;
+
+ 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) {
+ crypto_ec_deinit(data->grp->group);
+ crypto_ec_point_deinit(data->grp->pwe, 1);
+ os_free(data->grp);
+ }
+ wpabuf_free(data->inbuf);
+ wpabuf_free(data->outbuf);
+ bin_clear_free(data, sizeof(*data));
+}
+#else
static void eap_pwd_reset(struct eap_sm *sm, void *priv)
{
struct eap_pwd_data *data = priv;
@@ -159,6 +197,7 @@ static void eap_pwd_reset(struct eap_sm *sm, void *priv)
wpabuf_free(data->outbuf);
bin_clear_free(data, sizeof(*data));
}
+#endif
static void eap_pwd_build_id_req(struct eap_sm *sm, struct eap_pwd_data *data,
@@ -195,6 +234,93 @@ static void eap_pwd_build_id_req(struct eap_sm *sm, struct eap_pwd_data *data,
}
+#ifdef CRYPTO_ABSTRACT_API
+static void eap_pwd_build_commit_req(struct eap_sm *sm,
+ struct eap_pwd_data *data, u8 id)
+{
+ struct crypto_bignum *mask = NULL;
+ u8 *scalar = NULL, *element = NULL;
+ int prime_len, order_len;
+
+ wpa_printf(MSG_DEBUG, "EAP-pwd: Commit/Request");
+ /*
+ * if we're fragmenting then we already have an commit request, just
+ * return
+ */
+ if (data->out_frag_pos)
+ return;
+
+ prime_len = crypto_ec_prime_len(data->grp->group);
+ order_len = crypto_ec_order_len(data->grp->group);
+
+ if (((data->private_value = crypto_bignum_init()) == NULL) ||
+ ((data->my_element = crypto_ec_point_init(data->grp->group)) == NULL) ||
+ ((data->my_scalar = crypto_bignum_init()) == NULL) ||
+ ((mask = crypto_bignum_init()) == NULL)) {
+ wpa_printf(MSG_INFO, "EAP-PWD (server): scalar allocation "
+ "fail");
+ goto fin;
+ }
+
+ 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 (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 (crypto_ec_point_invert(data->grp->group, data->my_element) != 0) {
+ wpa_printf(MSG_INFO, "EAP-PWD (server): element inversion "
+ "fail");
+ goto fin;
+ }
+ crypto_bignum_deinit(mask, 1);
+
+ if (((scalar = os_malloc(order_len)) == NULL) ||
+ ((element = os_malloc(prime_len * 2)) == NULL)) {
+ wpa_printf(MSG_INFO, "EAP-PWD (server): data allocation fail");
+ goto fin;
+ }
+
+ 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;
+ }
+
+ crypto_bignum_to_bin(data->my_scalar, scalar, order_len, order_len);
+
+ 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 * prime_len);
+ wpabuf_put_data(data->outbuf, scalar, order_len);
+
+fin:
+ os_free(scalar);
+ os_free(element);
+ if (data->outbuf == NULL)
+ eap_pwd_state(data, FAILURE);
+}
+#else
static void eap_pwd_build_commit_req(struct eap_sm *sm,
struct eap_pwd_data *data, u8 id)
{
@@ -300,8 +426,107 @@ fin:
if (data->outbuf == NULL)
eap_pwd_state(data, FAILURE);
}
+#endif
+
+
+#ifdef CRYPTO_ABSTRACT_API
+static void eap_pwd_build_confirm_req(struct eap_sm *sm,
+ struct eap_pwd_data *data, u8 id)
+{
+ struct crypto_hash *hash;
+ u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
+ u16 grp;
+ int prime_len, order_len;
+ wpa_printf(MSG_DEBUG, "EAP-pwd: Confirm/Request");
+ /*
+ * if we're fragmenting then we already have an confirm request, just
+ * return
+ */
+ 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(prime_len * 2)) == NULL) {
+ wpa_printf(MSG_INFO, "EAP-PWD (server): debug allocation "
+ "fail");
+ goto fin;
+ }
+
+ /*
+ * commit is H(k | server_element | server_scalar | peer_element |
+ * peer_scalar | ciphersuite)
+ */
+ hash = eap_pwd_h_init();
+ if (hash == NULL)
+ goto fin;
+
+ /*
+ * 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.
+ *
+ * First is k
+ */
+ crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len);
+ eap_pwd_h_update(hash, cruft, prime_len);
+
+ /* server element: x, y */
+ 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;
+ }
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
+
+ /* server scalar */
+ 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 (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;
+ }
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
+
+ /* peer scalar */
+ 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, prime_len);
+ ptr = cruft;
+ os_memcpy(ptr, &grp, sizeof(u16));
+ ptr += sizeof(u16);
+ *ptr = EAP_PWD_DEFAULT_RAND_FUNC;
+ ptr += sizeof(u8);
+ *ptr = EAP_PWD_DEFAULT_PRF;
+ ptr += sizeof(u8);
+ eap_pwd_h_update(hash, cruft, ptr - cruft);
+ /* all done with the random function */
+ eap_pwd_h_final(hash, conf);
+ os_memcpy(data->my_confirm, conf, SHA256_MAC_LEN);
+
+ data->outbuf = wpabuf_alloc(SHA256_MAC_LEN);
+ if (data->outbuf == NULL)
+ goto fin;
+
+ wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
+
+fin:
+ bin_clear_free(cruft, prime_len * 2);
+ if (data->outbuf == NULL)
+ eap_pwd_state(data, FAILURE);
+}
+#else
static void eap_pwd_build_confirm_req(struct eap_sm *sm,
struct eap_pwd_data *data, u8 id)
{
@@ -425,6 +650,7 @@ fin:
if (data->outbuf == NULL)
eap_pwd_state(data, FAILURE);
}
+#endif
static struct wpabuf *
@@ -648,13 +874,139 @@ static void eap_pwd_process_id_resp(struct eap_sm *sm,
"PWE");
return;
}
+#ifdef CRYPTO_ABSTRACT_API
+ wpa_printf(MSG_DEBUG, "EAP-PWD (server): computed %d bit PWE...",
+ (int)crypto_ec_prime_len_bits(data->grp->group));
+#else
wpa_printf(MSG_DEBUG, "EAP-PWD (server): computed %d bit PWE...",
BN_num_bits(data->grp->prime));
+#endif
eap_pwd_state(data, PWD_Commit_Req);
}
+#ifdef CRYPTO_ABSTRACT_API
+static void
+eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
+ const u8 *payload, size_t payload_len)
+{
+ 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 = 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,
+ "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
+ (unsigned int) payload_len,
+ (unsigned int) (2 * prime_len + order_len));
+ goto fin;
+ }
+
+ if (((data->k = crypto_bignum_init()) == NULL) ||
+ ((cofactor = crypto_bignum_init()) == NULL) ||
+ ((point = crypto_ec_point_init(data->grp->group)) == NULL) ||
+ ((K = crypto_ec_point_init(data->grp->group)) == NULL)) {
+ wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation "
+ "fail");
+ goto fin;
+ }
+
+ 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;
+ if ((data->peer_element = crypto_ec_point_from_bin(data->grp->group,
+ ptr)) == NULL) {
+ wpa_printf(MSG_INFO, "EAP-PWD (server): setting peer element "
+ "fail");
+ goto fin;
+ }
+ ptr += prime_len * 2;
+ if ((data->peer_scalar = crypto_bignum_init_set(ptr,
+ order_len)) == NULL) {
+ wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation "
+ "fail");
+ 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;
+ }
+ }
+
+ /* compute the shared key, k */
+ 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 (!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;
+ }
+ }
+
+ /*
+ * This check is strictly speaking just for the case above where
+ * co-factor > 1 but it was suggested that even though this is probably
+ * never going to happen it is a simple and safe check "just to be
+ * sure" so let's be safe.
+ */
+ 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 (crypto_ec_point_x(K, data->k)) {
+ wpa_printf(MSG_INFO, "EAP-PWD (server): unable to extract "
+ "shared secret from secret point");
+ goto fin;
+ }
+ res = 1;
+
+fin:
+ 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);
+ else
+ eap_pwd_state(data, FAILURE);
+}
+#else
static void
eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
const u8 *payload, size_t payload_len)
@@ -780,8 +1132,109 @@ fin:
else
eap_pwd_state(data, FAILURE);
}
+#endif
+
+
+#ifdef CRYPTO_ABSTRACT_API
+static void
+eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
+ const u8 *payload, size_t payload_len)
+{
+ struct crypto_hash *hash;
+ u32 cs;
+ u16 grp;
+ u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
+ int 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,
+ "EAP-pwd: Unexpected Confirm payload length %u "
+ "(expected %u)", (unsigned int) payload_len,
+ SHA256_MAC_LEN);
+ goto fin;
+ }
+
+ /* build up the ciphersuite: group | random_function | prf */
+ grp = htons(data->group_num);
+ ptr = (u8 *) &cs;
+ os_memcpy(ptr, &grp, sizeof(u16));
+ ptr += sizeof(u16);
+ *ptr = EAP_PWD_DEFAULT_RAND_FUNC;
+ 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(prime_len * 2)) == NULL) {
+ wpa_printf(MSG_INFO, "EAP-PWD (peer): allocation fail");
+ goto fin;
+ }
+
+ /*
+ * commit is H(k | peer_element | peer_scalar | server_element |
+ * server_scalar | ciphersuite)
+ */
+ hash = eap_pwd_h_init();
+ if (hash == NULL)
+ goto fin;
+
+ /* k */
+ crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len);
+ eap_pwd_h_update(hash, cruft, prime_len);
+
+ /* peer element: x, y */
+ 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;
+ }
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
+
+ /* peer scalar */
+ 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 (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;
+ }
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
+ /* server scalar */
+ crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len);
+ eap_pwd_h_update(hash, cruft, order_len);
+ /* ciphersuite */
+ eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
+
+ /* all done */
+ eap_pwd_h_final(hash, conf);
+
+ ptr = (u8 *) payload;
+ if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) {
+ wpa_printf(MSG_INFO, "EAP-PWD (server): confirm did not "
+ "verify");
+ goto fin;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-pwd (server): confirm verified");
+ 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)
+ eap_pwd_state(data, FAILURE);
+ else
+ eap_pwd_state(data, SUCCESS);
+
+fin:
+ bin_clear_free(cruft, prime_len);
+}
+#else
static void
eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
const u8 *payload, size_t payload_len)
@@ -907,6 +1360,7 @@ fin:
BN_clear_free(x);
BN_clear_free(y);
}
+#endif
static void eap_pwd_process(struct eap_sm *sm, void *priv,