Disconnect hostapd from building in base
[dragonfly.git] / contrib / hostapd / src / eap_server / eap_server_tls.c
CommitLineData
ebfa2275
SZ
1/*
2 * hostapd / EAP-TLS (RFC 2716)
a875087d 3 * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
ebfa2275 4 *
4781064b
JM
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
ebfa2275
SZ
7 */
8
9#include "includes.h"
10
ebfa2275
SZ
11#include "common.h"
12#include "eap_i.h"
13#include "eap_tls_common.h"
4781064b 14#include "crypto/tls.h"
ebfa2275
SZ
15
16
17static void eap_tls_reset(struct eap_sm *sm, void *priv);
18
19
20struct eap_tls_data {
21 struct eap_ssl_data ssl;
22 enum { START, CONTINUE, SUCCESS, FAILURE } state;
a875087d 23 int established;
4781064b 24 u8 eap_type;
ebfa2275
SZ
25};
26
27
a875087d
JL
28static const char * eap_tls_state_txt(int state)
29{
30 switch (state) {
31 case START:
32 return "START";
33 case CONTINUE:
34 return "CONTINUE";
35 case SUCCESS:
36 return "SUCCESS";
37 case FAILURE:
38 return "FAILURE";
39 default:
40 return "Unknown?!";
41 }
42}
43
44
45static void eap_tls_state(struct eap_tls_data *data, int state)
46{
47 wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s",
48 eap_tls_state_txt(data->state),
49 eap_tls_state_txt(state));
50 data->state = state;
51}
52
53
ebfa2275
SZ
54static void * eap_tls_init(struct eap_sm *sm)
55{
56 struct eap_tls_data *data;
57
a875087d 58 data = os_zalloc(sizeof(*data));
ebfa2275
SZ
59 if (data == NULL)
60 return NULL;
61 data->state = START;
62
a875087d 63 if (eap_server_tls_ssl_init(sm, &data->ssl, 1)) {
ebfa2275
SZ
64 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
65 eap_tls_reset(sm, data);
66 return NULL;
67 }
68
4781064b
JM
69 data->eap_type = EAP_TYPE_TLS;
70
ebfa2275
SZ
71 return data;
72}
73
74
4781064b
JM
75#ifdef EAP_SERVER_UNAUTH_TLS
76static void * eap_unauth_tls_init(struct eap_sm *sm)
77{
78 struct eap_tls_data *data;
79
80 data = os_zalloc(sizeof(*data));
81 if (data == NULL)
82 return NULL;
83 data->state = START;
84
85 if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
86 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
87 eap_tls_reset(sm, data);
88 return NULL;
89 }
90
91 data->eap_type = EAP_UNAUTH_TLS_TYPE;
92 return data;
93}
94#endif /* EAP_SERVER_UNAUTH_TLS */
95
96
ebfa2275
SZ
97static void eap_tls_reset(struct eap_sm *sm, void *priv)
98{
99 struct eap_tls_data *data = priv;
100 if (data == NULL)
101 return;
a875087d
JL
102 eap_server_tls_ssl_deinit(sm, &data->ssl);
103 os_free(data);
ebfa2275
SZ
104}
105
106
a875087d
JL
107static struct wpabuf * eap_tls_build_start(struct eap_sm *sm,
108 struct eap_tls_data *data, u8 id)
ebfa2275 109{
a875087d 110 struct wpabuf *req;
ebfa2275 111
4781064b 112 req = eap_tls_msg_alloc(data->eap_type, 1, EAP_CODE_REQUEST, id);
ebfa2275
SZ
113 if (req == NULL) {
114 wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for "
115 "request");
a875087d 116 eap_tls_state(data, FAILURE);
ebfa2275
SZ
117 return NULL;
118 }
119
a875087d 120 wpabuf_put_u8(req, EAP_TLS_FLAGS_START);
ebfa2275 121
a875087d 122 eap_tls_state(data, CONTINUE);
ebfa2275 123
a875087d 124 return req;
ebfa2275
SZ
125}
126
127
a875087d 128static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
ebfa2275 129{
a875087d
JL
130 struct eap_tls_data *data = priv;
131 struct wpabuf *res;
ebfa2275 132
a875087d 133 if (data->ssl.state == FRAG_ACK) {
4781064b 134 return eap_server_tls_build_ack(id, data->eap_type, 0);
ebfa2275
SZ
135 }
136
a875087d 137 if (data->ssl.state == WAIT_FRAG_ACK) {
4781064b 138 res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0,
a875087d
JL
139 id);
140 goto check_established;
141 }
ebfa2275
SZ
142
143 switch (data->state) {
144 case START:
a875087d 145 return eap_tls_build_start(sm, data, id);
ebfa2275 146 case CONTINUE:
a875087d
JL
147 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
148 data->established = 1;
149 break;
ebfa2275
SZ
150 default:
151 wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d",
152 __func__, data->state);
153 return NULL;
154 }
a875087d 155
4781064b 156 res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0, id);
a875087d
JL
157
158check_established:
159 if (data->established && data->ssl.state != WAIT_FRAG_ACK) {
160 /* TLS handshake has been completed and there are no more
161 * fragments waiting to be sent out. */
162 wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
163 eap_tls_state(data, SUCCESS);
164 }
165
166 return res;
ebfa2275
SZ
167}
168
169
170static Boolean eap_tls_check(struct eap_sm *sm, void *priv,
a875087d 171 struct wpabuf *respData)
ebfa2275 172{
4781064b 173 struct eap_tls_data *data = priv;
a875087d
JL
174 const u8 *pos;
175 size_t len;
ebfa2275 176
4781064b
JM
177 if (data->eap_type == EAP_UNAUTH_TLS_TYPE)
178 pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
179 EAP_VENDOR_TYPE_UNAUTH_TLS, respData,
180 &len);
181 else
182 pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_type,
183 respData, &len);
a875087d 184 if (pos == NULL || len < 1) {
ebfa2275
SZ
185 wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
186 return TRUE;
187 }
188
189 return FALSE;
190}
191
192
a875087d
JL
193static void eap_tls_process_msg(struct eap_sm *sm, void *priv,
194 const struct wpabuf *respData)
ebfa2275
SZ
195{
196 struct eap_tls_data *data = priv;
4781064b 197 if (data->state == SUCCESS && wpabuf_len(data->ssl.tls_in) == 0) {
a875087d
JL
198 wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS "
199 "handshake message");
ebfa2275
SZ
200 return;
201 }
a875087d
JL
202 if (eap_server_tls_phase1(sm, &data->ssl) < 0)
203 eap_tls_state(data, FAILURE);
204}
ebfa2275 205
a875087d
JL
206
207static void eap_tls_process(struct eap_sm *sm, void *priv,
208 struct wpabuf *respData)
209{
210 struct eap_tls_data *data = priv;
211 if (eap_server_tls_process(sm, &data->ssl, respData, data,
4781064b 212 data->eap_type, NULL, eap_tls_process_msg) <
a875087d
JL
213 0)
214 eap_tls_state(data, FAILURE);
ebfa2275
SZ
215}
216
217
218static Boolean eap_tls_isDone(struct eap_sm *sm, void *priv)
219{
220 struct eap_tls_data *data = priv;
221 return data->state == SUCCESS || data->state == FAILURE;
222}
223
224
225static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
226{
227 struct eap_tls_data *data = priv;
228 u8 *eapKeyData;
229
230 if (data->state != SUCCESS)
231 return NULL;
232
a875087d
JL
233 eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
234 "client EAP encryption",
235 EAP_TLS_KEY_LEN);
ebfa2275
SZ
236 if (eapKeyData) {
237 *len = EAP_TLS_KEY_LEN;
238 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key",
239 eapKeyData, EAP_TLS_KEY_LEN);
240 } else {
241 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key");
242 }
243
244 return eapKeyData;
245}
246
247
248static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
249{
250 struct eap_tls_data *data = priv;
251 u8 *eapKeyData, *emsk;
252
253 if (data->state != SUCCESS)
254 return NULL;
255
a875087d
JL
256 eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
257 "client EAP encryption",
258 EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
ebfa2275 259 if (eapKeyData) {
a875087d 260 emsk = os_malloc(EAP_EMSK_LEN);
ebfa2275 261 if (emsk)
a875087d
JL
262 os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
263 EAP_EMSK_LEN);
264 os_free(eapKeyData);
ebfa2275
SZ
265 } else
266 emsk = NULL;
267
268 if (emsk) {
269 *len = EAP_EMSK_LEN;
270 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK",
271 emsk, EAP_EMSK_LEN);
272 } else {
273 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK");
274 }
275
276 return emsk;
277}
278
279
280static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv)
281{
282 struct eap_tls_data *data = priv;
283 return data->state == SUCCESS;
284}
285
286
287int eap_server_tls_register(void)
288{
289 struct eap_method *eap;
290 int ret;
291
292 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
293 EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
294 if (eap == NULL)
295 return -1;
296
297 eap->init = eap_tls_init;
298 eap->reset = eap_tls_reset;
299 eap->buildReq = eap_tls_buildReq;
300 eap->check = eap_tls_check;
301 eap->process = eap_tls_process;
302 eap->isDone = eap_tls_isDone;
303 eap->getKey = eap_tls_getKey;
304 eap->isSuccess = eap_tls_isSuccess;
305 eap->get_emsk = eap_tls_get_emsk;
306
307 ret = eap_server_method_register(eap);
308 if (ret)
309 eap_server_method_free(eap);
310 return ret;
311}
4781064b
JM
312
313
314#ifdef EAP_SERVER_UNAUTH_TLS
315int eap_server_unauth_tls_register(void)
316{
317 struct eap_method *eap;
318 int ret;
319
320 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
321 EAP_VENDOR_UNAUTH_TLS,
322 EAP_VENDOR_TYPE_UNAUTH_TLS,
323 "UNAUTH-TLS");
324 if (eap == NULL)
325 return -1;
326
327 eap->init = eap_unauth_tls_init;
328 eap->reset = eap_tls_reset;
329 eap->buildReq = eap_tls_buildReq;
330 eap->check = eap_tls_check;
331 eap->process = eap_tls_process;
332 eap->isDone = eap_tls_isDone;
333 eap->getKey = eap_tls_getKey;
334 eap->isSuccess = eap_tls_isSuccess;
335 eap->get_emsk = eap_tls_get_emsk;
336
337 ret = eap_server_method_register(eap);
338 if (ret)
339 eap_server_method_free(eap);
340 return ret;
341}
342#endif /* EAP_SERVER_UNAUTH_TLS */