1/* 2 * hostapd / EAP-MD5 server 3 * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9#include "includes.h" 10 11#include "common.h" 12#include "crypto/random.h" 13#include "eap_i.h" 14#include "eap_common/chap.h" 15 16 17#define CHALLENGE_LEN 16 18 19struct eap_md5_data { 20 u8 challenge[CHALLENGE_LEN]; 21 enum { CONTINUE, SUCCESS, FAILURE } state; 22}; 23 24 25static void * eap_md5_init(struct eap_sm *sm) 26{ 27 struct eap_md5_data *data; 28 29 data = os_zalloc(sizeof(*data)); 30 if (data == NULL) 31 return NULL; 32 data->state = CONTINUE; 33 34 return data; 35} 36 37 38static void eap_md5_reset(struct eap_sm *sm, void *priv) 39{ 40 struct eap_md5_data *data = priv; 41 os_free(data); 42} 43 44 45static struct wpabuf * eap_md5_buildReq(struct eap_sm *sm, void *priv, u8 id) 46{ 47 struct eap_md5_data *data = priv; 48 struct wpabuf *req; 49 50 if (random_get_bytes(data->challenge, CHALLENGE_LEN)) { 51 wpa_printf(MSG_ERROR, "EAP-MD5: Failed to get random data"); 52 data->state = FAILURE; 53 return NULL; 54 } 55 56 req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, 1 + CHALLENGE_LEN, 57 EAP_CODE_REQUEST, id); 58 if (req == NULL) { 59 wpa_printf(MSG_ERROR, "EAP-MD5: Failed to allocate memory for " 60 "request"); 61 data->state = FAILURE; 62 return NULL; 63 } 64 65 wpabuf_put_u8(req, CHALLENGE_LEN); 66 wpabuf_put_data(req, data->challenge, CHALLENGE_LEN); 67 wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge", data->challenge, 68 CHALLENGE_LEN); 69 70 data->state = CONTINUE; 71 72 return req; 73} 74 75 76static Boolean eap_md5_check(struct eap_sm *sm, void *priv, 77 struct wpabuf *respData) 78{ 79 const u8 *pos; 80 size_t len; 81 82 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, respData, &len); 83 if (pos == NULL || len < 1) { 84 wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame"); 85 return TRUE; 86 } 87 if (*pos != CHAP_MD5_LEN || 1 + CHAP_MD5_LEN > len) { 88 wpa_printf(MSG_INFO, "EAP-MD5: Invalid response " 89 "(response_len=%d payload_len=%lu", 90 *pos, (unsigned long) len); 91 return TRUE; 92 } 93 94 return FALSE; 95} 96 97 98static void eap_md5_process(struct eap_sm *sm, void *priv, 99 struct wpabuf *respData) 100{ 101 struct eap_md5_data *data = priv; 102 const u8 *pos; 103 size_t plen; 104 u8 hash[CHAP_MD5_LEN], id; 105 106 if (sm->user == NULL || sm->user->password == NULL || 107 sm->user->password_hash) { 108 wpa_printf(MSG_INFO, "EAP-MD5: Plaintext password not " 109 "configured"); 110 data->state = FAILURE; 111 return; 112 } 113 114 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, respData, &plen); 115 if (pos == NULL || *pos != CHAP_MD5_LEN || plen < 1 + CHAP_MD5_LEN) 116 return; /* Should not happen - frame already validated */ 117 118 pos++; /* Skip response len */ 119 wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", pos, CHAP_MD5_LEN); 120 121 id = eap_get_id(respData); 122 if (chap_md5(id, sm->user->password, sm->user->password_len, 123 data->challenge, CHALLENGE_LEN, hash)) { 124 wpa_printf(MSG_INFO, "EAP-MD5: CHAP MD5 operation failed"); 125 data->state = FAILURE; 126 return; 127 } 128 129 if (os_memcmp_const(hash, pos, CHAP_MD5_LEN) == 0) { 130 wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Success"); 131 data->state = SUCCESS; 132 } else { 133 wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Failure"); 134 data->state = FAILURE; 135 } 136} 137 138 139static Boolean eap_md5_isDone(struct eap_sm *sm, void *priv) 140{ 141 struct eap_md5_data *data = priv; 142 return data->state != CONTINUE; 143} 144 145 146static Boolean eap_md5_isSuccess(struct eap_sm *sm, void *priv) 147{ 148 struct eap_md5_data *data = priv; 149 return data->state == SUCCESS; 150} 151 152 153int eap_server_md5_register(void) 154{ 155 struct eap_method *eap; 156 157 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 158 EAP_VENDOR_IETF, EAP_TYPE_MD5, "MD5"); 159 if (eap == NULL) 160 return -1; 161 162 eap->init = eap_md5_init; 163 eap->reset = eap_md5_reset; 164 eap->buildReq = eap_md5_buildReq; 165 eap->check = eap_md5_check; 166 eap->process = eap_md5_process; 167 eap->isDone = eap_md5_isDone; 168 eap->isSuccess = eap_md5_isSuccess; 169 170 return eap_server_method_register(eap); 171} 172