1f05cddf9SRui Paulo /* 2f05cddf9SRui Paulo * EAP peer method: EAP-pwd (RFC 5931) 3f05cddf9SRui Paulo * Copyright (c) 2010, Dan Harkins <dharkins@lounge.org> 4f05cddf9SRui Paulo * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 7f05cddf9SRui Paulo */ 8f05cddf9SRui Paulo 9f05cddf9SRui Paulo #include "includes.h" 10f05cddf9SRui Paulo 11f05cddf9SRui Paulo #include "common.h" 1285732ac8SCy Schubert #include "crypto/sha1.h" 13f05cddf9SRui Paulo #include "crypto/sha256.h" 1485732ac8SCy Schubert #include "crypto/sha512.h" 15325151a3SRui Paulo #include "crypto/ms_funcs.h" 1685732ac8SCy Schubert #include "crypto/crypto.h" 17f05cddf9SRui Paulo #include "eap_peer/eap_i.h" 18f05cddf9SRui Paulo #include "eap_common/eap_pwd_common.h" 19f05cddf9SRui Paulo 20f05cddf9SRui Paulo 21f05cddf9SRui Paulo struct eap_pwd_data { 22f05cddf9SRui Paulo enum { 235b9c547cSRui Paulo PWD_ID_Req, PWD_Commit_Req, PWD_Confirm_Req, 245b9c547cSRui Paulo SUCCESS_ON_FRAG_COMPLETION, SUCCESS, FAILURE 25f05cddf9SRui Paulo } state; 26f05cddf9SRui Paulo u8 *id_peer; 27f05cddf9SRui Paulo size_t id_peer_len; 28f05cddf9SRui Paulo u8 *id_server; 29f05cddf9SRui Paulo size_t id_server_len; 30f05cddf9SRui Paulo u8 *password; 31f05cddf9SRui Paulo size_t password_len; 32325151a3SRui Paulo int password_hash; 33206b73d0SCy Schubert struct wpa_freq_range_list allowed_groups; 34f05cddf9SRui Paulo u16 group_num; 3585732ac8SCy Schubert u8 prep; 3685732ac8SCy Schubert u8 token[4]; 37f05cddf9SRui Paulo EAP_PWD_group *grp; 38f05cddf9SRui Paulo 39f05cddf9SRui Paulo struct wpabuf *inbuf; 40f05cddf9SRui Paulo size_t in_frag_pos; 41f05cddf9SRui Paulo struct wpabuf *outbuf; 42f05cddf9SRui Paulo size_t out_frag_pos; 43f05cddf9SRui Paulo size_t mtu; 44f05cddf9SRui Paulo 4585732ac8SCy Schubert struct crypto_bignum *k; 4685732ac8SCy Schubert struct crypto_bignum *private_value; 4785732ac8SCy Schubert struct crypto_bignum *server_scalar; 4885732ac8SCy Schubert struct crypto_bignum *my_scalar; 4985732ac8SCy Schubert struct crypto_ec_point *my_element; 5085732ac8SCy Schubert struct crypto_ec_point *server_element; 51f05cddf9SRui Paulo 52f05cddf9SRui Paulo u8 msk[EAP_MSK_LEN]; 53f05cddf9SRui Paulo u8 emsk[EAP_EMSK_LEN]; 545b9c547cSRui Paulo u8 session_id[1 + SHA256_MAC_LEN]; 55f05cddf9SRui Paulo }; 56f05cddf9SRui Paulo 57f05cddf9SRui Paulo 58206b73d0SCy Schubert static void eap_pwd_deinit(struct eap_sm *sm, void *priv); 59206b73d0SCy Schubert 60206b73d0SCy Schubert 61f05cddf9SRui Paulo #ifndef CONFIG_NO_STDOUT_DEBUG 62f05cddf9SRui Paulo static const char * eap_pwd_state_txt(int state) 63f05cddf9SRui Paulo { 64f05cddf9SRui Paulo switch (state) { 65f05cddf9SRui Paulo case PWD_ID_Req: 66f05cddf9SRui Paulo return "PWD-ID-Req"; 67f05cddf9SRui Paulo case PWD_Commit_Req: 68f05cddf9SRui Paulo return "PWD-Commit-Req"; 69f05cddf9SRui Paulo case PWD_Confirm_Req: 70f05cddf9SRui Paulo return "PWD-Confirm-Req"; 715b9c547cSRui Paulo case SUCCESS_ON_FRAG_COMPLETION: 725b9c547cSRui Paulo return "SUCCESS_ON_FRAG_COMPLETION"; 73f05cddf9SRui Paulo case SUCCESS: 74f05cddf9SRui Paulo return "SUCCESS"; 75f05cddf9SRui Paulo case FAILURE: 76f05cddf9SRui Paulo return "FAILURE"; 77f05cddf9SRui Paulo default: 78f05cddf9SRui Paulo return "PWD-UNK"; 79f05cddf9SRui Paulo } 80f05cddf9SRui Paulo } 81f05cddf9SRui Paulo #endif /* CONFIG_NO_STDOUT_DEBUG */ 82f05cddf9SRui Paulo 83f05cddf9SRui Paulo 84f05cddf9SRui Paulo static void eap_pwd_state(struct eap_pwd_data *data, int state) 85f05cddf9SRui Paulo { 86f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "EAP-PWD: %s -> %s", 87f05cddf9SRui Paulo eap_pwd_state_txt(data->state), eap_pwd_state_txt(state)); 88f05cddf9SRui Paulo data->state = state; 89f05cddf9SRui Paulo } 90f05cddf9SRui Paulo 91f05cddf9SRui Paulo 92f05cddf9SRui Paulo static void * eap_pwd_init(struct eap_sm *sm) 93f05cddf9SRui Paulo { 94f05cddf9SRui Paulo struct eap_pwd_data *data; 95f05cddf9SRui Paulo const u8 *identity, *password; 96f05cddf9SRui Paulo size_t identity_len, password_len; 975b9c547cSRui Paulo int fragment_size; 98325151a3SRui Paulo int pwhash; 99206b73d0SCy Schubert const char *phase1; 100f05cddf9SRui Paulo 101325151a3SRui Paulo password = eap_get_config_password2(sm, &password_len, &pwhash); 102f05cddf9SRui Paulo if (password == NULL) { 103f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-PWD: No password configured!"); 104f05cddf9SRui Paulo return NULL; 105f05cddf9SRui Paulo } 106f05cddf9SRui Paulo 107f05cddf9SRui Paulo identity = eap_get_config_identity(sm, &identity_len); 108f05cddf9SRui Paulo if (identity == NULL) { 109f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-PWD: No identity configured!"); 110f05cddf9SRui Paulo return NULL; 111f05cddf9SRui Paulo } 112f05cddf9SRui Paulo 113f05cddf9SRui Paulo if ((data = os_zalloc(sizeof(*data))) == NULL) { 114f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-PWD: memory allocation data fail"); 115f05cddf9SRui Paulo return NULL; 116f05cddf9SRui Paulo } 117f05cddf9SRui Paulo 118f05cddf9SRui Paulo if ((data->id_peer = os_malloc(identity_len)) == NULL) { 119f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail"); 120f05cddf9SRui Paulo os_free(data); 121f05cddf9SRui Paulo return NULL; 122f05cddf9SRui Paulo } 123f05cddf9SRui Paulo 124f05cddf9SRui Paulo os_memcpy(data->id_peer, identity, identity_len); 125f05cddf9SRui Paulo data->id_peer_len = identity_len; 126f05cddf9SRui Paulo 127f05cddf9SRui Paulo if ((data->password = os_malloc(password_len)) == NULL) { 128f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-PWD: memory allocation psk fail"); 1295b9c547cSRui Paulo bin_clear_free(data->id_peer, data->id_peer_len); 130f05cddf9SRui Paulo os_free(data); 131f05cddf9SRui Paulo return NULL; 132f05cddf9SRui Paulo } 133f05cddf9SRui Paulo os_memcpy(data->password, password, password_len); 134f05cddf9SRui Paulo data->password_len = password_len; 135325151a3SRui Paulo data->password_hash = pwhash; 136f05cddf9SRui Paulo 137206b73d0SCy Schubert phase1 = eap_get_config_phase1(sm); 138206b73d0SCy Schubert if (phase1) { 139206b73d0SCy Schubert const char *pos, *end; 140206b73d0SCy Schubert char *copy = NULL; 141206b73d0SCy Schubert int res; 142206b73d0SCy Schubert 143206b73d0SCy Schubert pos = os_strstr(phase1, "eap_pwd_groups="); 144206b73d0SCy Schubert if (pos) { 145206b73d0SCy Schubert pos += 15; 146206b73d0SCy Schubert end = os_strchr(pos, ' '); 147206b73d0SCy Schubert if (end) { 148206b73d0SCy Schubert copy = os_zalloc(end - pos + 1); 149206b73d0SCy Schubert if (!copy) 150206b73d0SCy Schubert goto fail; 151206b73d0SCy Schubert os_memcpy(copy, pos, end - pos); 152206b73d0SCy Schubert pos = copy; 153206b73d0SCy Schubert } 154206b73d0SCy Schubert res = freq_range_list_parse(&data->allowed_groups, pos); 155206b73d0SCy Schubert os_free(copy); 156206b73d0SCy Schubert if (res) 157206b73d0SCy Schubert goto fail; 158206b73d0SCy Schubert } 159206b73d0SCy Schubert } 160206b73d0SCy Schubert 161f05cddf9SRui Paulo data->out_frag_pos = data->in_frag_pos = 0; 162f05cddf9SRui Paulo data->inbuf = data->outbuf = NULL; 1635b9c547cSRui Paulo fragment_size = eap_get_config_fragment_size(sm); 1645b9c547cSRui Paulo if (fragment_size <= 0) 1655b9c547cSRui Paulo data->mtu = 1020; /* default from RFC 5931 */ 1665b9c547cSRui Paulo else 1675b9c547cSRui Paulo data->mtu = fragment_size; 168f05cddf9SRui Paulo 169f05cddf9SRui Paulo data->state = PWD_ID_Req; 170f05cddf9SRui Paulo 171f05cddf9SRui Paulo return data; 172206b73d0SCy Schubert fail: 173206b73d0SCy Schubert eap_pwd_deinit(sm, data); 174206b73d0SCy Schubert return NULL; 175f05cddf9SRui Paulo } 176f05cddf9SRui Paulo 177f05cddf9SRui Paulo 178f05cddf9SRui Paulo static void eap_pwd_deinit(struct eap_sm *sm, void *priv) 179f05cddf9SRui Paulo { 180f05cddf9SRui Paulo struct eap_pwd_data *data = priv; 181f05cddf9SRui Paulo 18285732ac8SCy Schubert crypto_bignum_deinit(data->private_value, 1); 18385732ac8SCy Schubert crypto_bignum_deinit(data->server_scalar, 1); 18485732ac8SCy Schubert crypto_bignum_deinit(data->my_scalar, 1); 18585732ac8SCy Schubert crypto_bignum_deinit(data->k, 1); 18685732ac8SCy Schubert crypto_ec_point_deinit(data->my_element, 1); 18785732ac8SCy Schubert crypto_ec_point_deinit(data->server_element, 1); 1885b9c547cSRui Paulo bin_clear_free(data->id_peer, data->id_peer_len); 1895b9c547cSRui Paulo bin_clear_free(data->id_server, data->id_server_len); 1905b9c547cSRui Paulo bin_clear_free(data->password, data->password_len); 191f05cddf9SRui Paulo if (data->grp) { 19285732ac8SCy Schubert crypto_ec_deinit(data->grp->group); 19385732ac8SCy Schubert crypto_ec_point_deinit(data->grp->pwe, 1); 194f05cddf9SRui Paulo os_free(data->grp); 195f05cddf9SRui Paulo } 1965b9c547cSRui Paulo wpabuf_free(data->inbuf); 1975b9c547cSRui Paulo wpabuf_free(data->outbuf); 198206b73d0SCy Schubert os_free(data->allowed_groups.range); 1995b9c547cSRui Paulo bin_clear_free(data, sizeof(*data)); 200f05cddf9SRui Paulo } 201f05cddf9SRui Paulo 202f05cddf9SRui Paulo 203f05cddf9SRui Paulo static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len) 204f05cddf9SRui Paulo { 205f05cddf9SRui Paulo struct eap_pwd_data *data = priv; 206f05cddf9SRui Paulo u8 *key; 207f05cddf9SRui Paulo 208f05cddf9SRui Paulo if (data->state != SUCCESS) 209f05cddf9SRui Paulo return NULL; 210f05cddf9SRui Paulo 21185732ac8SCy Schubert key = os_memdup(data->msk, EAP_MSK_LEN); 212f05cddf9SRui Paulo if (key == NULL) 213f05cddf9SRui Paulo return NULL; 214f05cddf9SRui Paulo 215f05cddf9SRui Paulo *len = EAP_MSK_LEN; 216f05cddf9SRui Paulo 217f05cddf9SRui Paulo return key; 218f05cddf9SRui Paulo } 219f05cddf9SRui Paulo 220f05cddf9SRui Paulo 2215b9c547cSRui Paulo static u8 * eap_pwd_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 2225b9c547cSRui Paulo { 2235b9c547cSRui Paulo struct eap_pwd_data *data = priv; 2245b9c547cSRui Paulo u8 *id; 2255b9c547cSRui Paulo 2265b9c547cSRui Paulo if (data->state != SUCCESS) 2275b9c547cSRui Paulo return NULL; 2285b9c547cSRui Paulo 22985732ac8SCy Schubert id = os_memdup(data->session_id, 1 + SHA256_MAC_LEN); 2305b9c547cSRui Paulo if (id == NULL) 2315b9c547cSRui Paulo return NULL; 2325b9c547cSRui Paulo 2335b9c547cSRui Paulo *len = 1 + SHA256_MAC_LEN; 2345b9c547cSRui Paulo 2355b9c547cSRui Paulo return id; 2365b9c547cSRui Paulo } 2375b9c547cSRui Paulo 2385b9c547cSRui Paulo 239206b73d0SCy Schubert static int eap_pwd_allowed_group(struct eap_pwd_data *data, u16 group) 240206b73d0SCy Schubert { 241206b73d0SCy Schubert if (!data->allowed_groups.range) { 242206b73d0SCy Schubert /* By default, allow the groups using NIST curves P-256, P-384, 243206b73d0SCy Schubert * and P-521. */ 244206b73d0SCy Schubert return group == 19 || group == 20 || group == 21; 245206b73d0SCy Schubert } 246206b73d0SCy Schubert 247206b73d0SCy Schubert return freq_range_list_includes(&data->allowed_groups, group); 248206b73d0SCy Schubert } 249206b73d0SCy Schubert 250206b73d0SCy Schubert 251f05cddf9SRui Paulo static void 252f05cddf9SRui Paulo eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data, 253f05cddf9SRui Paulo struct eap_method_ret *ret, 254f05cddf9SRui Paulo const struct wpabuf *reqData, 255f05cddf9SRui Paulo const u8 *payload, size_t payload_len) 256f05cddf9SRui Paulo { 257f05cddf9SRui Paulo struct eap_pwd_id *id; 258f05cddf9SRui Paulo 259f05cddf9SRui Paulo if (data->state != PWD_ID_Req) { 260c1d255d3SCy Schubert ret->ignore = true; 261f05cddf9SRui Paulo eap_pwd_state(data, FAILURE); 262f05cddf9SRui Paulo return; 263f05cddf9SRui Paulo } 264f05cddf9SRui Paulo 265f05cddf9SRui Paulo if (payload_len < sizeof(struct eap_pwd_id)) { 266c1d255d3SCy Schubert ret->ignore = true; 267f05cddf9SRui Paulo eap_pwd_state(data, FAILURE); 268f05cddf9SRui Paulo return; 269f05cddf9SRui Paulo } 270f05cddf9SRui Paulo 271f05cddf9SRui Paulo id = (struct eap_pwd_id *) payload; 272f05cddf9SRui Paulo data->group_num = be_to_host16(id->group_num); 273325151a3SRui Paulo wpa_printf(MSG_DEBUG, 274325151a3SRui Paulo "EAP-PWD: Server EAP-pwd-ID proposal: group=%u random=%u prf=%u prep=%u", 275325151a3SRui Paulo data->group_num, id->random_function, id->prf, id->prep); 276206b73d0SCy Schubert if (id->random_function != EAP_PWD_DEFAULT_RAND_FUNC || 277206b73d0SCy Schubert id->prf != EAP_PWD_DEFAULT_PRF || 278206b73d0SCy Schubert !eap_pwd_allowed_group(data, data->group_num)) { 279206b73d0SCy Schubert wpa_printf(MSG_INFO, 280206b73d0SCy Schubert "EAP-pwd: Unsupported or disabled proposal"); 281f05cddf9SRui Paulo eap_pwd_state(data, FAILURE); 282f05cddf9SRui Paulo return; 283f05cddf9SRui Paulo } 284f05cddf9SRui Paulo 285325151a3SRui Paulo if (id->prep != EAP_PWD_PREP_NONE && 28685732ac8SCy Schubert id->prep != EAP_PWD_PREP_MS && 28785732ac8SCy Schubert id->prep != EAP_PWD_PREP_SSHA1 && 28885732ac8SCy Schubert id->prep != EAP_PWD_PREP_SSHA256 && 28985732ac8SCy Schubert id->prep != EAP_PWD_PREP_SSHA512) { 290325151a3SRui Paulo wpa_printf(MSG_DEBUG, 291325151a3SRui Paulo "EAP-PWD: Unsupported password pre-processing technique (Prep=%u)", 292325151a3SRui Paulo id->prep); 293325151a3SRui Paulo eap_pwd_state(data, FAILURE); 294325151a3SRui Paulo return; 295325151a3SRui Paulo } 296325151a3SRui Paulo 297325151a3SRui Paulo if (id->prep == EAP_PWD_PREP_NONE && data->password_hash) { 298325151a3SRui Paulo wpa_printf(MSG_DEBUG, 299325151a3SRui Paulo "EAP-PWD: Unhashed password not available"); 300325151a3SRui Paulo eap_pwd_state(data, FAILURE); 301325151a3SRui Paulo return; 302325151a3SRui Paulo } 303325151a3SRui Paulo 304f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "EAP-PWD (peer): using group %d", 305f05cddf9SRui Paulo data->group_num); 306f05cddf9SRui Paulo 30785732ac8SCy Schubert data->prep = id->prep; 30885732ac8SCy Schubert os_memcpy(data->token, id->token, sizeof(id->token)); 30985732ac8SCy Schubert 31085732ac8SCy Schubert if (data->id_server || data->grp) { 31185732ac8SCy Schubert wpa_printf(MSG_INFO, "EAP-pwd: data was already allocated"); 31285732ac8SCy Schubert eap_pwd_state(data, FAILURE); 31385732ac8SCy Schubert return; 31485732ac8SCy Schubert } 31585732ac8SCy Schubert 316f05cddf9SRui Paulo data->id_server = os_malloc(payload_len - sizeof(struct eap_pwd_id)); 317f05cddf9SRui Paulo if (data->id_server == NULL) { 318f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail"); 319f05cddf9SRui Paulo eap_pwd_state(data, FAILURE); 320f05cddf9SRui Paulo return; 321f05cddf9SRui Paulo } 322f05cddf9SRui Paulo data->id_server_len = payload_len - sizeof(struct eap_pwd_id); 323f05cddf9SRui Paulo os_memcpy(data->id_server, id->identity, data->id_server_len); 324f05cddf9SRui Paulo wpa_hexdump_ascii(MSG_INFO, "EAP-PWD (peer): server sent id of", 325f05cddf9SRui Paulo data->id_server, data->id_server_len); 326f05cddf9SRui Paulo 32785732ac8SCy Schubert data->grp = get_eap_pwd_group(data->group_num); 3285b9c547cSRui Paulo if (data->grp == NULL) { 329f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for " 330f05cddf9SRui Paulo "group"); 331f05cddf9SRui Paulo eap_pwd_state(data, FAILURE); 332f05cddf9SRui Paulo return; 333f05cddf9SRui Paulo } 334f05cddf9SRui Paulo 33585732ac8SCy Schubert data->outbuf = wpabuf_alloc(sizeof(struct eap_pwd_id) + 33685732ac8SCy Schubert data->id_peer_len); 33785732ac8SCy Schubert if (data->outbuf == NULL) { 33885732ac8SCy Schubert eap_pwd_state(data, FAILURE); 33985732ac8SCy Schubert return; 34085732ac8SCy Schubert } 34185732ac8SCy Schubert wpabuf_put_be16(data->outbuf, data->group_num); 34285732ac8SCy Schubert wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_RAND_FUNC); 34385732ac8SCy Schubert wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_PRF); 34485732ac8SCy Schubert wpabuf_put_data(data->outbuf, id->token, sizeof(id->token)); 34585732ac8SCy Schubert wpabuf_put_u8(data->outbuf, id->prep); 34685732ac8SCy Schubert wpabuf_put_data(data->outbuf, data->id_peer, data->id_peer_len); 34785732ac8SCy Schubert 34885732ac8SCy Schubert eap_pwd_state(data, PWD_Commit_Req); 34985732ac8SCy Schubert } 35085732ac8SCy Schubert 35185732ac8SCy Schubert 35285732ac8SCy Schubert static void 35385732ac8SCy Schubert eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data, 35485732ac8SCy Schubert struct eap_method_ret *ret, 35585732ac8SCy Schubert const struct wpabuf *reqData, 35685732ac8SCy Schubert const u8 *payload, size_t payload_len) 35785732ac8SCy Schubert { 3584bc52338SCy Schubert struct crypto_ec_point *K = NULL; 3594bc52338SCy Schubert struct crypto_bignum *mask = NULL; 36085732ac8SCy Schubert const u8 *ptr = payload; 3614bc52338SCy Schubert u8 *scalar, *element; 36285732ac8SCy Schubert size_t prime_len, order_len; 36385732ac8SCy Schubert const u8 *password; 36485732ac8SCy Schubert size_t password_len; 36585732ac8SCy Schubert u8 pwhashhash[16]; 36685732ac8SCy Schubert const u8 *salt_pwd[2]; 36785732ac8SCy Schubert size_t salt_pwd_len[2], exp_len; 36885732ac8SCy Schubert u8 salt_len, salthashpwd[64]; /* 64 = SHA512_DIGEST_LENGTH */ 36985732ac8SCy Schubert int res; 37085732ac8SCy Schubert 37185732ac8SCy Schubert if (data->state != PWD_Commit_Req) { 372c1d255d3SCy Schubert ret->ignore = true; 37385732ac8SCy Schubert goto fin; 37485732ac8SCy Schubert } 37585732ac8SCy Schubert 37685732ac8SCy Schubert if (!data->grp) { 37785732ac8SCy Schubert wpa_printf(MSG_DEBUG, 37885732ac8SCy Schubert "EAP-PWD (client): uninitialized EAP-pwd group"); 379c1d255d3SCy Schubert ret->ignore = true; 38085732ac8SCy Schubert goto fin; 38185732ac8SCy Schubert } 38285732ac8SCy Schubert 38385732ac8SCy Schubert prime_len = crypto_ec_prime_len(data->grp->group); 38485732ac8SCy Schubert order_len = crypto_ec_order_len(data->grp->group); 38585732ac8SCy Schubert 38685732ac8SCy Schubert switch (data->prep) { 38785732ac8SCy Schubert case EAP_PWD_PREP_MS: 38885732ac8SCy Schubert wpa_printf(MSG_DEBUG, 38985732ac8SCy Schubert "EAP-pwd commit request, password prep is MS"); 390325151a3SRui Paulo #ifdef CONFIG_FIPS 391325151a3SRui Paulo wpa_printf(MSG_ERROR, 392325151a3SRui Paulo "EAP-PWD (peer): MS password hash not supported in FIPS mode"); 393325151a3SRui Paulo eap_pwd_state(data, FAILURE); 394325151a3SRui Paulo return; 395325151a3SRui Paulo #else /* CONFIG_FIPS */ 39685732ac8SCy Schubert if (payload_len != 2 * prime_len + order_len) { 39785732ac8SCy Schubert wpa_printf(MSG_INFO, 39885732ac8SCy Schubert "EAP-pwd: Unexpected Commit payload length %u (expected %u)", 39985732ac8SCy Schubert (unsigned int) payload_len, 40085732ac8SCy Schubert (unsigned int) (2 * prime_len + order_len)); 40185732ac8SCy Schubert goto fin; 40285732ac8SCy Schubert } 403325151a3SRui Paulo if (data->password_hash) { 404325151a3SRui Paulo res = hash_nt_password_hash(data->password, pwhashhash); 405325151a3SRui Paulo } else { 406325151a3SRui Paulo u8 pwhash[16]; 407325151a3SRui Paulo 408325151a3SRui Paulo res = nt_password_hash(data->password, 409325151a3SRui Paulo data->password_len, pwhash); 410325151a3SRui Paulo if (res == 0) 411325151a3SRui Paulo res = hash_nt_password_hash(pwhash, pwhashhash); 412206b73d0SCy Schubert forced_memzero(pwhash, sizeof(pwhash)); 413325151a3SRui Paulo } 414325151a3SRui Paulo 415325151a3SRui Paulo if (res) { 416325151a3SRui Paulo eap_pwd_state(data, FAILURE); 417325151a3SRui Paulo return; 418325151a3SRui Paulo } 419325151a3SRui Paulo 420325151a3SRui Paulo password = pwhashhash; 421325151a3SRui Paulo password_len = sizeof(pwhashhash); 422325151a3SRui Paulo #endif /* CONFIG_FIPS */ 42385732ac8SCy Schubert break; 42485732ac8SCy Schubert case EAP_PWD_PREP_SSHA1: 42585732ac8SCy Schubert wpa_printf(MSG_DEBUG, 42685732ac8SCy Schubert "EAP-pwd commit request, password prep is salted sha1"); 42785732ac8SCy Schubert if (payload_len < 1 || *ptr == 0) { 42885732ac8SCy Schubert wpa_printf(MSG_DEBUG, "EAP-pwd: Invalid Salt-len"); 42985732ac8SCy Schubert goto fin; 430325151a3SRui Paulo } 43185732ac8SCy Schubert salt_len = *ptr++; 43285732ac8SCy Schubert exp_len = 1 + salt_len + 2 * prime_len + order_len; 43385732ac8SCy Schubert if (payload_len != exp_len) { 43485732ac8SCy Schubert wpa_printf(MSG_INFO, 43585732ac8SCy Schubert "EAP-pwd: Unexpected Commit payload length %u (expected %u)", 43685732ac8SCy Schubert (unsigned int) payload_len, 43785732ac8SCy Schubert (unsigned int) exp_len); 438325151a3SRui Paulo goto fin; 439325151a3SRui Paulo } 440325151a3SRui Paulo 44185732ac8SCy Schubert /* salted-password = Hash(password | salt) */ 44285732ac8SCy Schubert wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Unsalted password", 44385732ac8SCy Schubert data->password, data->password_len); 44485732ac8SCy Schubert wpa_hexdump(MSG_DEBUG, "EAP-pwd: Salt", ptr, salt_len); 44585732ac8SCy Schubert salt_pwd[0] = data->password; 44685732ac8SCy Schubert salt_pwd[1] = ptr; 44785732ac8SCy Schubert salt_pwd_len[0] = data->password_len; 44885732ac8SCy Schubert salt_pwd_len[1] = salt_len; 44985732ac8SCy Schubert if (sha1_vector(2, salt_pwd, salt_pwd_len, salthashpwd) < 0) 45085732ac8SCy Schubert goto fin; 451325151a3SRui Paulo 45285732ac8SCy Schubert wpa_printf(MSG_DEBUG, 45385732ac8SCy Schubert "EAP-pwd: sha1 hashed %d byte salt with password", 45485732ac8SCy Schubert (int) salt_len); 45585732ac8SCy Schubert ptr += salt_len; 45685732ac8SCy Schubert password = salthashpwd; 45785732ac8SCy Schubert password_len = SHA1_MAC_LEN; 45885732ac8SCy Schubert wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Salted password", 45985732ac8SCy Schubert password, password_len); 46085732ac8SCy Schubert break; 46185732ac8SCy Schubert case EAP_PWD_PREP_SSHA256: 46285732ac8SCy Schubert wpa_printf(MSG_DEBUG, 46385732ac8SCy Schubert "EAP-pwd commit request, password prep is salted sha256"); 46485732ac8SCy Schubert if (payload_len < 1 || *ptr == 0) { 46585732ac8SCy Schubert wpa_printf(MSG_DEBUG, "EAP-pwd: Invalid Salt-len"); 46685732ac8SCy Schubert goto fin; 46785732ac8SCy Schubert } 46885732ac8SCy Schubert salt_len = *ptr++; 46985732ac8SCy Schubert exp_len = 1 + salt_len + 2 * prime_len + order_len; 47085732ac8SCy Schubert if (payload_len != exp_len) { 47185732ac8SCy Schubert wpa_printf(MSG_INFO, 47285732ac8SCy Schubert "EAP-pwd: Unexpected Commit payload length %u (expected %u)", 47385732ac8SCy Schubert (unsigned int) payload_len, 47485732ac8SCy Schubert (unsigned int) exp_len); 47585732ac8SCy Schubert goto fin; 47685732ac8SCy Schubert } 47785732ac8SCy Schubert 47885732ac8SCy Schubert /* salted-password = Hash(password | salt) */ 47985732ac8SCy Schubert wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Unsalted password", 48085732ac8SCy Schubert data->password, data->password_len); 48185732ac8SCy Schubert wpa_hexdump(MSG_DEBUG, "EAP-pwd: Salt", ptr, salt_len); 48285732ac8SCy Schubert salt_pwd[0] = data->password; 48385732ac8SCy Schubert salt_pwd[1] = ptr; 48485732ac8SCy Schubert salt_pwd_len[0] = data->password_len; 48585732ac8SCy Schubert salt_pwd_len[1] = salt_len; 48685732ac8SCy Schubert if (sha256_vector(2, salt_pwd, salt_pwd_len, salthashpwd) < 0) 48785732ac8SCy Schubert goto fin; 48885732ac8SCy Schubert 48985732ac8SCy Schubert ptr += salt_len; 49085732ac8SCy Schubert password = salthashpwd; 49185732ac8SCy Schubert password_len = SHA256_MAC_LEN; 49285732ac8SCy Schubert wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Salted password", 49385732ac8SCy Schubert password, password_len); 49485732ac8SCy Schubert break; 49585732ac8SCy Schubert #ifdef CONFIG_SHA512 49685732ac8SCy Schubert case EAP_PWD_PREP_SSHA512: 49785732ac8SCy Schubert wpa_printf(MSG_DEBUG, 49885732ac8SCy Schubert "EAP-pwd commit request, password prep is salted sha512"); 49985732ac8SCy Schubert if (payload_len < 1 || *ptr == 0) { 50085732ac8SCy Schubert wpa_printf(MSG_DEBUG, "EAP-pwd: Invalid Salt-len"); 50185732ac8SCy Schubert goto fin; 50285732ac8SCy Schubert } 50385732ac8SCy Schubert salt_len = *ptr++; 50485732ac8SCy Schubert exp_len = 1 + salt_len + 2 * prime_len + order_len; 50585732ac8SCy Schubert if (payload_len != exp_len) { 50685732ac8SCy Schubert wpa_printf(MSG_INFO, 50785732ac8SCy Schubert "EAP-pwd: Unexpected Commit payload length %u (expected %u)", 50885732ac8SCy Schubert (unsigned int) payload_len, 50985732ac8SCy Schubert (unsigned int) exp_len); 51085732ac8SCy Schubert goto fin; 51185732ac8SCy Schubert } 51285732ac8SCy Schubert 51385732ac8SCy Schubert /* salted-password = Hash(password | salt) */ 51485732ac8SCy Schubert wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Unsalted password", 51585732ac8SCy Schubert data->password, data->password_len); 51685732ac8SCy Schubert wpa_hexdump(MSG_DEBUG, "EAP-pwd: Salt", ptr, salt_len); 51785732ac8SCy Schubert salt_pwd[0] = data->password; 51885732ac8SCy Schubert salt_pwd[1] = ptr; 51985732ac8SCy Schubert salt_pwd_len[0] = data->password_len; 52085732ac8SCy Schubert salt_pwd_len[1] = salt_len; 52185732ac8SCy Schubert if (sha512_vector(2, salt_pwd, salt_pwd_len, salthashpwd) < 0) 52285732ac8SCy Schubert goto fin; 52385732ac8SCy Schubert 52485732ac8SCy Schubert ptr += salt_len; 52585732ac8SCy Schubert password = salthashpwd; 52685732ac8SCy Schubert password_len = SHA512_MAC_LEN; 52785732ac8SCy Schubert wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Salted password", 52885732ac8SCy Schubert password, password_len); 52985732ac8SCy Schubert break; 53085732ac8SCy Schubert #endif /* CONFIG_SHA512 */ 53185732ac8SCy Schubert case EAP_PWD_PREP_NONE: 53285732ac8SCy Schubert wpa_printf(MSG_DEBUG, 53385732ac8SCy Schubert "EAP-pwd commit request, password prep is NONE"); 53485732ac8SCy Schubert if (data->password_hash) { 53585732ac8SCy Schubert wpa_printf(MSG_DEBUG, 53685732ac8SCy Schubert "EAP-PWD: Unhashed password not available"); 53785732ac8SCy Schubert eap_pwd_state(data, FAILURE); 53885732ac8SCy Schubert return; 53985732ac8SCy Schubert } 540325151a3SRui Paulo if (payload_len != 2 * prime_len + order_len) { 541325151a3SRui Paulo wpa_printf(MSG_INFO, 542325151a3SRui Paulo "EAP-pwd: Unexpected Commit payload length %u (expected %u)", 543325151a3SRui Paulo (unsigned int) payload_len, 544325151a3SRui Paulo (unsigned int) (2 * prime_len + order_len)); 545325151a3SRui Paulo goto fin; 546325151a3SRui Paulo } 54785732ac8SCy Schubert password = data->password; 54885732ac8SCy Schubert password_len = data->password_len; 54985732ac8SCy Schubert break; 55085732ac8SCy Schubert default: 55185732ac8SCy Schubert wpa_printf(MSG_DEBUG, 55285732ac8SCy Schubert "EAP-pwd: Unsupported password pre-processing technique (Prep=%u)", 55385732ac8SCy Schubert data->prep); 55485732ac8SCy Schubert eap_pwd_state(data, FAILURE); 55585732ac8SCy Schubert return; 55685732ac8SCy Schubert } 557f05cddf9SRui Paulo 55885732ac8SCy Schubert /* compute PWE */ 55985732ac8SCy Schubert res = compute_password_element(data->grp, data->group_num, 56085732ac8SCy Schubert password, password_len, 56185732ac8SCy Schubert data->id_server, data->id_server_len, 56285732ac8SCy Schubert data->id_peer, data->id_peer_len, 56385732ac8SCy Schubert data->token); 564206b73d0SCy Schubert forced_memzero(pwhashhash, sizeof(pwhashhash)); 565206b73d0SCy Schubert forced_memzero(salthashpwd, sizeof(salthashpwd)); 56685732ac8SCy Schubert if (res) { 56785732ac8SCy Schubert wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute PWE"); 56885732ac8SCy Schubert eap_pwd_state(data, FAILURE); 56985732ac8SCy Schubert return; 57085732ac8SCy Schubert } 57185732ac8SCy Schubert 57285732ac8SCy Schubert wpa_printf(MSG_DEBUG, "EAP-PWD (peer): computed %d bit PWE...", 57385732ac8SCy Schubert (int) crypto_ec_prime_len_bits(data->grp->group)); 57485732ac8SCy Schubert 57585732ac8SCy Schubert data->private_value = crypto_bignum_init(); 57685732ac8SCy Schubert data->my_element = crypto_ec_point_init(data->grp->group); 57785732ac8SCy Schubert data->my_scalar = crypto_bignum_init(); 57885732ac8SCy Schubert mask = crypto_bignum_init(); 5794bc52338SCy Schubert if (!data->private_value || !data->my_element || 58085732ac8SCy Schubert !data->my_scalar || !mask) { 581f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-PWD (peer): scalar allocation fail"); 582f05cddf9SRui Paulo goto fin; 583f05cddf9SRui Paulo } 584f05cddf9SRui Paulo 5854bc52338SCy Schubert if (eap_pwd_get_rand_mask(data->grp, data->private_value, mask, 5864bc52338SCy Schubert data->my_scalar) < 0) 587f05cddf9SRui Paulo goto fin; 588f05cddf9SRui Paulo 58985732ac8SCy Schubert if (crypto_ec_point_mul(data->grp->group, data->grp->pwe, mask, 59085732ac8SCy Schubert data->my_element) < 0) { 591f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-PWD (peer): element allocation " 592f05cddf9SRui Paulo "fail"); 593f05cddf9SRui Paulo eap_pwd_state(data, FAILURE); 594f05cddf9SRui Paulo goto fin; 595f05cddf9SRui Paulo } 596f05cddf9SRui Paulo 59785732ac8SCy Schubert if (crypto_ec_point_invert(data->grp->group, data->my_element) < 0) { 598f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-PWD (peer): element inversion fail"); 599f05cddf9SRui Paulo goto fin; 600f05cddf9SRui Paulo } 601f05cddf9SRui Paulo 602f05cddf9SRui Paulo /* process the request */ 60385732ac8SCy Schubert data->k = crypto_bignum_init(); 60485732ac8SCy Schubert K = crypto_ec_point_init(data->grp->group); 6054bc52338SCy Schubert if (!data->k || !K) { 606f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-PWD (peer): peer data allocation " 607f05cddf9SRui Paulo "fail"); 608f05cddf9SRui Paulo goto fin; 609f05cddf9SRui Paulo } 610f05cddf9SRui Paulo 611f05cddf9SRui Paulo /* element, x then y, followed by scalar */ 6124bc52338SCy Schubert data->server_element = eap_pwd_get_element(data->grp, ptr); 61385732ac8SCy Schubert if (!data->server_element) { 614f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-PWD (peer): setting peer element " 615f05cddf9SRui Paulo "fail"); 616f05cddf9SRui Paulo goto fin; 617f05cddf9SRui Paulo } 61885732ac8SCy Schubert ptr += prime_len * 2; 6194bc52338SCy Schubert data->server_scalar = eap_pwd_get_scalar(data->grp, ptr); 62085732ac8SCy Schubert if (!data->server_scalar) { 62185732ac8SCy Schubert wpa_printf(MSG_INFO, 62285732ac8SCy Schubert "EAP-PWD (peer): setting peer scalar fail"); 62385732ac8SCy Schubert goto fin; 62485732ac8SCy Schubert } 625f05cddf9SRui Paulo 626f05cddf9SRui Paulo /* compute the shared key, k */ 62785732ac8SCy Schubert if (crypto_ec_point_mul(data->grp->group, data->grp->pwe, 62885732ac8SCy Schubert data->server_scalar, K) < 0 || 62985732ac8SCy Schubert crypto_ec_point_add(data->grp->group, K, data->server_element, 63085732ac8SCy Schubert K) < 0 || 63185732ac8SCy Schubert crypto_ec_point_mul(data->grp->group, K, data->private_value, 63285732ac8SCy Schubert K) < 0) { 633f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-PWD (peer): computing shared key " 634f05cddf9SRui Paulo "fail"); 635f05cddf9SRui Paulo goto fin; 636f05cddf9SRui Paulo } 637f05cddf9SRui Paulo 638f05cddf9SRui Paulo /* 6394bc52338SCy Schubert * This check is strictly speaking just for the case where 640f05cddf9SRui Paulo * co-factor > 1 but it was suggested that even though this is probably 641f05cddf9SRui Paulo * never going to happen it is a simple and safe check "just to be 642f05cddf9SRui Paulo * sure" so let's be safe. 643f05cddf9SRui Paulo */ 64485732ac8SCy Schubert if (crypto_ec_point_is_at_infinity(data->grp->group, K)) { 645f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-PWD (peer): shared key point is at " 646f05cddf9SRui Paulo "infinity!\n"); 647f05cddf9SRui Paulo goto fin; 648f05cddf9SRui Paulo } 649f05cddf9SRui Paulo 65085732ac8SCy Schubert if (crypto_ec_point_x(data->grp->group, K, data->k) < 0) { 651f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to extract " 652f05cddf9SRui Paulo "shared secret from point"); 653f05cddf9SRui Paulo goto fin; 654f05cddf9SRui Paulo } 655f05cddf9SRui Paulo 656f05cddf9SRui Paulo /* now do the response */ 6574bc52338SCy Schubert data->outbuf = wpabuf_alloc(2 * prime_len + order_len); 6584bc52338SCy Schubert if (data->outbuf == NULL) 659f05cddf9SRui Paulo goto fin; 6604bc52338SCy Schubert /* We send the element as (x,y) followed by the scalar */ 6614bc52338SCy Schubert element = wpabuf_put(data->outbuf, 2 * prime_len); 6624bc52338SCy Schubert scalar = wpabuf_put(data->outbuf, order_len); 663f05cddf9SRui Paulo 664f05cddf9SRui Paulo /* 665f05cddf9SRui Paulo * bignums occupy as little memory as possible so one that is 666f05cddf9SRui Paulo * sufficiently smaller than the prime or order might need pre-pending 667f05cddf9SRui Paulo * with zeros. 668f05cddf9SRui Paulo */ 669*a90b9d01SCy Schubert if (crypto_bignum_to_bin(data->my_scalar, scalar, order_len, 670*a90b9d01SCy Schubert order_len) < 0) 671*a90b9d01SCy Schubert goto fin; 672*a90b9d01SCy Schubert 67385732ac8SCy Schubert if (crypto_ec_point_to_bin(data->grp->group, data->my_element, element, 67485732ac8SCy Schubert element + prime_len) != 0) { 67585732ac8SCy Schubert wpa_printf(MSG_INFO, "EAP-PWD (peer): point assignment fail"); 67685732ac8SCy Schubert goto fin; 67785732ac8SCy Schubert } 678f05cddf9SRui Paulo 679f05cddf9SRui Paulo fin: 68085732ac8SCy Schubert crypto_bignum_deinit(mask, 1); 68185732ac8SCy Schubert crypto_ec_point_deinit(K, 1); 682f05cddf9SRui Paulo if (data->outbuf == NULL) 683f05cddf9SRui Paulo eap_pwd_state(data, FAILURE); 684f05cddf9SRui Paulo else 685f05cddf9SRui Paulo eap_pwd_state(data, PWD_Confirm_Req); 686f05cddf9SRui Paulo } 687f05cddf9SRui Paulo 688f05cddf9SRui Paulo 689f05cddf9SRui Paulo static void 690f05cddf9SRui Paulo eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, 691f05cddf9SRui Paulo struct eap_method_ret *ret, 692f05cddf9SRui Paulo const struct wpabuf *reqData, 693f05cddf9SRui Paulo const u8 *payload, size_t payload_len) 694f05cddf9SRui Paulo { 69585732ac8SCy Schubert struct crypto_hash *hash = NULL; 696f05cddf9SRui Paulo u32 cs; 697f05cddf9SRui Paulo u16 grp; 698f05cddf9SRui Paulo u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr; 69985732ac8SCy Schubert size_t prime_len = 0, order_len = 0; 700f05cddf9SRui Paulo 701325151a3SRui Paulo if (data->state != PWD_Confirm_Req) { 702c1d255d3SCy Schubert ret->ignore = true; 703325151a3SRui Paulo goto fin; 704325151a3SRui Paulo } 705325151a3SRui Paulo 706325151a3SRui Paulo if (payload_len != SHA256_MAC_LEN) { 707325151a3SRui Paulo wpa_printf(MSG_INFO, 708325151a3SRui Paulo "EAP-pwd: Unexpected Confirm payload length %u (expected %u)", 709325151a3SRui Paulo (unsigned int) payload_len, SHA256_MAC_LEN); 710325151a3SRui Paulo goto fin; 711325151a3SRui Paulo } 712325151a3SRui Paulo 71385732ac8SCy Schubert prime_len = crypto_ec_prime_len(data->grp->group); 71485732ac8SCy Schubert order_len = crypto_ec_order_len(data->grp->group); 71585732ac8SCy Schubert 716f05cddf9SRui Paulo /* 717f05cddf9SRui Paulo * first build up the ciphersuite which is group | random_function | 718f05cddf9SRui Paulo * prf 719f05cddf9SRui Paulo */ 720f05cddf9SRui Paulo grp = htons(data->group_num); 721f05cddf9SRui Paulo ptr = (u8 *) &cs; 722f05cddf9SRui Paulo os_memcpy(ptr, &grp, sizeof(u16)); 723f05cddf9SRui Paulo ptr += sizeof(u16); 724f05cddf9SRui Paulo *ptr = EAP_PWD_DEFAULT_RAND_FUNC; 725f05cddf9SRui Paulo ptr += sizeof(u8); 726f05cddf9SRui Paulo *ptr = EAP_PWD_DEFAULT_PRF; 727f05cddf9SRui Paulo 72885732ac8SCy Schubert /* each component of the point will be at most as big as the prime */ 72985732ac8SCy Schubert cruft = os_malloc(prime_len * 2); 73085732ac8SCy Schubert if (!cruft) { 731f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-PWD (server): confirm allocation " 732f05cddf9SRui Paulo "fail"); 733f05cddf9SRui Paulo goto fin; 734f05cddf9SRui Paulo } 735f05cddf9SRui Paulo 736f05cddf9SRui Paulo /* 737f05cddf9SRui Paulo * server's commit is H(k | server_element | server_scalar | 738f05cddf9SRui Paulo * peer_element | peer_scalar | ciphersuite) 739f05cddf9SRui Paulo */ 740f05cddf9SRui Paulo hash = eap_pwd_h_init(); 741f05cddf9SRui Paulo if (hash == NULL) 742f05cddf9SRui Paulo goto fin; 743f05cddf9SRui Paulo 744f05cddf9SRui Paulo /* 745f05cddf9SRui Paulo * zero the memory each time because this is mod prime math and some 746f05cddf9SRui Paulo * value may start with a few zeros and the previous one did not. 747f05cddf9SRui Paulo */ 748*a90b9d01SCy Schubert if (crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len) < 0) 749*a90b9d01SCy Schubert goto fin; 750*a90b9d01SCy Schubert 75185732ac8SCy Schubert eap_pwd_h_update(hash, cruft, prime_len); 752f05cddf9SRui Paulo 753f05cddf9SRui Paulo /* server element: x, y */ 75485732ac8SCy Schubert if (crypto_ec_point_to_bin(data->grp->group, data->server_element, 75585732ac8SCy Schubert cruft, cruft + prime_len) != 0) { 756f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " 757f05cddf9SRui Paulo "assignment fail"); 758f05cddf9SRui Paulo goto fin; 759f05cddf9SRui Paulo } 76085732ac8SCy Schubert eap_pwd_h_update(hash, cruft, prime_len * 2); 761f05cddf9SRui Paulo 762f05cddf9SRui Paulo /* server scalar */ 763*a90b9d01SCy Schubert if (crypto_bignum_to_bin(data->server_scalar, cruft, order_len, 764*a90b9d01SCy Schubert order_len) < 0) 765*a90b9d01SCy Schubert goto fin; 766*a90b9d01SCy Schubert 76785732ac8SCy Schubert eap_pwd_h_update(hash, cruft, order_len); 768f05cddf9SRui Paulo 769f05cddf9SRui Paulo /* my element: x, y */ 77085732ac8SCy Schubert if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft, 77185732ac8SCy Schubert cruft + prime_len) != 0) { 772f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " 773f05cddf9SRui Paulo "assignment fail"); 774f05cddf9SRui Paulo goto fin; 775f05cddf9SRui Paulo } 77685732ac8SCy Schubert eap_pwd_h_update(hash, cruft, prime_len * 2); 777f05cddf9SRui Paulo 778f05cddf9SRui Paulo /* my scalar */ 779*a90b9d01SCy Schubert if (crypto_bignum_to_bin(data->my_scalar, cruft, order_len, 780*a90b9d01SCy Schubert order_len) < 0) 781*a90b9d01SCy Schubert goto fin; 782*a90b9d01SCy Schubert 78385732ac8SCy Schubert eap_pwd_h_update(hash, cruft, order_len); 784f05cddf9SRui Paulo 785f05cddf9SRui Paulo /* the ciphersuite */ 786f05cddf9SRui Paulo eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32)); 787f05cddf9SRui Paulo 788f05cddf9SRui Paulo /* random function fin */ 789f05cddf9SRui Paulo eap_pwd_h_final(hash, conf); 79085732ac8SCy Schubert hash = NULL; 791f05cddf9SRui Paulo 792f05cddf9SRui Paulo ptr = (u8 *) payload; 7935b9c547cSRui Paulo if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) { 794f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm did not verify"); 795f05cddf9SRui Paulo goto fin; 796f05cddf9SRui Paulo } 797f05cddf9SRui Paulo 798f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "EAP-pwd (peer): confirm verified"); 799f05cddf9SRui Paulo 800f05cddf9SRui Paulo /* 801f05cddf9SRui Paulo * compute confirm: 802f05cddf9SRui Paulo * H(k | peer_element | peer_scalar | server_element | server_scalar | 803f05cddf9SRui Paulo * ciphersuite) 804f05cddf9SRui Paulo */ 805f05cddf9SRui Paulo hash = eap_pwd_h_init(); 806f05cddf9SRui Paulo if (hash == NULL) 807f05cddf9SRui Paulo goto fin; 808f05cddf9SRui Paulo 809f05cddf9SRui Paulo /* k */ 810*a90b9d01SCy Schubert if (crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len) < 0) 811*a90b9d01SCy Schubert goto fin; 812*a90b9d01SCy Schubert 81385732ac8SCy Schubert eap_pwd_h_update(hash, cruft, prime_len); 814f05cddf9SRui Paulo 815f05cddf9SRui Paulo /* my element */ 81685732ac8SCy Schubert if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft, 81785732ac8SCy Schubert cruft + prime_len) != 0) { 818f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point " 819f05cddf9SRui Paulo "assignment fail"); 820f05cddf9SRui Paulo goto fin; 821f05cddf9SRui Paulo } 82285732ac8SCy Schubert eap_pwd_h_update(hash, cruft, prime_len * 2); 823f05cddf9SRui Paulo 824f05cddf9SRui Paulo /* my scalar */ 825*a90b9d01SCy Schubert if (crypto_bignum_to_bin(data->my_scalar, cruft, order_len, 826*a90b9d01SCy Schubert order_len) < 0) 827*a90b9d01SCy Schubert goto fin; 828*a90b9d01SCy Schubert 82985732ac8SCy Schubert eap_pwd_h_update(hash, cruft, order_len); 830f05cddf9SRui Paulo 831f05cddf9SRui Paulo /* server element: x, y */ 83285732ac8SCy Schubert if (crypto_ec_point_to_bin(data->grp->group, data->server_element, 83385732ac8SCy Schubert cruft, cruft + prime_len) != 0) { 834f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point " 835f05cddf9SRui Paulo "assignment fail"); 836f05cddf9SRui Paulo goto fin; 837f05cddf9SRui Paulo } 83885732ac8SCy Schubert eap_pwd_h_update(hash, cruft, prime_len * 2); 839f05cddf9SRui Paulo 840f05cddf9SRui Paulo /* server scalar */ 841*a90b9d01SCy Schubert if (crypto_bignum_to_bin(data->server_scalar, cruft, order_len, 842*a90b9d01SCy Schubert order_len) < 0) 843*a90b9d01SCy Schubert goto fin; 844*a90b9d01SCy Schubert 84585732ac8SCy Schubert eap_pwd_h_update(hash, cruft, order_len); 846f05cddf9SRui Paulo 847f05cddf9SRui Paulo /* the ciphersuite */ 848f05cddf9SRui Paulo eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32)); 849f05cddf9SRui Paulo 850f05cddf9SRui Paulo /* all done */ 851f05cddf9SRui Paulo eap_pwd_h_final(hash, conf); 85285732ac8SCy Schubert hash = NULL; 853f05cddf9SRui Paulo 85485732ac8SCy Schubert if (compute_keys(data->grp, data->k, 855f05cddf9SRui Paulo data->my_scalar, data->server_scalar, conf, ptr, 8565b9c547cSRui Paulo &cs, data->msk, data->emsk, data->session_id) < 0) { 857f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute MSK | " 858f05cddf9SRui Paulo "EMSK"); 859f05cddf9SRui Paulo goto fin; 860f05cddf9SRui Paulo } 861f05cddf9SRui Paulo 862f05cddf9SRui Paulo data->outbuf = wpabuf_alloc(SHA256_MAC_LEN); 863f05cddf9SRui Paulo if (data->outbuf == NULL) 864f05cddf9SRui Paulo goto fin; 865f05cddf9SRui Paulo 866f05cddf9SRui Paulo wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN); 867f05cddf9SRui Paulo 868f05cddf9SRui Paulo fin: 86985732ac8SCy Schubert bin_clear_free(cruft, prime_len * 2); 870f05cddf9SRui Paulo if (data->outbuf == NULL) { 8715b9c547cSRui Paulo ret->methodState = METHOD_DONE; 872f05cddf9SRui Paulo ret->decision = DECISION_FAIL; 873f05cddf9SRui Paulo eap_pwd_state(data, FAILURE); 874f05cddf9SRui Paulo } else { 8755b9c547cSRui Paulo eap_pwd_state(data, SUCCESS_ON_FRAG_COMPLETION); 876f05cddf9SRui Paulo } 87785732ac8SCy Schubert 87885732ac8SCy Schubert /* clean allocated memory */ 87985732ac8SCy Schubert if (hash) 88085732ac8SCy Schubert eap_pwd_h_final(hash, conf); 881f05cddf9SRui Paulo } 882f05cddf9SRui Paulo 883f05cddf9SRui Paulo 884f05cddf9SRui Paulo static struct wpabuf * 885f05cddf9SRui Paulo eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, 886f05cddf9SRui Paulo const struct wpabuf *reqData) 887f05cddf9SRui Paulo { 888f05cddf9SRui Paulo struct eap_pwd_data *data = priv; 889f05cddf9SRui Paulo struct wpabuf *resp = NULL; 890f05cddf9SRui Paulo const u8 *pos, *buf; 891f05cddf9SRui Paulo size_t len; 892f05cddf9SRui Paulo u16 tot_len = 0; 893f05cddf9SRui Paulo u8 lm_exch; 894f05cddf9SRui Paulo 895f05cddf9SRui Paulo pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, reqData, &len); 896f05cddf9SRui Paulo if ((pos == NULL) || (len < 1)) { 897f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "EAP-pwd: Got a frame but pos is %s and " 898f05cddf9SRui Paulo "len is %d", 899f05cddf9SRui Paulo pos == NULL ? "NULL" : "not NULL", (int) len); 900c1d255d3SCy Schubert ret->ignore = true; 901f05cddf9SRui Paulo return NULL; 902f05cddf9SRui Paulo } 903f05cddf9SRui Paulo 904c1d255d3SCy Schubert ret->ignore = false; 905f05cddf9SRui Paulo ret->methodState = METHOD_MAY_CONT; 906f05cddf9SRui Paulo ret->decision = DECISION_FAIL; 907c1d255d3SCy Schubert ret->allowNotifications = false; 908f05cddf9SRui Paulo 909f05cddf9SRui Paulo lm_exch = *pos; 910f05cddf9SRui Paulo pos++; /* skip over the bits and the exch */ 911f05cddf9SRui Paulo len--; 912f05cddf9SRui Paulo 913f05cddf9SRui Paulo /* 914f05cddf9SRui Paulo * we're fragmenting so send out the next fragment 915f05cddf9SRui Paulo */ 916f05cddf9SRui Paulo if (data->out_frag_pos) { 917f05cddf9SRui Paulo /* 918f05cddf9SRui Paulo * this should be an ACK 919f05cddf9SRui Paulo */ 920f05cddf9SRui Paulo if (len) 921f05cddf9SRui Paulo wpa_printf(MSG_INFO, "Bad Response! Fragmenting but " 922f05cddf9SRui Paulo "not an ACK"); 923f05cddf9SRui Paulo 924f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "EAP-pwd: Got an ACK for a fragment"); 925f05cddf9SRui Paulo /* 926f05cddf9SRui Paulo * check if there are going to be more fragments 927f05cddf9SRui Paulo */ 928f05cddf9SRui Paulo len = wpabuf_len(data->outbuf) - data->out_frag_pos; 929f05cddf9SRui Paulo if ((len + EAP_PWD_HDR_SIZE) > data->mtu) { 930f05cddf9SRui Paulo len = data->mtu - EAP_PWD_HDR_SIZE; 931f05cddf9SRui Paulo EAP_PWD_SET_MORE_BIT(lm_exch); 932f05cddf9SRui Paulo } 933f05cddf9SRui Paulo resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, 934f05cddf9SRui Paulo EAP_PWD_HDR_SIZE + len, 935f05cddf9SRui Paulo EAP_CODE_RESPONSE, eap_get_id(reqData)); 936f05cddf9SRui Paulo if (resp == NULL) { 937f05cddf9SRui Paulo wpa_printf(MSG_INFO, "Unable to allocate memory for " 938f05cddf9SRui Paulo "next fragment!"); 939f05cddf9SRui Paulo return NULL; 940f05cddf9SRui Paulo } 941f05cddf9SRui Paulo wpabuf_put_u8(resp, lm_exch); 942f05cddf9SRui Paulo buf = wpabuf_head_u8(data->outbuf); 943f05cddf9SRui Paulo wpabuf_put_data(resp, buf + data->out_frag_pos, len); 944f05cddf9SRui Paulo data->out_frag_pos += len; 945f05cddf9SRui Paulo /* 946f05cddf9SRui Paulo * this is the last fragment so get rid of the out buffer 947f05cddf9SRui Paulo */ 948f05cddf9SRui Paulo if (data->out_frag_pos >= wpabuf_len(data->outbuf)) { 949f05cddf9SRui Paulo wpabuf_free(data->outbuf); 950f05cddf9SRui Paulo data->outbuf = NULL; 951f05cddf9SRui Paulo data->out_frag_pos = 0; 952f05cddf9SRui Paulo } 953f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "EAP-pwd: Send %s fragment of %d bytes", 954f05cddf9SRui Paulo data->out_frag_pos == 0 ? "last" : "next", 955f05cddf9SRui Paulo (int) len); 9565b9c547cSRui Paulo if (data->state == SUCCESS_ON_FRAG_COMPLETION) { 9575b9c547cSRui Paulo ret->methodState = METHOD_DONE; 9585b9c547cSRui Paulo ret->decision = DECISION_UNCOND_SUCC; 9595b9c547cSRui Paulo eap_pwd_state(data, SUCCESS); 9605b9c547cSRui Paulo } 961f05cddf9SRui Paulo return resp; 962f05cddf9SRui Paulo } 963f05cddf9SRui Paulo 964f05cddf9SRui Paulo /* 965f05cddf9SRui Paulo * see if this is a fragment that needs buffering 966f05cddf9SRui Paulo * 967f05cddf9SRui Paulo * if it's the first fragment there'll be a length field 968f05cddf9SRui Paulo */ 969f05cddf9SRui Paulo if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) { 970325151a3SRui Paulo if (len < 2) { 971325151a3SRui Paulo wpa_printf(MSG_DEBUG, 972325151a3SRui Paulo "EAP-pwd: Frame too short to contain Total-Length field"); 973c1d255d3SCy Schubert ret->ignore = true; 974325151a3SRui Paulo return NULL; 975325151a3SRui Paulo } 976f05cddf9SRui Paulo tot_len = WPA_GET_BE16(pos); 977f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments whose " 978f05cddf9SRui Paulo "total length = %d", tot_len); 9795b9c547cSRui Paulo if (tot_len > 15000) 9805b9c547cSRui Paulo return NULL; 981325151a3SRui Paulo if (data->inbuf) { 982325151a3SRui Paulo wpa_printf(MSG_DEBUG, 983325151a3SRui Paulo "EAP-pwd: Unexpected new fragment start when previous fragment is still in use"); 984c1d255d3SCy Schubert ret->ignore = true; 985325151a3SRui Paulo return NULL; 986325151a3SRui Paulo } 987f05cddf9SRui Paulo data->inbuf = wpabuf_alloc(tot_len); 988f05cddf9SRui Paulo if (data->inbuf == NULL) { 989f05cddf9SRui Paulo wpa_printf(MSG_INFO, "Out of memory to buffer " 990f05cddf9SRui Paulo "fragments!"); 991f05cddf9SRui Paulo return NULL; 992f05cddf9SRui Paulo } 993325151a3SRui Paulo data->in_frag_pos = 0; 994f05cddf9SRui Paulo pos += sizeof(u16); 995f05cddf9SRui Paulo len -= sizeof(u16); 996f05cddf9SRui Paulo } 997f05cddf9SRui Paulo /* 998f05cddf9SRui Paulo * buffer and ACK the fragment 999f05cddf9SRui Paulo */ 1000780fb4a2SCy Schubert if (EAP_PWD_GET_MORE_BIT(lm_exch) || data->in_frag_pos) { 10014bc52338SCy Schubert if (!data->inbuf) { 10024bc52338SCy Schubert wpa_printf(MSG_DEBUG, 10034bc52338SCy Schubert "EAP-pwd: No buffer for reassembly"); 10044bc52338SCy Schubert ret->methodState = METHOD_DONE; 10054bc52338SCy Schubert ret->decision = DECISION_FAIL; 10064bc52338SCy Schubert return NULL; 10074bc52338SCy Schubert } 1008f05cddf9SRui Paulo data->in_frag_pos += len; 1009f05cddf9SRui Paulo if (data->in_frag_pos > wpabuf_size(data->inbuf)) { 1010f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-pwd: Buffer overflow attack " 1011f05cddf9SRui Paulo "detected (%d vs. %d)!", 1012f05cddf9SRui Paulo (int) data->in_frag_pos, 1013f05cddf9SRui Paulo (int) wpabuf_len(data->inbuf)); 1014f05cddf9SRui Paulo wpabuf_free(data->inbuf); 10155b9c547cSRui Paulo data->inbuf = NULL; 1016f05cddf9SRui Paulo data->in_frag_pos = 0; 1017f05cddf9SRui Paulo return NULL; 1018f05cddf9SRui Paulo } 1019f05cddf9SRui Paulo wpabuf_put_data(data->inbuf, pos, len); 1020780fb4a2SCy Schubert } 1021780fb4a2SCy Schubert if (EAP_PWD_GET_MORE_BIT(lm_exch)) { 1022f05cddf9SRui Paulo resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, 1023f05cddf9SRui Paulo EAP_PWD_HDR_SIZE, 1024f05cddf9SRui Paulo EAP_CODE_RESPONSE, eap_get_id(reqData)); 1025f05cddf9SRui Paulo if (resp != NULL) 1026f05cddf9SRui Paulo wpabuf_put_u8(resp, (EAP_PWD_GET_EXCHANGE(lm_exch))); 1027f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "EAP-pwd: ACKing a %d byte fragment", 1028f05cddf9SRui Paulo (int) len); 1029f05cddf9SRui Paulo return resp; 1030f05cddf9SRui Paulo } 1031f05cddf9SRui Paulo /* 1032f05cddf9SRui Paulo * we're buffering and this is the last fragment 1033f05cddf9SRui Paulo */ 10344bc52338SCy Schubert if (data->in_frag_pos && data->inbuf) { 1035f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes", 1036f05cddf9SRui Paulo (int) len); 1037f05cddf9SRui Paulo pos = wpabuf_head_u8(data->inbuf); 1038f05cddf9SRui Paulo len = data->in_frag_pos; 1039f05cddf9SRui Paulo } 1040f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "EAP-pwd: processing frame: exch %d, len %d", 1041f05cddf9SRui Paulo EAP_PWD_GET_EXCHANGE(lm_exch), (int) len); 1042f05cddf9SRui Paulo 1043f05cddf9SRui Paulo switch (EAP_PWD_GET_EXCHANGE(lm_exch)) { 1044f05cddf9SRui Paulo case EAP_PWD_OPCODE_ID_EXCH: 1045f05cddf9SRui Paulo eap_pwd_perform_id_exchange(sm, data, ret, reqData, 1046f05cddf9SRui Paulo pos, len); 1047f05cddf9SRui Paulo break; 1048f05cddf9SRui Paulo case EAP_PWD_OPCODE_COMMIT_EXCH: 1049f05cddf9SRui Paulo eap_pwd_perform_commit_exchange(sm, data, ret, reqData, 1050f05cddf9SRui Paulo pos, len); 1051f05cddf9SRui Paulo break; 1052f05cddf9SRui Paulo case EAP_PWD_OPCODE_CONFIRM_EXCH: 1053f05cddf9SRui Paulo eap_pwd_perform_confirm_exchange(sm, data, ret, reqData, 1054f05cddf9SRui Paulo pos, len); 1055f05cddf9SRui Paulo break; 1056f05cddf9SRui Paulo default: 1057f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-pwd: Ignoring message with unknown " 1058f05cddf9SRui Paulo "opcode %d", lm_exch); 1059f05cddf9SRui Paulo break; 1060f05cddf9SRui Paulo } 1061f05cddf9SRui Paulo /* 1062f05cddf9SRui Paulo * if we buffered the just processed input now's the time to free it 1063f05cddf9SRui Paulo */ 1064f05cddf9SRui Paulo if (data->in_frag_pos) { 1065f05cddf9SRui Paulo wpabuf_free(data->inbuf); 10665b9c547cSRui Paulo data->inbuf = NULL; 1067f05cddf9SRui Paulo data->in_frag_pos = 0; 1068f05cddf9SRui Paulo } 1069f05cddf9SRui Paulo 10705b9c547cSRui Paulo if (data->outbuf == NULL) { 10715b9c547cSRui Paulo ret->methodState = METHOD_DONE; 10725b9c547cSRui Paulo ret->decision = DECISION_FAIL; 1073f05cddf9SRui Paulo return NULL; /* generic failure */ 10745b9c547cSRui Paulo } 1075f05cddf9SRui Paulo 1076f05cddf9SRui Paulo /* 1077f05cddf9SRui Paulo * we have output! Do we need to fragment it? 1078f05cddf9SRui Paulo */ 1079325151a3SRui Paulo lm_exch = EAP_PWD_GET_EXCHANGE(lm_exch); 1080f05cddf9SRui Paulo len = wpabuf_len(data->outbuf); 1081f05cddf9SRui Paulo if ((len + EAP_PWD_HDR_SIZE) > data->mtu) { 1082f05cddf9SRui Paulo resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, data->mtu, 1083f05cddf9SRui Paulo EAP_CODE_RESPONSE, eap_get_id(reqData)); 1084f05cddf9SRui Paulo /* 1085f05cddf9SRui Paulo * if so it's the first so include a length field 1086f05cddf9SRui Paulo */ 1087f05cddf9SRui Paulo EAP_PWD_SET_LENGTH_BIT(lm_exch); 1088f05cddf9SRui Paulo EAP_PWD_SET_MORE_BIT(lm_exch); 1089f05cddf9SRui Paulo tot_len = len; 1090f05cddf9SRui Paulo /* 1091f05cddf9SRui Paulo * keep the packet at the MTU 1092f05cddf9SRui Paulo */ 1093f05cddf9SRui Paulo len = data->mtu - EAP_PWD_HDR_SIZE - sizeof(u16); 1094f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "EAP-pwd: Fragmenting output, total " 1095f05cddf9SRui Paulo "length = %d", tot_len); 1096f05cddf9SRui Paulo } else { 1097f05cddf9SRui Paulo resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, 1098f05cddf9SRui Paulo EAP_PWD_HDR_SIZE + len, 1099f05cddf9SRui Paulo EAP_CODE_RESPONSE, eap_get_id(reqData)); 1100f05cddf9SRui Paulo } 1101f05cddf9SRui Paulo if (resp == NULL) 1102f05cddf9SRui Paulo return NULL; 1103f05cddf9SRui Paulo 1104f05cddf9SRui Paulo wpabuf_put_u8(resp, lm_exch); 1105f05cddf9SRui Paulo if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) { 1106f05cddf9SRui Paulo wpabuf_put_be16(resp, tot_len); 1107f05cddf9SRui Paulo data->out_frag_pos += len; 1108f05cddf9SRui Paulo } 1109f05cddf9SRui Paulo buf = wpabuf_head_u8(data->outbuf); 1110f05cddf9SRui Paulo wpabuf_put_data(resp, buf, len); 1111f05cddf9SRui Paulo /* 1112f05cddf9SRui Paulo * if we're not fragmenting then there's no need to carry this around 1113f05cddf9SRui Paulo */ 1114f05cddf9SRui Paulo if (data->out_frag_pos == 0) { 1115f05cddf9SRui Paulo wpabuf_free(data->outbuf); 1116f05cddf9SRui Paulo data->outbuf = NULL; 1117f05cddf9SRui Paulo data->out_frag_pos = 0; 11185b9c547cSRui Paulo if (data->state == SUCCESS_ON_FRAG_COMPLETION) { 11195b9c547cSRui Paulo ret->methodState = METHOD_DONE; 11205b9c547cSRui Paulo ret->decision = DECISION_UNCOND_SUCC; 11215b9c547cSRui Paulo eap_pwd_state(data, SUCCESS); 11225b9c547cSRui Paulo } 1123f05cddf9SRui Paulo } 1124f05cddf9SRui Paulo 1125f05cddf9SRui Paulo return resp; 1126f05cddf9SRui Paulo } 1127f05cddf9SRui Paulo 1128f05cddf9SRui Paulo 1129c1d255d3SCy Schubert static bool eap_pwd_key_available(struct eap_sm *sm, void *priv) 1130f05cddf9SRui Paulo { 1131f05cddf9SRui Paulo struct eap_pwd_data *data = priv; 1132f05cddf9SRui Paulo return data->state == SUCCESS; 1133f05cddf9SRui Paulo } 1134f05cddf9SRui Paulo 1135f05cddf9SRui Paulo 1136f05cddf9SRui Paulo static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 1137f05cddf9SRui Paulo { 1138f05cddf9SRui Paulo struct eap_pwd_data *data = priv; 1139f05cddf9SRui Paulo u8 *key; 1140f05cddf9SRui Paulo 1141f05cddf9SRui Paulo if (data->state != SUCCESS) 1142f05cddf9SRui Paulo return NULL; 1143f05cddf9SRui Paulo 1144f05cddf9SRui Paulo if ((key = os_malloc(EAP_EMSK_LEN)) == NULL) 1145f05cddf9SRui Paulo return NULL; 1146f05cddf9SRui Paulo 1147f05cddf9SRui Paulo os_memcpy(key, data->emsk, EAP_EMSK_LEN); 1148f05cddf9SRui Paulo *len = EAP_EMSK_LEN; 1149f05cddf9SRui Paulo 1150f05cddf9SRui Paulo return key; 1151f05cddf9SRui Paulo } 1152f05cddf9SRui Paulo 1153f05cddf9SRui Paulo 1154f05cddf9SRui Paulo int eap_peer_pwd_register(void) 1155f05cddf9SRui Paulo { 1156f05cddf9SRui Paulo struct eap_method *eap; 1157f05cddf9SRui Paulo 1158f05cddf9SRui Paulo eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 1159f05cddf9SRui Paulo EAP_VENDOR_IETF, EAP_TYPE_PWD, "PWD"); 1160f05cddf9SRui Paulo if (eap == NULL) 1161f05cddf9SRui Paulo return -1; 1162f05cddf9SRui Paulo 1163f05cddf9SRui Paulo eap->init = eap_pwd_init; 1164f05cddf9SRui Paulo eap->deinit = eap_pwd_deinit; 1165f05cddf9SRui Paulo eap->process = eap_pwd_process; 1166f05cddf9SRui Paulo eap->isKeyAvailable = eap_pwd_key_available; 1167f05cddf9SRui Paulo eap->getKey = eap_pwd_getkey; 11685b9c547cSRui Paulo eap->getSessionId = eap_pwd_get_session_id; 1169f05cddf9SRui Paulo eap->get_emsk = eap_pwd_get_emsk; 1170f05cddf9SRui Paulo 1171780fb4a2SCy Schubert return eap_peer_method_register(eap); 1172f05cddf9SRui Paulo } 1173