13ff40c12SJohn Marino /*
23ff40c12SJohn Marino * hostapd / EAP-GTC (RFC 3748)
33ff40c12SJohn Marino * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
43ff40c12SJohn Marino *
53ff40c12SJohn Marino * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino * See README for more details.
73ff40c12SJohn Marino */
83ff40c12SJohn Marino
93ff40c12SJohn Marino #include "includes.h"
103ff40c12SJohn Marino
113ff40c12SJohn Marino #include "common.h"
123ff40c12SJohn Marino #include "eap_i.h"
133ff40c12SJohn Marino
143ff40c12SJohn Marino
153ff40c12SJohn Marino struct eap_gtc_data {
163ff40c12SJohn Marino enum { CONTINUE, SUCCESS, FAILURE } state;
173ff40c12SJohn Marino int prefix;
183ff40c12SJohn Marino };
193ff40c12SJohn Marino
203ff40c12SJohn Marino
eap_gtc_init(struct eap_sm * sm)213ff40c12SJohn Marino static void * eap_gtc_init(struct eap_sm *sm)
223ff40c12SJohn Marino {
233ff40c12SJohn Marino struct eap_gtc_data *data;
243ff40c12SJohn Marino
253ff40c12SJohn Marino data = os_zalloc(sizeof(*data));
263ff40c12SJohn Marino if (data == NULL)
273ff40c12SJohn Marino return NULL;
283ff40c12SJohn Marino data->state = CONTINUE;
293ff40c12SJohn Marino
303ff40c12SJohn Marino #ifdef EAP_SERVER_FAST
313ff40c12SJohn Marino if (sm->m && sm->m->vendor == EAP_VENDOR_IETF &&
323ff40c12SJohn Marino sm->m->method == EAP_TYPE_FAST) {
333ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix "
343ff40c12SJohn Marino "with challenge/response");
353ff40c12SJohn Marino data->prefix = 1;
363ff40c12SJohn Marino }
373ff40c12SJohn Marino #endif /* EAP_SERVER_FAST */
383ff40c12SJohn Marino
393ff40c12SJohn Marino return data;
403ff40c12SJohn Marino }
413ff40c12SJohn Marino
423ff40c12SJohn Marino
eap_gtc_reset(struct eap_sm * sm,void * priv)433ff40c12SJohn Marino static void eap_gtc_reset(struct eap_sm *sm, void *priv)
443ff40c12SJohn Marino {
453ff40c12SJohn Marino struct eap_gtc_data *data = priv;
463ff40c12SJohn Marino os_free(data);
473ff40c12SJohn Marino }
483ff40c12SJohn Marino
493ff40c12SJohn Marino
eap_gtc_buildReq(struct eap_sm * sm,void * priv,u8 id)503ff40c12SJohn Marino static struct wpabuf * eap_gtc_buildReq(struct eap_sm *sm, void *priv, u8 id)
513ff40c12SJohn Marino {
523ff40c12SJohn Marino struct eap_gtc_data *data = priv;
533ff40c12SJohn Marino struct wpabuf *req;
543ff40c12SJohn Marino char *msg;
553ff40c12SJohn Marino size_t msg_len;
563ff40c12SJohn Marino
573ff40c12SJohn Marino msg = data->prefix ? "CHALLENGE=Password" : "Password";
583ff40c12SJohn Marino
593ff40c12SJohn Marino msg_len = os_strlen(msg);
603ff40c12SJohn Marino req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, msg_len,
613ff40c12SJohn Marino EAP_CODE_REQUEST, id);
623ff40c12SJohn Marino if (req == NULL) {
633ff40c12SJohn Marino wpa_printf(MSG_ERROR, "EAP-GTC: Failed to allocate memory for "
643ff40c12SJohn Marino "request");
653ff40c12SJohn Marino data->state = FAILURE;
663ff40c12SJohn Marino return NULL;
673ff40c12SJohn Marino }
683ff40c12SJohn Marino
693ff40c12SJohn Marino wpabuf_put_data(req, msg, msg_len);
703ff40c12SJohn Marino
713ff40c12SJohn Marino data->state = CONTINUE;
723ff40c12SJohn Marino
733ff40c12SJohn Marino return req;
743ff40c12SJohn Marino }
753ff40c12SJohn Marino
763ff40c12SJohn Marino
eap_gtc_check(struct eap_sm * sm,void * priv,struct wpabuf * respData)773ff40c12SJohn Marino static Boolean eap_gtc_check(struct eap_sm *sm, void *priv,
783ff40c12SJohn Marino struct wpabuf *respData)
793ff40c12SJohn Marino {
803ff40c12SJohn Marino const u8 *pos;
813ff40c12SJohn Marino size_t len;
823ff40c12SJohn Marino
833ff40c12SJohn Marino pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, respData, &len);
843ff40c12SJohn Marino if (pos == NULL || len < 1) {
853ff40c12SJohn Marino wpa_printf(MSG_INFO, "EAP-GTC: Invalid frame");
863ff40c12SJohn Marino return TRUE;
873ff40c12SJohn Marino }
883ff40c12SJohn Marino
893ff40c12SJohn Marino return FALSE;
903ff40c12SJohn Marino }
913ff40c12SJohn Marino
923ff40c12SJohn Marino
eap_gtc_process(struct eap_sm * sm,void * priv,struct wpabuf * respData)933ff40c12SJohn Marino static void eap_gtc_process(struct eap_sm *sm, void *priv,
943ff40c12SJohn Marino struct wpabuf *respData)
953ff40c12SJohn Marino {
963ff40c12SJohn Marino struct eap_gtc_data *data = priv;
973ff40c12SJohn Marino const u8 *pos;
983ff40c12SJohn Marino size_t rlen;
993ff40c12SJohn Marino
1003ff40c12SJohn Marino pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, respData, &rlen);
1013ff40c12SJohn Marino if (pos == NULL || rlen < 1)
1023ff40c12SJohn Marino return; /* Should not happen - frame already validated */
1033ff40c12SJohn Marino
1043ff40c12SJohn Marino wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response", pos, rlen);
1053ff40c12SJohn Marino
1063ff40c12SJohn Marino #ifdef EAP_SERVER_FAST
1073ff40c12SJohn Marino if (data->prefix) {
1083ff40c12SJohn Marino const u8 *pos2, *end;
1093ff40c12SJohn Marino /* "RESPONSE=<user>\0<password>" */
1103ff40c12SJohn Marino if (rlen < 10) {
1113ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-GTC: Too short response "
1123ff40c12SJohn Marino "for EAP-FAST prefix");
1133ff40c12SJohn Marino data->state = FAILURE;
1143ff40c12SJohn Marino return;
1153ff40c12SJohn Marino }
1163ff40c12SJohn Marino
1173ff40c12SJohn Marino end = pos + rlen;
1183ff40c12SJohn Marino pos += 9;
1193ff40c12SJohn Marino pos2 = pos;
1203ff40c12SJohn Marino while (pos2 < end && *pos2)
1213ff40c12SJohn Marino pos2++;
1223ff40c12SJohn Marino if (pos2 == end) {
1233ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-GTC: No password in "
1243ff40c12SJohn Marino "response to EAP-FAST prefix");
1253ff40c12SJohn Marino data->state = FAILURE;
1263ff40c12SJohn Marino return;
1273ff40c12SJohn Marino }
1283ff40c12SJohn Marino
1293ff40c12SJohn Marino wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Response user",
1303ff40c12SJohn Marino pos, pos2 - pos);
1313ff40c12SJohn Marino if (sm->identity && sm->require_identity_match &&
1323ff40c12SJohn Marino (pos2 - pos != (int) sm->identity_len ||
1333ff40c12SJohn Marino os_memcmp(pos, sm->identity, sm->identity_len))) {
1343ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-GTC: Phase 2 Identity did "
1353ff40c12SJohn Marino "not match with required Identity");
1363ff40c12SJohn Marino wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Expected "
1373ff40c12SJohn Marino "identity",
1383ff40c12SJohn Marino sm->identity, sm->identity_len);
1393ff40c12SJohn Marino data->state = FAILURE;
1403ff40c12SJohn Marino return;
1413ff40c12SJohn Marino } else {
1423ff40c12SJohn Marino os_free(sm->identity);
1433ff40c12SJohn Marino sm->identity_len = pos2 - pos;
144*a1157835SDaniel Fojt sm->identity = os_memdup(pos, sm->identity_len);
1453ff40c12SJohn Marino if (sm->identity == NULL) {
1463ff40c12SJohn Marino data->state = FAILURE;
1473ff40c12SJohn Marino return;
1483ff40c12SJohn Marino }
1493ff40c12SJohn Marino }
1503ff40c12SJohn Marino
1513ff40c12SJohn Marino if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
1523ff40c12SJohn Marino wpa_hexdump_ascii(MSG_DEBUG, "EAP-GTC: Phase2 "
1533ff40c12SJohn Marino "Identity not found in the user "
1543ff40c12SJohn Marino "database",
1553ff40c12SJohn Marino sm->identity, sm->identity_len);
1563ff40c12SJohn Marino data->state = FAILURE;
1573ff40c12SJohn Marino return;
1583ff40c12SJohn Marino }
1593ff40c12SJohn Marino
1603ff40c12SJohn Marino pos = pos2 + 1;
1613ff40c12SJohn Marino rlen = end - pos;
1623ff40c12SJohn Marino wpa_hexdump_ascii_key(MSG_MSGDUMP,
1633ff40c12SJohn Marino "EAP-GTC: Response password",
1643ff40c12SJohn Marino pos, rlen);
1653ff40c12SJohn Marino }
1663ff40c12SJohn Marino #endif /* EAP_SERVER_FAST */
1673ff40c12SJohn Marino
1683ff40c12SJohn Marino if (sm->user == NULL || sm->user->password == NULL ||
1693ff40c12SJohn Marino sm->user->password_hash) {
1703ff40c12SJohn Marino wpa_printf(MSG_INFO, "EAP-GTC: Plaintext password not "
1713ff40c12SJohn Marino "configured");
1723ff40c12SJohn Marino data->state = FAILURE;
1733ff40c12SJohn Marino return;
1743ff40c12SJohn Marino }
1753ff40c12SJohn Marino
1763ff40c12SJohn Marino if (rlen != sm->user->password_len ||
177*a1157835SDaniel Fojt os_memcmp_const(pos, sm->user->password, rlen) != 0) {
1783ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Failure");
1793ff40c12SJohn Marino data->state = FAILURE;
1803ff40c12SJohn Marino } else {
1813ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Success");
1823ff40c12SJohn Marino data->state = SUCCESS;
1833ff40c12SJohn Marino }
1843ff40c12SJohn Marino }
1853ff40c12SJohn Marino
1863ff40c12SJohn Marino
eap_gtc_isDone(struct eap_sm * sm,void * priv)1873ff40c12SJohn Marino static Boolean eap_gtc_isDone(struct eap_sm *sm, void *priv)
1883ff40c12SJohn Marino {
1893ff40c12SJohn Marino struct eap_gtc_data *data = priv;
1903ff40c12SJohn Marino return data->state != CONTINUE;
1913ff40c12SJohn Marino }
1923ff40c12SJohn Marino
1933ff40c12SJohn Marino
eap_gtc_isSuccess(struct eap_sm * sm,void * priv)1943ff40c12SJohn Marino static Boolean eap_gtc_isSuccess(struct eap_sm *sm, void *priv)
1953ff40c12SJohn Marino {
1963ff40c12SJohn Marino struct eap_gtc_data *data = priv;
1973ff40c12SJohn Marino return data->state == SUCCESS;
1983ff40c12SJohn Marino }
1993ff40c12SJohn Marino
2003ff40c12SJohn Marino
eap_server_gtc_register(void)2013ff40c12SJohn Marino int eap_server_gtc_register(void)
2023ff40c12SJohn Marino {
2033ff40c12SJohn Marino struct eap_method *eap;
2043ff40c12SJohn Marino
2053ff40c12SJohn Marino eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
2063ff40c12SJohn Marino EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC");
2073ff40c12SJohn Marino if (eap == NULL)
2083ff40c12SJohn Marino return -1;
2093ff40c12SJohn Marino
2103ff40c12SJohn Marino eap->init = eap_gtc_init;
2113ff40c12SJohn Marino eap->reset = eap_gtc_reset;
2123ff40c12SJohn Marino eap->buildReq = eap_gtc_buildReq;
2133ff40c12SJohn Marino eap->check = eap_gtc_check;
2143ff40c12SJohn Marino eap->process = eap_gtc_process;
2153ff40c12SJohn Marino eap->isDone = eap_gtc_isDone;
2163ff40c12SJohn Marino eap->isSuccess = eap_gtc_isSuccess;
2173ff40c12SJohn Marino
218*a1157835SDaniel Fojt return eap_server_method_register(eap);
2193ff40c12SJohn Marino }
220