1 /* 2 * EAP peer method: Test method for vendor specific (expanded) EAP type 3 * Copyright (c) 2005-2006, Jouni Malinen <j (at) w1.fi> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 * 14 * This file implements a vendor specific test method using EAP expanded types. 15 * This is only for test use and must not be used for authentication since no 16 * security is provided. 17 */ 18 19 #include "includes.h" 20 21 #include "common.h" 22 #include "eap_i.h" 23 #ifdef TEST_PENDING_REQUEST 24 #include "eloop.h" 25 #endif /* TEST_PENDING_REQUEST */ 26 27 28 #define EAP_VENDOR_ID 0xfffefd 29 #define EAP_VENDOR_TYPE 0xfcfbfaf9 30 31 32 /* #define TEST_PENDING_REQUEST */ 33 34 struct eap_vendor_test_data { 35 enum { INIT, CONFIRM, SUCCESS } state; 36 int first_try; 37 }; 38 39 40 static void * eap_vendor_test_init(struct eap_sm *sm) 41 { 42 struct eap_vendor_test_data *data; 43 data = os_zalloc(sizeof(*data)); 44 if (data == NULL) 45 return NULL; 46 data->state = INIT; 47 data->first_try = 1; 48 return data; 49 } 50 51 52 static void eap_vendor_test_deinit(struct eap_sm *sm, void *priv) 53 { 54 struct eap_vendor_test_data *data = priv; 55 os_free(data); 56 } 57 58 59 #ifdef TEST_PENDING_REQUEST 60 static void eap_vendor_ready(void *eloop_ctx, void *timeout_ctx) 61 { 62 struct eap_sm *sm = eloop_ctx; 63 wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Ready to re-process pending " 64 "request"); 65 eap_notify_pending(sm); 66 } 67 #endif /* TEST_PENDING_REQUEST */ 68 69 70 static struct wpabuf * eap_vendor_test_process(struct eap_sm *sm, void *priv, 71 struct eap_method_ret *ret, 72 const struct wpabuf *reqData) 73 { 74 struct eap_vendor_test_data *data = priv; 75 struct wpabuf *resp; 76 const u8 *pos; 77 size_t len; 78 79 pos = eap_hdr_validate(EAP_VENDOR_ID, EAP_VENDOR_TYPE, reqData, &len); 80 if (pos == NULL || len < 1) { 81 ret->ignore = TRUE; 82 return NULL; 83 } 84 85 if (data->state == INIT && *pos != 1) { 86 wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message " 87 "%d in INIT state", *pos); 88 ret->ignore = TRUE; 89 return NULL; 90 } 91 92 if (data->state == CONFIRM && *pos != 3) { 93 wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message " 94 "%d in CONFIRM state", *pos); 95 ret->ignore = TRUE; 96 return NULL; 97 } 98 99 if (data->state == SUCCESS) { 100 wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message " 101 "in SUCCESS state"); 102 ret->ignore = TRUE; 103 return NULL; 104 } 105 106 if (data->state == CONFIRM) { 107 #ifdef TEST_PENDING_REQUEST 108 if (data->first_try) { 109 data->first_try = 0; 110 wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Testing " 111 "pending request"); 112 ret->ignore = TRUE; 113 eloop_register_timeout(1, 0, eap_vendor_ready, sm, 114 NULL); 115 return NULL; 116 } 117 #endif /* TEST_PENDING_REQUEST */ 118 } 119 120 ret->ignore = FALSE; 121 122 wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Generating Response"); 123 ret->allowNotifications = TRUE; 124 125 resp = eap_msg_alloc(EAP_VENDOR_ID, EAP_VENDOR_TYPE, 1, 126 EAP_CODE_RESPONSE, eap_get_id(reqData)); 127 if (resp == NULL) 128 return NULL; 129 130 if (data->state == INIT) { 131 wpabuf_put_u8(resp, 2); 132 data->state = CONFIRM; 133 ret->methodState = METHOD_CONT; 134 ret->decision = DECISION_FAIL; 135 } else { 136 wpabuf_put_u8(resp, 4); 137 data->state = SUCCESS; 138 ret->methodState = METHOD_DONE; 139 ret->decision = DECISION_UNCOND_SUCC; 140 } 141 142 return resp; 143 } 144 145 146 static Boolean eap_vendor_test_isKeyAvailable(struct eap_sm *sm, void *priv) 147 { 148 struct eap_vendor_test_data *data = priv; 149 return data->state == SUCCESS; 150 } 151 152 153 static u8 * eap_vendor_test_getKey(struct eap_sm *sm, void *priv, size_t *len) 154 { 155 struct eap_vendor_test_data *data = priv; 156 u8 *key; 157 const int key_len = 64; 158 159 if (data->state != SUCCESS) 160 return NULL; 161 162 key = os_malloc(key_len); 163 if (key == NULL) 164 return NULL; 165 166 os_memset(key, 0x11, key_len / 2); 167 os_memset(key + key_len / 2, 0x22, key_len / 2); 168 *len = key_len; 169 170 return key; 171 } 172 173 174 int eap_peer_vendor_test_register(void) 175 { 176 struct eap_method *eap; 177 int ret; 178 179 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 180 EAP_VENDOR_ID, EAP_VENDOR_TYPE, 181 "VENDOR-TEST"); 182 if (eap == NULL) 183 return -1; 184 185 eap->init = eap_vendor_test_init; 186 eap->deinit = eap_vendor_test_deinit; 187 eap->process = eap_vendor_test_process; 188 eap->isKeyAvailable = eap_vendor_test_isKeyAvailable; 189 eap->getKey = eap_vendor_test_getKey; 190 191 ret = eap_peer_method_register(eap); 192 if (ret) 193 eap_peer_method_free(eap); 194 return ret; 195 } 196