1189251Ssam/* 2189251Ssam * EAP peer method: EAP-GTC (RFC 3748) 3189251Ssam * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi> 4189251Ssam * 5189251Ssam * This program is free software; you can redistribute it and/or modify 6189251Ssam * it under the terms of the GNU General Public License version 2 as 7189251Ssam * published by the Free Software Foundation. 8189251Ssam * 9189251Ssam * Alternatively, this software may be distributed under the terms of BSD 10189251Ssam * license. 11189251Ssam * 12189251Ssam * See README and COPYING for more details. 13189251Ssam */ 14189251Ssam 15189251Ssam#include "includes.h" 16189251Ssam 17189251Ssam#include "common.h" 18189251Ssam#include "eap_i.h" 19189251Ssam 20189251Ssam 21189251Ssamstruct eap_gtc_data { 22189251Ssam int prefix; 23189251Ssam}; 24189251Ssam 25189251Ssam 26189251Ssamstatic void * eap_gtc_init(struct eap_sm *sm) 27189251Ssam{ 28189251Ssam struct eap_gtc_data *data; 29189251Ssam data = os_zalloc(sizeof(*data)); 30189251Ssam if (data == NULL) 31189251Ssam return NULL; 32189251Ssam 33189251Ssam if (sm->m && sm->m->vendor == EAP_VENDOR_IETF && 34189251Ssam sm->m->method == EAP_TYPE_FAST) { 35189251Ssam wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix " 36189251Ssam "with challenge/response"); 37189251Ssam data->prefix = 1; 38189251Ssam } 39189251Ssam return data; 40189251Ssam} 41189251Ssam 42189251Ssam 43189251Ssamstatic void eap_gtc_deinit(struct eap_sm *sm, void *priv) 44189251Ssam{ 45189251Ssam struct eap_gtc_data *data = priv; 46189251Ssam os_free(data); 47189251Ssam} 48189251Ssam 49189251Ssam 50189251Ssamstatic struct wpabuf * eap_gtc_process(struct eap_sm *sm, void *priv, 51189251Ssam struct eap_method_ret *ret, 52189251Ssam const struct wpabuf *reqData) 53189251Ssam{ 54189251Ssam struct eap_gtc_data *data = priv; 55189251Ssam struct wpabuf *resp; 56189251Ssam const u8 *pos, *password, *identity; 57189251Ssam size_t password_len, identity_len, len, plen; 58189251Ssam int otp; 59189251Ssam u8 id; 60189251Ssam 61189251Ssam pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, reqData, &len); 62189251Ssam if (pos == NULL) { 63189251Ssam ret->ignore = TRUE; 64189251Ssam return NULL; 65189251Ssam } 66189251Ssam id = eap_get_id(reqData); 67189251Ssam 68189251Ssam wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Request message", pos, len); 69189251Ssam if (data->prefix && 70189251Ssam (len < 10 || os_memcmp(pos, "CHALLENGE=", 10) != 0)) { 71189251Ssam wpa_printf(MSG_DEBUG, "EAP-GTC: Challenge did not start with " 72189251Ssam "expected prefix"); 73189251Ssam 74189251Ssam /* Send an empty response in order to allow tunneled 75189251Ssam * acknowledgement of the failure. This will also cover the 76189251Ssam * error case which seems to use EAP-MSCHAPv2 like error 77189251Ssam * reporting with EAP-GTC inside EAP-FAST tunnel. */ 78189251Ssam resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, 79189251Ssam 0, EAP_CODE_RESPONSE, id); 80189251Ssam return resp; 81189251Ssam } 82189251Ssam 83189251Ssam password = eap_get_config_otp(sm, &password_len); 84189251Ssam if (password) 85189251Ssam otp = 1; 86189251Ssam else { 87189251Ssam password = eap_get_config_password(sm, &password_len); 88189251Ssam otp = 0; 89189251Ssam } 90189251Ssam 91189251Ssam if (password == NULL) { 92189251Ssam wpa_printf(MSG_INFO, "EAP-GTC: Password not configured"); 93189251Ssam eap_sm_request_otp(sm, (const char *) pos, len); 94189251Ssam ret->ignore = TRUE; 95189251Ssam return NULL; 96189251Ssam } 97189251Ssam 98189251Ssam ret->ignore = FALSE; 99189251Ssam 100189251Ssam ret->methodState = data->prefix ? METHOD_MAY_CONT : METHOD_DONE; 101189251Ssam ret->decision = DECISION_COND_SUCC; 102189251Ssam ret->allowNotifications = FALSE; 103189251Ssam 104189251Ssam plen = password_len; 105189251Ssam identity = eap_get_config_identity(sm, &identity_len); 106189251Ssam if (identity == NULL) 107189251Ssam return NULL; 108189251Ssam if (data->prefix) 109189251Ssam plen += 9 + identity_len + 1; 110189251Ssam resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, plen, 111189251Ssam EAP_CODE_RESPONSE, id); 112189251Ssam if (resp == NULL) 113189251Ssam return NULL; 114189251Ssam if (data->prefix) { 115189251Ssam wpabuf_put_data(resp, "RESPONSE=", 9); 116189251Ssam wpabuf_put_data(resp, identity, identity_len); 117189251Ssam wpabuf_put_u8(resp, '\0'); 118189251Ssam } 119189251Ssam wpabuf_put_data(resp, password, password_len); 120189251Ssam wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response", 121189251Ssam wpabuf_head_u8(resp) + sizeof(struct eap_hdr) + 122189251Ssam 1, plen); 123189251Ssam 124189251Ssam if (otp) { 125189251Ssam wpa_printf(MSG_DEBUG, "EAP-GTC: Forgetting used password"); 126189251Ssam eap_clear_config_otp(sm); 127189251Ssam } 128189251Ssam 129189251Ssam return resp; 130189251Ssam} 131189251Ssam 132189251Ssam 133189251Ssamint eap_peer_gtc_register(void) 134189251Ssam{ 135189251Ssam struct eap_method *eap; 136189251Ssam int ret; 137189251Ssam 138189251Ssam eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 139189251Ssam EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC"); 140189251Ssam if (eap == NULL) 141189251Ssam return -1; 142189251Ssam 143189251Ssam eap->init = eap_gtc_init; 144189251Ssam eap->deinit = eap_gtc_deinit; 145189251Ssam eap->process = eap_gtc_process; 146189251Ssam 147189251Ssam ret = eap_peer_method_register(eap); 148189251Ssam if (ret) 149189251Ssam eap_peer_method_free(eap); 150189251Ssam return ret; 151189251Ssam} 152