1214501Srpaulo/* 2214501Srpaulo * hostapd / EAP-GTC (RFC 3748) 3214501Srpaulo * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214501Srpaulo */ 8214501Srpaulo 9214501Srpaulo#include "includes.h" 10214501Srpaulo 11214501Srpaulo#include "common.h" 12214501Srpaulo#include "eap_i.h" 13214501Srpaulo 14214501Srpaulo 15214501Srpaulostruct eap_gtc_data { 16214501Srpaulo enum { CONTINUE, SUCCESS, FAILURE } state; 17214501Srpaulo int prefix; 18214501Srpaulo}; 19214501Srpaulo 20214501Srpaulo 21214501Srpaulostatic void * eap_gtc_init(struct eap_sm *sm) 22214501Srpaulo{ 23214501Srpaulo struct eap_gtc_data *data; 24214501Srpaulo 25214501Srpaulo data = os_zalloc(sizeof(*data)); 26214501Srpaulo if (data == NULL) 27214501Srpaulo return NULL; 28214501Srpaulo data->state = CONTINUE; 29214501Srpaulo 30214501Srpaulo#ifdef EAP_SERVER_FAST 31214501Srpaulo if (sm->m && sm->m->vendor == EAP_VENDOR_IETF && 32214501Srpaulo sm->m->method == EAP_TYPE_FAST) { 33214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix " 34214501Srpaulo "with challenge/response"); 35214501Srpaulo data->prefix = 1; 36214501Srpaulo } 37214501Srpaulo#endif /* EAP_SERVER_FAST */ 38214501Srpaulo 39214501Srpaulo return data; 40214501Srpaulo} 41214501Srpaulo 42214501Srpaulo 43214501Srpaulostatic void eap_gtc_reset(struct eap_sm *sm, void *priv) 44214501Srpaulo{ 45214501Srpaulo struct eap_gtc_data *data = priv; 46214501Srpaulo os_free(data); 47214501Srpaulo} 48214501Srpaulo 49214501Srpaulo 50214501Srpaulostatic struct wpabuf * eap_gtc_buildReq(struct eap_sm *sm, void *priv, u8 id) 51214501Srpaulo{ 52214501Srpaulo struct eap_gtc_data *data = priv; 53214501Srpaulo struct wpabuf *req; 54214501Srpaulo char *msg; 55214501Srpaulo size_t msg_len; 56214501Srpaulo 57214501Srpaulo msg = data->prefix ? "CHALLENGE=Password" : "Password"; 58214501Srpaulo 59214501Srpaulo msg_len = os_strlen(msg); 60214501Srpaulo req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, msg_len, 61214501Srpaulo EAP_CODE_REQUEST, id); 62214501Srpaulo if (req == NULL) { 63214501Srpaulo wpa_printf(MSG_ERROR, "EAP-GTC: Failed to allocate memory for " 64214501Srpaulo "request"); 65214501Srpaulo data->state = FAILURE; 66214501Srpaulo return NULL; 67214501Srpaulo } 68214501Srpaulo 69214501Srpaulo wpabuf_put_data(req, msg, msg_len); 70214501Srpaulo 71214501Srpaulo data->state = CONTINUE; 72214501Srpaulo 73214501Srpaulo return req; 74214501Srpaulo} 75214501Srpaulo 76214501Srpaulo 77214501Srpaulostatic Boolean eap_gtc_check(struct eap_sm *sm, void *priv, 78214501Srpaulo struct wpabuf *respData) 79214501Srpaulo{ 80214501Srpaulo const u8 *pos; 81214501Srpaulo size_t len; 82214501Srpaulo 83214501Srpaulo pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, respData, &len); 84214501Srpaulo if (pos == NULL || len < 1) { 85214501Srpaulo wpa_printf(MSG_INFO, "EAP-GTC: Invalid frame"); 86214501Srpaulo return TRUE; 87214501Srpaulo } 88214501Srpaulo 89214501Srpaulo return FALSE; 90214501Srpaulo} 91214501Srpaulo 92214501Srpaulo 93214501Srpaulostatic void eap_gtc_process(struct eap_sm *sm, void *priv, 94214501Srpaulo struct wpabuf *respData) 95214501Srpaulo{ 96214501Srpaulo struct eap_gtc_data *data = priv; 97214501Srpaulo const u8 *pos; 98214501Srpaulo size_t rlen; 99214501Srpaulo 100214501Srpaulo pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, respData, &rlen); 101214501Srpaulo if (pos == NULL || rlen < 1) 102214501Srpaulo return; /* Should not happen - frame already validated */ 103214501Srpaulo 104214501Srpaulo wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response", pos, rlen); 105214501Srpaulo 106214501Srpaulo#ifdef EAP_SERVER_FAST 107214501Srpaulo if (data->prefix) { 108214501Srpaulo const u8 *pos2, *end; 109214501Srpaulo /* "RESPONSE=<user>\0<password>" */ 110214501Srpaulo if (rlen < 10) { 111214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GTC: Too short response " 112214501Srpaulo "for EAP-FAST prefix"); 113214501Srpaulo data->state = FAILURE; 114214501Srpaulo return; 115214501Srpaulo } 116214501Srpaulo 117214501Srpaulo end = pos + rlen; 118214501Srpaulo pos += 9; 119214501Srpaulo pos2 = pos; 120214501Srpaulo while (pos2 < end && *pos2) 121214501Srpaulo pos2++; 122214501Srpaulo if (pos2 == end) { 123214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GTC: No password in " 124214501Srpaulo "response to EAP-FAST prefix"); 125214501Srpaulo data->state = FAILURE; 126214501Srpaulo return; 127214501Srpaulo } 128214501Srpaulo 129214501Srpaulo wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Response user", 130214501Srpaulo pos, pos2 - pos); 131214501Srpaulo if (sm->identity && sm->require_identity_match && 132214501Srpaulo (pos2 - pos != (int) sm->identity_len || 133214501Srpaulo os_memcmp(pos, sm->identity, sm->identity_len))) { 134214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GTC: Phase 2 Identity did " 135214501Srpaulo "not match with required Identity"); 136214501Srpaulo wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Expected " 137214501Srpaulo "identity", 138214501Srpaulo sm->identity, sm->identity_len); 139214501Srpaulo data->state = FAILURE; 140214501Srpaulo return; 141214501Srpaulo } else { 142214501Srpaulo os_free(sm->identity); 143214501Srpaulo sm->identity_len = pos2 - pos; 144214501Srpaulo sm->identity = os_malloc(sm->identity_len); 145214501Srpaulo if (sm->identity == NULL) { 146214501Srpaulo data->state = FAILURE; 147214501Srpaulo return; 148214501Srpaulo } 149214501Srpaulo os_memcpy(sm->identity, pos, sm->identity_len); 150214501Srpaulo } 151214501Srpaulo 152214501Srpaulo if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { 153214501Srpaulo wpa_hexdump_ascii(MSG_DEBUG, "EAP-GTC: Phase2 " 154214501Srpaulo "Identity not found in the user " 155214501Srpaulo "database", 156214501Srpaulo sm->identity, sm->identity_len); 157214501Srpaulo data->state = FAILURE; 158214501Srpaulo return; 159214501Srpaulo } 160214501Srpaulo 161214501Srpaulo pos = pos2 + 1; 162214501Srpaulo rlen = end - pos; 163214501Srpaulo wpa_hexdump_ascii_key(MSG_MSGDUMP, 164214501Srpaulo "EAP-GTC: Response password", 165214501Srpaulo pos, rlen); 166214501Srpaulo } 167214501Srpaulo#endif /* EAP_SERVER_FAST */ 168214501Srpaulo 169214501Srpaulo if (sm->user == NULL || sm->user->password == NULL || 170214501Srpaulo sm->user->password_hash) { 171214501Srpaulo wpa_printf(MSG_INFO, "EAP-GTC: Plaintext password not " 172214501Srpaulo "configured"); 173214501Srpaulo data->state = FAILURE; 174214501Srpaulo return; 175214501Srpaulo } 176214501Srpaulo 177214501Srpaulo if (rlen != sm->user->password_len || 178214501Srpaulo os_memcmp(pos, sm->user->password, rlen) != 0) { 179214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Failure"); 180214501Srpaulo data->state = FAILURE; 181214501Srpaulo } else { 182214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Success"); 183214501Srpaulo data->state = SUCCESS; 184214501Srpaulo } 185214501Srpaulo} 186214501Srpaulo 187214501Srpaulo 188214501Srpaulostatic Boolean eap_gtc_isDone(struct eap_sm *sm, void *priv) 189214501Srpaulo{ 190214501Srpaulo struct eap_gtc_data *data = priv; 191214501Srpaulo return data->state != CONTINUE; 192214501Srpaulo} 193214501Srpaulo 194214501Srpaulo 195214501Srpaulostatic Boolean eap_gtc_isSuccess(struct eap_sm *sm, void *priv) 196214501Srpaulo{ 197214501Srpaulo struct eap_gtc_data *data = priv; 198214501Srpaulo return data->state == SUCCESS; 199214501Srpaulo} 200214501Srpaulo 201214501Srpaulo 202214501Srpauloint eap_server_gtc_register(void) 203214501Srpaulo{ 204214501Srpaulo struct eap_method *eap; 205214501Srpaulo int ret; 206214501Srpaulo 207214501Srpaulo eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 208214501Srpaulo EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC"); 209214501Srpaulo if (eap == NULL) 210214501Srpaulo return -1; 211214501Srpaulo 212214501Srpaulo eap->init = eap_gtc_init; 213214501Srpaulo eap->reset = eap_gtc_reset; 214214501Srpaulo eap->buildReq = eap_gtc_buildReq; 215214501Srpaulo eap->check = eap_gtc_check; 216214501Srpaulo eap->process = eap_gtc_process; 217214501Srpaulo eap->isDone = eap_gtc_isDone; 218214501Srpaulo eap->isSuccess = eap_gtc_isSuccess; 219214501Srpaulo 220214501Srpaulo ret = eap_server_method_register(eap); 221214501Srpaulo if (ret) 222214501Srpaulo eap_server_method_free(eap); 223214501Srpaulo return ret; 224214501Srpaulo} 225