1 /* 2 * hostapd / EAP-GTC (RFC 3748) 3 * Copyright (c) 2004-2006, 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 "eap_i.h" 13 14 15 struct eap_gtc_data { 16 enum { CONTINUE, SUCCESS, FAILURE } state; 17 int prefix; 18 }; 19 20 21 static void * eap_gtc_init(struct eap_sm *sm) 22 { 23 struct eap_gtc_data *data; 24 25 data = os_zalloc(sizeof(*data)); 26 if (data == NULL) 27 return NULL; 28 data->state = CONTINUE; 29 30 #ifdef EAP_SERVER_FAST 31 if (sm->m && sm->m->vendor == EAP_VENDOR_IETF && 32 sm->m->method == EAP_TYPE_FAST) { 33 wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix " 34 "with challenge/response"); 35 data->prefix = 1; 36 } 37 #endif /* EAP_SERVER_FAST */ 38 39 return data; 40 } 41 42 43 static void eap_gtc_reset(struct eap_sm *sm, void *priv) 44 { 45 struct eap_gtc_data *data = priv; 46 os_free(data); 47 } 48 49 50 static struct wpabuf * eap_gtc_buildReq(struct eap_sm *sm, void *priv, u8 id) 51 { 52 struct eap_gtc_data *data = priv; 53 struct wpabuf *req; 54 char *msg; 55 size_t msg_len; 56 57 msg = data->prefix ? "CHALLENGE=Password" : "Password"; 58 59 msg_len = os_strlen(msg); 60 req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, msg_len, 61 EAP_CODE_REQUEST, id); 62 if (req == NULL) { 63 wpa_printf(MSG_ERROR, "EAP-GTC: Failed to allocate memory for " 64 "request"); 65 data->state = FAILURE; 66 return NULL; 67 } 68 69 wpabuf_put_data(req, msg, msg_len); 70 71 data->state = CONTINUE; 72 73 return req; 74 } 75 76 77 static Boolean eap_gtc_check(struct eap_sm *sm, void *priv, 78 struct wpabuf *respData) 79 { 80 const u8 *pos; 81 size_t len; 82 83 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, respData, &len); 84 if (pos == NULL || len < 1) { 85 wpa_printf(MSG_INFO, "EAP-GTC: Invalid frame"); 86 return TRUE; 87 } 88 89 return FALSE; 90 } 91 92 93 static void eap_gtc_process(struct eap_sm *sm, void *priv, 94 struct wpabuf *respData) 95 { 96 struct eap_gtc_data *data = priv; 97 const u8 *pos; 98 size_t rlen; 99 100 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, respData, &rlen); 101 if (pos == NULL || rlen < 1) 102 return; /* Should not happen - frame already validated */ 103 104 wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response", pos, rlen); 105 106 #ifdef EAP_SERVER_FAST 107 if (data->prefix) { 108 const u8 *pos2, *end; 109 /* "RESPONSE=<user>\0<password>" */ 110 if (rlen < 10) { 111 wpa_printf(MSG_DEBUG, "EAP-GTC: Too short response " 112 "for EAP-FAST prefix"); 113 data->state = FAILURE; 114 return; 115 } 116 117 end = pos + rlen; 118 pos += 9; 119 pos2 = pos; 120 while (pos2 < end && *pos2) 121 pos2++; 122 if (pos2 == end) { 123 wpa_printf(MSG_DEBUG, "EAP-GTC: No password in " 124 "response to EAP-FAST prefix"); 125 data->state = FAILURE; 126 return; 127 } 128 129 wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Response user", 130 pos, pos2 - pos); 131 if (sm->identity && sm->require_identity_match && 132 (pos2 - pos != (int) sm->identity_len || 133 os_memcmp(pos, sm->identity, sm->identity_len))) { 134 wpa_printf(MSG_DEBUG, "EAP-GTC: Phase 2 Identity did " 135 "not match with required Identity"); 136 wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Expected " 137 "identity", 138 sm->identity, sm->identity_len); 139 data->state = FAILURE; 140 return; 141 } else { 142 os_free(sm->identity); 143 sm->identity_len = pos2 - pos; 144 sm->identity = os_malloc(sm->identity_len); 145 if (sm->identity == NULL) { 146 data->state = FAILURE; 147 return; 148 } 149 os_memcpy(sm->identity, pos, sm->identity_len); 150 } 151 152 if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { 153 wpa_hexdump_ascii(MSG_DEBUG, "EAP-GTC: Phase2 " 154 "Identity not found in the user " 155 "database", 156 sm->identity, sm->identity_len); 157 data->state = FAILURE; 158 return; 159 } 160 161 pos = pos2 + 1; 162 rlen = end - pos; 163 wpa_hexdump_ascii_key(MSG_MSGDUMP, 164 "EAP-GTC: Response password", 165 pos, rlen); 166 } 167 #endif /* EAP_SERVER_FAST */ 168 169 if (sm->user == NULL || sm->user->password == NULL || 170 sm->user->password_hash) { 171 wpa_printf(MSG_INFO, "EAP-GTC: Plaintext password not " 172 "configured"); 173 data->state = FAILURE; 174 return; 175 } 176 177 if (rlen != sm->user->password_len || 178 os_memcmp(pos, sm->user->password, rlen) != 0) { 179 wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Failure"); 180 data->state = FAILURE; 181 } else { 182 wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Success"); 183 data->state = SUCCESS; 184 } 185 } 186 187 188 static Boolean eap_gtc_isDone(struct eap_sm *sm, void *priv) 189 { 190 struct eap_gtc_data *data = priv; 191 return data->state != CONTINUE; 192 } 193 194 195 static Boolean eap_gtc_isSuccess(struct eap_sm *sm, void *priv) 196 { 197 struct eap_gtc_data *data = priv; 198 return data->state == SUCCESS; 199 } 200 201 202 int eap_server_gtc_register(void) 203 { 204 struct eap_method *eap; 205 int ret; 206 207 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 208 EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC"); 209 if (eap == NULL) 210 return -1; 211 212 eap->init = eap_gtc_init; 213 eap->reset = eap_gtc_reset; 214 eap->buildReq = eap_gtc_buildReq; 215 eap->check = eap_gtc_check; 216 eap->process = eap_gtc_process; 217 eap->isDone = eap_gtc_isDone; 218 eap->isSuccess = eap_gtc_isSuccess; 219 220 ret = eap_server_method_register(eap); 221 if (ret) 222 eap_server_method_free(eap); 223 return ret; 224 } 225