hostapd: Update vendor branch to 0.6.10
[dragonfly.git] / contrib / hostapd / src / eap_server / eap_tls.c
blob5747940f7806d0ee10100720db0569cbd8f2ea4f
1 /*
2 * hostapd / EAP-TLS (RFC 2716)
3 * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
12 * See README and COPYING for more details.
15 #include "includes.h"
17 #include "common.h"
18 #include "eap_i.h"
19 #include "eap_tls_common.h"
20 #include "tls.h"
23 static void eap_tls_reset(struct eap_sm *sm, void *priv);
26 struct eap_tls_data {
27 struct eap_ssl_data ssl;
28 enum { START, CONTINUE, SUCCESS, FAILURE } state;
29 int established;
33 static const char * eap_tls_state_txt(int state)
35 switch (state) {
36 case START:
37 return "START";
38 case CONTINUE:
39 return "CONTINUE";
40 case SUCCESS:
41 return "SUCCESS";
42 case FAILURE:
43 return "FAILURE";
44 default:
45 return "Unknown?!";
50 static void eap_tls_state(struct eap_tls_data *data, int state)
52 wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s",
53 eap_tls_state_txt(data->state),
54 eap_tls_state_txt(state));
55 data->state = state;
59 static void * eap_tls_init(struct eap_sm *sm)
61 struct eap_tls_data *data;
63 data = os_zalloc(sizeof(*data));
64 if (data == NULL)
65 return NULL;
66 data->state = START;
68 if (eap_server_tls_ssl_init(sm, &data->ssl, 1)) {
69 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
70 eap_tls_reset(sm, data);
71 return NULL;
74 return data;
78 static void eap_tls_reset(struct eap_sm *sm, void *priv)
80 struct eap_tls_data *data = priv;
81 if (data == NULL)
82 return;
83 eap_server_tls_ssl_deinit(sm, &data->ssl);
84 os_free(data);
88 static struct wpabuf * eap_tls_build_start(struct eap_sm *sm,
89 struct eap_tls_data *data, u8 id)
91 struct wpabuf *req;
93 req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLS, 1, EAP_CODE_REQUEST,
94 id);
95 if (req == NULL) {
96 wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for "
97 "request");
98 eap_tls_state(data, FAILURE);
99 return NULL;
102 wpabuf_put_u8(req, EAP_TLS_FLAGS_START);
104 eap_tls_state(data, CONTINUE);
106 return req;
110 static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
112 struct eap_tls_data *data = priv;
113 struct wpabuf *res;
115 if (data->ssl.state == FRAG_ACK) {
116 return eap_server_tls_build_ack(id, EAP_TYPE_TLS, 0);
119 if (data->ssl.state == WAIT_FRAG_ACK) {
120 res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0,
121 id);
122 goto check_established;
125 switch (data->state) {
126 case START:
127 return eap_tls_build_start(sm, data, id);
128 case CONTINUE:
129 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
130 data->established = 1;
131 break;
132 default:
133 wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d",
134 __func__, data->state);
135 return NULL;
138 res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, id);
140 check_established:
141 if (data->established && data->ssl.state != WAIT_FRAG_ACK) {
142 /* TLS handshake has been completed and there are no more
143 * fragments waiting to be sent out. */
144 wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
145 eap_tls_state(data, SUCCESS);
148 return res;
152 static Boolean eap_tls_check(struct eap_sm *sm, void *priv,
153 struct wpabuf *respData)
155 const u8 *pos;
156 size_t len;
158 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLS, respData, &len);
159 if (pos == NULL || len < 1) {
160 wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
161 return TRUE;
164 return FALSE;
168 static void eap_tls_process_msg(struct eap_sm *sm, void *priv,
169 const struct wpabuf *respData)
171 struct eap_tls_data *data = priv;
172 if (data->state == SUCCESS && wpabuf_len(data->ssl.in_buf) == 0) {
173 wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS "
174 "handshake message");
175 return;
177 if (eap_server_tls_phase1(sm, &data->ssl) < 0)
178 eap_tls_state(data, FAILURE);
182 static void eap_tls_process(struct eap_sm *sm, void *priv,
183 struct wpabuf *respData)
185 struct eap_tls_data *data = priv;
186 if (eap_server_tls_process(sm, &data->ssl, respData, data,
187 EAP_TYPE_TLS, NULL, eap_tls_process_msg) <
189 eap_tls_state(data, FAILURE);
193 static Boolean eap_tls_isDone(struct eap_sm *sm, void *priv)
195 struct eap_tls_data *data = priv;
196 return data->state == SUCCESS || data->state == FAILURE;
200 static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
202 struct eap_tls_data *data = priv;
203 u8 *eapKeyData;
205 if (data->state != SUCCESS)
206 return NULL;
208 eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
209 "client EAP encryption",
210 EAP_TLS_KEY_LEN);
211 if (eapKeyData) {
212 *len = EAP_TLS_KEY_LEN;
213 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key",
214 eapKeyData, EAP_TLS_KEY_LEN);
215 } else {
216 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key");
219 return eapKeyData;
223 static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
225 struct eap_tls_data *data = priv;
226 u8 *eapKeyData, *emsk;
228 if (data->state != SUCCESS)
229 return NULL;
231 eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
232 "client EAP encryption",
233 EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
234 if (eapKeyData) {
235 emsk = os_malloc(EAP_EMSK_LEN);
236 if (emsk)
237 os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
238 EAP_EMSK_LEN);
239 os_free(eapKeyData);
240 } else
241 emsk = NULL;
243 if (emsk) {
244 *len = EAP_EMSK_LEN;
245 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK",
246 emsk, EAP_EMSK_LEN);
247 } else {
248 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK");
251 return emsk;
255 static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv)
257 struct eap_tls_data *data = priv;
258 return data->state == SUCCESS;
262 int eap_server_tls_register(void)
264 struct eap_method *eap;
265 int ret;
267 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
268 EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
269 if (eap == NULL)
270 return -1;
272 eap->init = eap_tls_init;
273 eap->reset = eap_tls_reset;
274 eap->buildReq = eap_tls_buildReq;
275 eap->check = eap_tls_check;
276 eap->process = eap_tls_process;
277 eap->isDone = eap_tls_isDone;
278 eap->getKey = eap_tls_getKey;
279 eap->isSuccess = eap_tls_isSuccess;
280 eap->get_emsk = eap_tls_get_emsk;
282 ret = eap_server_method_register(eap);
283 if (ret)
284 eap_server_method_free(eap);
285 return ret;