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