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 19 struct eap_md5_data { 20 u8 challenge[CHALLENGE_LEN]; 21 enum { CONTINUE, SUCCESS, FAILURE } state; 22 }; 23 24 25 static 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 38 static 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 45 static 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 76 static bool 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 98 static 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 139 static bool 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 146 static bool 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 153 int 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