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