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