1 /* 2 * hostapd / EAP-GTC (RFC 3748) 3 * Copyright (c) 2004-2006, 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 "eap_i.h" 19 20 21 struct eap_gtc_data { 22 enum { CONTINUE, SUCCESS, FAILURE } state; 23 int prefix; 24 }; 25 26 27 static void * eap_gtc_init(struct eap_sm *sm) 28 { 29 struct eap_gtc_data *data; 30 31 data = os_zalloc(sizeof(*data)); 32 if (data == NULL) 33 return NULL; 34 data->state = CONTINUE; 35 36 #ifdef EAP_FAST 37 if (sm->m && sm->m->vendor == EAP_VENDOR_IETF && 38 sm->m->method == EAP_TYPE_FAST) { 39 wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix " 40 "with challenge/response"); 41 data->prefix = 1; 42 } 43 #endif /* EAP_FAST */ 44 45 return data; 46 } 47 48 49 static void eap_gtc_reset(struct eap_sm *sm, void *priv) 50 { 51 struct eap_gtc_data *data = priv; 52 os_free(data); 53 } 54 55 56 static struct wpabuf * eap_gtc_buildReq(struct eap_sm *sm, void *priv, u8 id) 57 { 58 struct eap_gtc_data *data = priv; 59 struct wpabuf *req; 60 char *msg; 61 size_t msg_len; 62 63 msg = data->prefix ? "CHALLENGE=Password" : "Password"; 64 65 msg_len = os_strlen(msg); 66 req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, msg_len, 67 EAP_CODE_REQUEST, id); 68 if (req == NULL) { 69 wpa_printf(MSG_ERROR, "EAP-GTC: Failed to allocate memory for " 70 "request"); 71 data->state = FAILURE; 72 return NULL; 73 } 74 75 wpabuf_put_data(req, msg, msg_len); 76 77 data->state = CONTINUE; 78 79 return req; 80 } 81 82 83 static Boolean eap_gtc_check(struct eap_sm *sm, void *priv, 84 struct wpabuf *respData) 85 { 86 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 99 static 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_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_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 194 static 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 201 static 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 208 int 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