1193635Sedwin/* 2193635Sedwin * hostapd / EAP-GTC (RFC 3748) 3193635Sedwin * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi> 4193635Sedwin * 5193635Sedwin * This program is free software; you can redistribute it and/or modify 6193635Sedwin * it under the terms of the GNU General Public License version 2 as 7193635Sedwin * published by the Free Software Foundation. 8193635Sedwin * 9193635Sedwin * Alternatively, this software may be distributed under the terms of BSD 10193635Sedwin * license. 11193635Sedwin * 12193635Sedwin * See README and COPYING for more details. 13193635Sedwin */ 14193635Sedwin 15193635Sedwin#include "includes.h" 16195652Sdwmalone 17195652Sdwmalone#include "common.h" 18195652Sdwmalone#include "eap_i.h" 19193635Sedwin 20259974Sdelphij 21193635Sedwinstruct eap_gtc_data { 22239464Sdelphij enum { CONTINUE, SUCCESS, FAILURE } state; 23239464Sdelphij int prefix; 24239464Sdelphij}; 25239464Sdelphij 26193635Sedwin 27193635Sedwinstatic void * eap_gtc_init(struct eap_sm *sm) 28193635Sedwin{ 29193635Sedwin struct eap_gtc_data *data; 30195652Sdwmalone 31193635Sedwin data = os_zalloc(sizeof(*data)); 32193635Sedwin if (data == NULL) 33239464Sdelphij return NULL; 34239464Sdelphij data->state = CONTINUE; 35239464Sdelphij 36193635Sedwin#ifdef EAP_SERVER_FAST 37193635Sedwin if (sm->m && sm->m->vendor == EAP_VENDOR_IETF && 38259974Sdelphij sm->m->method == EAP_TYPE_FAST) { 39193635Sedwin wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix " 40259974Sdelphij "with challenge/response"); 41259974Sdelphij data->prefix = 1; 42259974Sdelphij } 43259974Sdelphij#endif /* EAP_SERVER_FAST */ 44259974Sdelphij 45259974Sdelphij return data; 46285612Sdelphij} 47285612Sdelphij 48259974Sdelphij 49259974Sdelphijstatic void eap_gtc_reset(struct eap_sm *sm, void *priv) 50259974Sdelphij{ 51259974Sdelphij struct eap_gtc_data *data = priv; 52259974Sdelphij os_free(data); 53259974Sdelphij} 54259974Sdelphij 55259974Sdelphij 56259974Sdelphijstatic struct wpabuf * eap_gtc_buildReq(struct eap_sm *sm, void *priv, u8 id) 57259974Sdelphij{ 58193635Sedwin struct eap_gtc_data *data = priv; 59193635Sedwin struct wpabuf *req; 60193635Sedwin char *msg; 61193635Sedwin size_t msg_len; 62193635Sedwin 63193635Sedwin msg = data->prefix ? "CHALLENGE=Password" : "Password"; 64259974Sdelphij 65259974Sdelphij msg_len = os_strlen(msg); 66259974Sdelphij req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, msg_len, 67259974Sdelphij EAP_CODE_REQUEST, id); 68259974Sdelphij if (req == NULL) { 69193635Sedwin wpa_printf(MSG_ERROR, "EAP-GTC: Failed to allocate memory for " 70193635Sedwin "request"); 71195652Sdwmalone data->state = FAILURE; 72195652Sdwmalone return NULL; 73195652Sdwmalone } 74195652Sdwmalone 75195652Sdwmalone wpabuf_put_data(req, msg, msg_len); 76195652Sdwmalone 77193635Sedwin data->state = CONTINUE; 78195652Sdwmalone 79195652Sdwmalone return req; 80295461Scy} 81295461Scy 82295461Scy 83295461Scystatic Boolean eap_gtc_check(struct eap_sm *sm, void *priv, 84295461Scy struct wpabuf *respData) 85295461Scy{ 86295461Scy const u8 *pos; 87 size_t len; 88 89 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, respData, &len); 90 if (pos == NULL || len < 1) { 91 wpa_printf(MSG_INFO, "EAP-GTC: Invalid frame"); 92 return TRUE; 93 } 94 95 return FALSE; 96} 97 98 99static void eap_gtc_process(struct eap_sm *sm, void *priv, 100 struct wpabuf *respData) 101{ 102 struct eap_gtc_data *data = priv; 103 const u8 *pos; 104 size_t rlen; 105 106 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, respData, &rlen); 107 if (pos == NULL || rlen < 1) 108 return; /* Should not happen - frame already validated */ 109 110 wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response", pos, rlen); 111 112#ifdef EAP_SERVER_FAST 113 if (data->prefix) { 114 const u8 *pos2, *end; 115 /* "RESPONSE=<user>\0<password>" */ 116 if (rlen < 10) { 117 wpa_printf(MSG_DEBUG, "EAP-GTC: Too short response " 118 "for EAP-FAST prefix"); 119 data->state = FAILURE; 120 return; 121 } 122 123 end = pos + rlen; 124 pos += 9; 125 pos2 = pos; 126 while (pos2 < end && *pos2) 127 pos2++; 128 if (pos2 == end) { 129 wpa_printf(MSG_DEBUG, "EAP-GTC: No password in " 130 "response to EAP-FAST prefix"); 131 data->state = FAILURE; 132 return; 133 } 134 135 wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Response user", 136 pos, pos2 - pos); 137 if (sm->identity && sm->require_identity_match && 138 (pos2 - pos != (int) sm->identity_len || 139 os_memcmp(pos, sm->identity, sm->identity_len))) { 140 wpa_printf(MSG_DEBUG, "EAP-GTC: Phase 2 Identity did " 141 "not match with required Identity"); 142 wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Expected " 143 "identity", 144 sm->identity, sm->identity_len); 145 data->state = FAILURE; 146 return; 147 } else { 148 os_free(sm->identity); 149 sm->identity_len = pos2 - pos; 150 sm->identity = os_malloc(sm->identity_len); 151 if (sm->identity == NULL) { 152 data->state = FAILURE; 153 return; 154 } 155 os_memcpy(sm->identity, pos, sm->identity_len); 156 } 157 158 if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { 159 wpa_hexdump_ascii(MSG_DEBUG, "EAP-GTC: Phase2 " 160 "Identity not found in the user " 161 "database", 162 sm->identity, sm->identity_len); 163 data->state = FAILURE; 164 return; 165 } 166 167 pos = pos2 + 1; 168 rlen = end - pos; 169 wpa_hexdump_ascii_key(MSG_MSGDUMP, 170 "EAP-GTC: Response password", 171 pos, rlen); 172 } 173#endif /* EAP_SERVER_FAST */ 174 175 if (sm->user == NULL || sm->user->password == NULL || 176 sm->user->password_hash) { 177 wpa_printf(MSG_INFO, "EAP-GTC: Plaintext password not " 178 "configured"); 179 data->state = FAILURE; 180 return; 181 } 182 183 if (rlen != sm->user->password_len || 184 os_memcmp(pos, sm->user->password, rlen) != 0) { 185 wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Failure"); 186 data->state = FAILURE; 187 } else { 188 wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Success"); 189 data->state = SUCCESS; 190 } 191} 192 193 194static Boolean eap_gtc_isDone(struct eap_sm *sm, void *priv) 195{ 196 struct eap_gtc_data *data = priv; 197 return data->state != CONTINUE; 198} 199 200 201static Boolean eap_gtc_isSuccess(struct eap_sm *sm, void *priv) 202{ 203 struct eap_gtc_data *data = priv; 204 return data->state == SUCCESS; 205} 206 207 208int eap_server_gtc_register(void) 209{ 210 struct eap_method *eap; 211 int ret; 212 213 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 214 EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC"); 215 if (eap == NULL) 216 return -1; 217 218 eap->init = eap_gtc_init; 219 eap->reset = eap_gtc_reset; 220 eap->buildReq = eap_gtc_buildReq; 221 eap->check = eap_gtc_check; 222 eap->process = eap_gtc_process; 223 eap->isDone = eap_gtc_isDone; 224 eap->isSuccess = eap_gtc_isSuccess; 225 226 ret = eap_server_method_register(eap); 227 if (ret) 228 eap_server_method_free(eap); 229 return ret; 230} 231