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