static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len) { struct eap_mschapv2_data *data = priv; u8 *key; int key_len; if (!data->master_key_valid || !data->success) return NULL; key_len = 2 * MSCHAPV2_KEY_LEN; key = os_malloc(key_len); if (key == NULL) return NULL; /* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key, i.e., * peer MS-MPPE-Send-Key | MS-MPPE-Recv-Key */ get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 1, 0); get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN, MSCHAPV2_KEY_LEN, 0, 0); wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key", key, key_len); *len = key_len; return key; }
static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len) { struct eap_mschapv2_data *data = priv; u8 *key; if (data->state != SUCCESS || !data->master_key_valid) return NULL; *len = 2 * MSCHAPV2_KEY_LEN; key = malloc(*len); if (key == NULL) return NULL; get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 0, 0); get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN, MSCHAPV2_KEY_LEN, 1, 0); wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key", key, *len); return key; }
static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len) { struct eap_mschapv2_data *data = priv; u8 *key; int key_len; if (!data->master_key_valid || !data->success) return NULL; if (data->full_key) { /* EAP-FAST needs both send and receive keys */ key_len = 2 * MSCHAPV2_KEY_LEN; } else { key_len = MSCHAPV2_KEY_LEN; } key = malloc(key_len); if (key == NULL) return NULL; if (data->full_key) { get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 0, 0); get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN, MSCHAPV2_KEY_LEN, 1, 0); } else { get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 1, 0); } wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key", key, key_len); *len = key_len; return key; }
int main(int argc, char *argv[]) { /* Test vector from RFC2759 example */ u8 *username = "******"; u8 *password = "******"; u8 auth_challenge[] = { 0x5B, 0x5D, 0x7C, 0x7D, 0x7B, 0x3F, 0x2F, 0x3E, 0x3C, 0x2C, 0x60, 0x21, 0x32, 0x26, 0x26, 0x28 }; u8 peer_challenge[] = { 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x3A, 0x33, 0x7C, 0x7E }; u8 challenge[] = { 0xD0, 0x2E, 0x43, 0x86, 0xBC, 0xE9, 0x12, 0x26 }; u8 password_hash[] = { 0x44, 0xEB, 0xBA, 0x8D, 0x53, 0x12, 0xB8, 0xD6, 0x11, 0x47, 0x44, 0x11, 0xF5, 0x69, 0x89, 0xAE }; u8 nt_response[] = { 0x82, 0x30, 0x9E, 0xCD, 0x8D, 0x70, 0x8B, 0x5E, 0xA0, 0x8F, 0xAA, 0x39, 0x81, 0xCD, 0x83, 0x54, 0x42, 0x33, 0x11, 0x4A, 0x3D, 0x85, 0xD6, 0xDF }; u8 password_hash_hash[] = { 0x41, 0xC0, 0x0C, 0x58, 0x4B, 0xD2, 0xD9, 0x1C, 0x40, 0x17, 0xA2, 0xA1, 0x2F, 0xA5, 0x9F, 0x3F }; u8 authenticator_response[] = { 0x40, 0x7A, 0x55, 0x89, 0x11, 0x5F, 0xD0, 0xD6, 0x20, 0x9F, 0x51, 0x0F, 0xE9, 0xC0, 0x45, 0x66, 0x93, 0x2C, 0xDA, 0x56 }; u8 master_key[] = { 0xFD, 0xEC, 0xE3, 0x71, 0x7A, 0x8C, 0x83, 0x8C, 0xB3, 0x88, 0xE5, 0x27, 0xAE, 0x3C, 0xDD, 0x31 }; u8 send_start_key[] = { 0x8B, 0x7C, 0xDC, 0x14, 0x9B, 0x99, 0x3A, 0x1B, 0xA1, 0x18, 0xCB, 0x15, 0x3F, 0x56, 0xDC, 0xCB }; u8 buf[32]; int errors = 0; printf("Testing ms_funcs.c\n"); challenge_hash(peer_challenge, auth_challenge, username, strlen(username), buf); if (memcmp(challenge, buf, sizeof(challenge)) != 0) { printf("challenge_hash failed\n"); errors++; } nt_password_hash(password, strlen(password), buf); if (memcmp(password_hash, buf, sizeof(password_hash)) != 0) { printf("nt_password_hash failed\n"); errors++; } generate_nt_response(auth_challenge, peer_challenge, username, strlen(username), password, strlen(password), buf); if (memcmp(nt_response, buf, sizeof(nt_response)) != 0) { printf("generate_nt_response failed\n"); errors++; } hash_nt_password_hash(password_hash, buf); if (memcmp(password_hash_hash, buf, sizeof(password_hash_hash)) != 0) { printf("hash_nt_password_hash failed\n"); errors++; } generate_authenticator_response(password, strlen(password), peer_challenge, auth_challenge, username, strlen(username), nt_response, buf); if (memcmp(authenticator_response, buf, sizeof(authenticator_response)) != 0) { printf("generate_authenticator_response failed\n"); errors++; } get_master_key(password_hash_hash, nt_response, buf); if (memcmp(master_key, buf, sizeof(master_key)) != 0) { printf("get_master_key failed\n"); errors++; } get_asymetric_start_key(master_key, buf, sizeof(send_start_key), 1, 1); if (memcmp(send_start_key, buf, sizeof(send_start_key)) != 0) { printf("get_asymetric_start_key failed\n"); errors++; } if (errors) printf("FAILED! %d errors\n", errors); return errors; }
static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, u8 **resp, size_t *resp_len) { struct wpa_ssid *config = eap_get_config(sm); u8 *buf, *pos, *challenge, *username, *peer_challenge; size_t username_len, i; wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAPV2 Request"); /* MSCHAPv2 does not include optional domain name in the * challenge-response calculation, so remove domain prefix * (if present). */ username = config->identity; username_len = config->identity_len; pos = username; for (i = 0; i < username_len; i++) { if (username[i] == '\\') { username_len -= i + 1; username += i + 1; break; } } pos = buf = os_malloc(config->identity_len + 1000); if (buf == NULL) { wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to allocate memory"); return -1; } /* User-Name */ pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, config->identity, config->identity_len); /* MS-CHAP-Challenge */ challenge = eap_ttls_implicit_challenge( sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1); if (challenge == NULL) { os_free(buf); wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive " "implicit challenge"); return -1; } peer_challenge = challenge + 1 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN; pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, RADIUS_VENDOR_ID_MICROSOFT, 1, challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); /* MS-CHAP2-Response */ pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP2_RESPONSE, RADIUS_VENDOR_ID_MICROSOFT, 1, EAP_TTLS_MSCHAPV2_RESPONSE_LEN); data->ident = challenge[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN]; *pos++ = data->ident; *pos++ = 0; /* Flags */ os_memcpy(pos, peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); pos += EAP_TTLS_MSCHAPV2_CHALLENGE_LEN; os_memset(pos, 0, 8); /* Reserved, must be zero */ pos += 8; wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAPV2: implicit auth_challenge", challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAPV2: peer_challenge", peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MSCHAPV2 username", username, username_len); wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAPV2 password", config->password, config->password_len); generate_nt_response(challenge, peer_challenge, username, username_len, config->password, config->password_len, pos); wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAPV2 response", pos, 24); generate_authenticator_response(config->password, config->password_len, peer_challenge, challenge, username, username_len, pos, data->auth_response); data->auth_response_valid = 1; if (data->ttls_version > 0) { u8 pw_hash[16], pw_hash_hash[16], master_key[16]; u8 session_key[2 * MSCHAPV2_KEY_LEN]; nt_password_hash(config->password, config->password_len, pw_hash); hash_nt_password_hash(pw_hash, pw_hash_hash); get_master_key(pw_hash_hash, pos /* nt_response */, master_key); get_asymetric_start_key(master_key, session_key, MSCHAPV2_KEY_LEN, 0, 0); get_asymetric_start_key(master_key, session_key + MSCHAPV2_KEY_LEN, MSCHAPV2_KEY_LEN, 1, 0); eap_ttls_ia_permute_inner_secret(sm, data, session_key, sizeof(session_key)); } pos += 24; os_free(challenge); AVP_PAD(buf, pos); *resp = buf; *resp_len = pos - buf; if (sm->workaround && data->ttls_version == 0) { /* At least FreeRADIUS seems to be terminating * EAP-TTLS/MSHCAPV2 without the expected MS-CHAP-v2 Success * packet. */ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: EAP workaround - " "allow success without tunneled response"); ret->methodState = METHOD_MAY_CONT; ret->decision = DECISION_COND_SUCC; } return 0; }