1/* 2 * EAP peer method: 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 15struct eap_gtc_data { 16 int prefix; 17}; 18 19 20static void * eap_gtc_init(struct eap_sm *sm) 21{ 22 struct eap_gtc_data *data; 23 data = os_zalloc(sizeof(*data)); 24 if (data == NULL) 25 return NULL; 26 27 if (sm->m && sm->m->vendor == EAP_VENDOR_IETF && 28 sm->m->method == EAP_TYPE_FAST) { 29 wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix " 30 "with challenge/response"); 31 data->prefix = 1; 32 } 33 return data; 34} 35 36 37static void eap_gtc_deinit(struct eap_sm *sm, void *priv) 38{ 39 struct eap_gtc_data *data = priv; 40 os_free(data); 41} 42 43 44static struct wpabuf * eap_gtc_process(struct eap_sm *sm, void *priv, 45 struct eap_method_ret *ret, 46 const struct wpabuf *reqData) 47{ 48 struct eap_gtc_data *data = priv; 49 struct wpabuf *resp; 50 const u8 *pos, *password, *identity; 51 size_t password_len, identity_len, len, plen; 52 int otp; 53 u8 id; 54 55 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, reqData, &len); 56 if (pos == NULL) { 57 ret->ignore = TRUE; 58 return NULL; 59 } 60 id = eap_get_id(reqData); 61 62 wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Request message", pos, len); 63 if (data->prefix && 64 (len < 10 || os_memcmp(pos, "CHALLENGE=", 10) != 0)) { 65 wpa_printf(MSG_DEBUG, "EAP-GTC: Challenge did not start with " 66 "expected prefix"); 67 68 /* Send an empty response in order to allow tunneled 69 * acknowledgement of the failure. This will also cover the 70 * error case which seems to use EAP-MSCHAPv2 like error 71 * reporting with EAP-GTC inside EAP-FAST tunnel. */ 72 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, 73 0, EAP_CODE_RESPONSE, id); 74 return resp; 75 } 76 77 password = eap_get_config_otp(sm, &password_len); 78 if (password) 79 otp = 1; 80 else { 81 password = eap_get_config_password(sm, &password_len); 82 otp = 0; 83 } 84 85 if (password == NULL) { 86 wpa_printf(MSG_INFO, "EAP-GTC: Password not configured"); 87 eap_sm_request_otp(sm, (const char *) pos, len); 88 ret->ignore = TRUE; 89 return NULL; 90 } 91 92 ret->ignore = FALSE; 93 94 ret->methodState = data->prefix ? METHOD_MAY_CONT : METHOD_DONE; 95 ret->decision = DECISION_COND_SUCC; 96 ret->allowNotifications = FALSE; 97 98 plen = password_len; 99 identity = eap_get_config_identity(sm, &identity_len); 100 if (identity == NULL) 101 return NULL; 102 if (data->prefix) 103 plen += 9 + identity_len + 1; 104 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, plen, 105 EAP_CODE_RESPONSE, id); 106 if (resp == NULL) 107 return NULL; 108 if (data->prefix) { 109 wpabuf_put_data(resp, "RESPONSE=", 9); 110 wpabuf_put_data(resp, identity, identity_len); 111 wpabuf_put_u8(resp, '\0'); 112 } 113 wpabuf_put_data(resp, password, password_len); 114 wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response", 115 wpabuf_head_u8(resp) + sizeof(struct eap_hdr) + 116 1, plen); 117 118 if (otp) { 119 wpa_printf(MSG_DEBUG, "EAP-GTC: Forgetting used password"); 120 eap_clear_config_otp(sm); 121 } 122 123 return resp; 124} 125 126 127int eap_peer_gtc_register(void) 128{ 129 struct eap_method *eap; 130 131 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 132 EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC"); 133 if (eap == NULL) 134 return -1; 135 136 eap->init = eap_gtc_init; 137 eap->deinit = eap_gtc_deinit; 138 eap->process = eap_gtc_process; 139 140 return eap_peer_method_register(eap); 141} 142