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_memdup(pos, sm->identity_len); 145 if (sm->identity == NULL) { 146 data->state = FAILURE; 147 return; 148 } 149 } 150 151 if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { 152 wpa_hexdump_ascii(MSG_DEBUG, "EAP-GTC: Phase2 " 153 "Identity not found in the user " 154 "database", 155 sm->identity, sm->identity_len); 156 data->state = FAILURE; 157 return; 158 } 159 160 pos = pos2 + 1; 161 rlen = end - pos; 162 wpa_hexdump_ascii_key(MSG_MSGDUMP, 163 "EAP-GTC: Response password", 164 pos, rlen); 165 } 166 #endif /* EAP_SERVER_FAST */ 167 168 if (sm->user == NULL || sm->user->password == NULL || 169 sm->user->password_hash) { 170 wpa_printf(MSG_INFO, "EAP-GTC: Plaintext password not " 171 "configured"); 172 data->state = FAILURE; 173 return; 174 } 175 176 if (rlen != sm->user->password_len || 177 os_memcmp_const(pos, sm->user->password, rlen) != 0) { 178 wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Failure"); 179 data->state = FAILURE; 180 } else { 181 wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Success"); 182 data->state = SUCCESS; 183 } 184 } 185 186 187 static Boolean eap_gtc_isDone(struct eap_sm *sm, void *priv) 188 { 189 struct eap_gtc_data *data = priv; 190 return data->state != CONTINUE; 191 } 192 193 194 static Boolean eap_gtc_isSuccess(struct eap_sm *sm, void *priv) 195 { 196 struct eap_gtc_data *data = priv; 197 return data->state == SUCCESS; 198 } 199 200 201 int eap_server_gtc_register(void) 202 { 203 struct eap_method *eap; 204 205 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 206 EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC"); 207 if (eap == NULL) 208 return -1; 209 210 eap->init = eap_gtc_init; 211 eap->reset = eap_gtc_reset; 212 eap->buildReq = eap_gtc_buildReq; 213 eap->check = eap_gtc_check; 214 eap->process = eap_gtc_process; 215 eap->isDone = eap_gtc_isDone; 216 eap->isSuccess = eap_gtc_isSuccess; 217 218 return eap_server_method_register(eap); 219 } 220