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