18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hostapd / EAP-MD5 server 361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details. 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h" 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h" 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/random.h" 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_i.h" 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_common/chap.h" 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define CHALLENGE_LEN 16 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct eap_md5_data { 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 challenge[CHALLENGE_LEN]; 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt enum { CONTINUE, SUCCESS, FAILURE } state; 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void * eap_md5_init(struct eap_sm *sm) 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_md5_data *data; 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data = os_zalloc(sizeof(*data)); 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data == NULL) 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = CONTINUE; 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return data; 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eap_md5_reset(struct eap_sm *sm, void *priv) 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_md5_data *data = priv; 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_md5_buildReq(struct eap_sm *sm, void *priv, u8 id) 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_md5_data *data = priv; 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *req; 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (random_get_bytes(data->challenge, CHALLENGE_LEN)) { 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "EAP-MD5: Failed to get random data"); 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = FAILURE; 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, 1 + CHALLENGE_LEN, 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt EAP_CODE_REQUEST, id); 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (req == NULL) { 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "EAP-MD5: Failed to allocate memory for " 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "request"); 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = FAILURE; 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_u8(req, CHALLENGE_LEN); 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(req, data->challenge, CHALLENGE_LEN); 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge", data->challenge, 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt CHALLENGE_LEN); 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = CONTINUE; 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return req; 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic Boolean eap_md5_check(struct eap_sm *sm, void *priv, 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *respData) 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos; 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len; 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, respData, &len); 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos == NULL || len < 1) { 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame"); 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return TRUE; 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (*pos != CHAP_MD5_LEN || 1 + CHAP_MD5_LEN > len) { 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "EAP-MD5: Invalid response " 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(response_len=%d payload_len=%lu", 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos, (unsigned long) len); 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return TRUE; 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return FALSE; 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eap_md5_process(struct eap_sm *sm, void *priv, 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *respData) 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_md5_data *data = priv; 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos; 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t plen; 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 hash[CHAP_MD5_LEN], id; 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sm->user == NULL || sm->user->password == NULL || 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sm->user->password_hash) { 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "EAP-MD5: Plaintext password not " 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "configured"); 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = FAILURE; 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, respData, &plen); 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos == NULL || *pos != CHAP_MD5_LEN || plen < 1 + CHAP_MD5_LEN) 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; /* Should not happen - frame already validated */ 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos++; /* Skip response len */ 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", pos, CHAP_MD5_LEN); 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt id = eap_get_id(respData); 12261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (chap_md5(id, sm->user->password, sm->user->password_len, 12361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt data->challenge, CHALLENGE_LEN, hash)) { 12461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_INFO, "EAP-MD5: CHAP MD5 operation failed"); 12561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt data->state = FAILURE; 12661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return; 12761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 129c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt if (os_memcmp_const(hash, pos, CHAP_MD5_LEN) == 0) { 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Success"); 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = SUCCESS; 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Failure"); 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = FAILURE; 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic Boolean eap_md5_isDone(struct eap_sm *sm, void *priv) 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_md5_data *data = priv; 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return data->state != CONTINUE; 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic Boolean eap_md5_isSuccess(struct eap_sm *sm, void *priv) 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_md5_data *data = priv; 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return data->state == SUCCESS; 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eap_server_md5_register(void) 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_method *eap; 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret; 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt EAP_VENDOR_IETF, EAP_TYPE_MD5, "MD5"); 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (eap == NULL) 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->init = eap_md5_init; 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->reset = eap_md5_reset; 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->buildReq = eap_md5_buildReq; 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->check = eap_md5_check; 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->process = eap_md5_process; 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->isDone = eap_md5_isDone; 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->isSuccess = eap_md5_isSuccess; 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = eap_server_method_register(eap); 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ret) 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_server_method_free(eap); 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ret; 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 176