]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wpa/src/eap_server/eap_server_tls.c
Update hostapd/wpa_supplicant to 2.8 to fix multiple vulnerabilities.
[FreeBSD/FreeBSD.git] / contrib / wpa / src / eap_server / eap_server_tls.c
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         int phase2;
26 };
27
28
29 static const char * eap_tls_state_txt(int state)
30 {
31         switch (state) {
32         case START:
33                 return "START";
34         case CONTINUE:
35                 return "CONTINUE";
36         case SUCCESS:
37                 return "SUCCESS";
38         case FAILURE:
39                 return "FAILURE";
40         default:
41                 return "Unknown?!";
42         }
43 }
44
45
46 static void eap_tls_state(struct eap_tls_data *data, int state)
47 {
48         wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s",
49                    eap_tls_state_txt(data->state),
50                    eap_tls_state_txt(state));
51         data->state = state;
52         if (state == FAILURE)
53                 tls_connection_remove_session(data->ssl.conn);
54 }
55
56
57 static void eap_tls_valid_session(struct eap_sm *sm, struct eap_tls_data *data)
58 {
59         struct wpabuf *buf;
60
61         if (!sm->tls_session_lifetime)
62                 return;
63
64         buf = wpabuf_alloc(1);
65         if (!buf)
66                 return;
67         wpabuf_put_u8(buf, data->eap_type);
68         tls_connection_set_success_data(data->ssl.conn, buf);
69 }
70
71
72 static void * eap_tls_init(struct eap_sm *sm)
73 {
74         struct eap_tls_data *data;
75
76         data = os_zalloc(sizeof(*data));
77         if (data == NULL)
78                 return NULL;
79         data->state = START;
80
81         if (eap_server_tls_ssl_init(sm, &data->ssl, 1, EAP_TYPE_TLS)) {
82                 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
83                 eap_tls_reset(sm, data);
84                 return NULL;
85         }
86
87         data->eap_type = EAP_TYPE_TLS;
88
89         data->phase2 = sm->init_phase2;
90
91         return data;
92 }
93
94
95 #ifdef EAP_SERVER_UNAUTH_TLS
96 static void * eap_unauth_tls_init(struct eap_sm *sm)
97 {
98         struct eap_tls_data *data;
99
100         data = os_zalloc(sizeof(*data));
101         if (data == NULL)
102                 return NULL;
103         data->state = START;
104
105         if (eap_server_tls_ssl_init(sm, &data->ssl, 0, EAP_UNAUTH_TLS_TYPE)) {
106                 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
107                 eap_tls_reset(sm, data);
108                 return NULL;
109         }
110
111         data->eap_type = EAP_UNAUTH_TLS_TYPE;
112         return data;
113 }
114 #endif /* EAP_SERVER_UNAUTH_TLS */
115
116
117 #ifdef CONFIG_HS20
118 static void * eap_wfa_unauth_tls_init(struct eap_sm *sm)
119 {
120         struct eap_tls_data *data;
121
122         data = os_zalloc(sizeof(*data));
123         if (data == NULL)
124                 return NULL;
125         data->state = START;
126
127         if (eap_server_tls_ssl_init(sm, &data->ssl, 0,
128                                     EAP_WFA_UNAUTH_TLS_TYPE)) {
129                 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
130                 eap_tls_reset(sm, data);
131                 return NULL;
132         }
133
134         data->eap_type = EAP_WFA_UNAUTH_TLS_TYPE;
135         return data;
136 }
137 #endif /* CONFIG_HS20 */
138
139
140 static void eap_tls_reset(struct eap_sm *sm, void *priv)
141 {
142         struct eap_tls_data *data = priv;
143         if (data == NULL)
144                 return;
145         eap_server_tls_ssl_deinit(sm, &data->ssl);
146         os_free(data);
147 }
148
149
150 static struct wpabuf * eap_tls_build_start(struct eap_sm *sm,
151                                            struct eap_tls_data *data, u8 id)
152 {
153         struct wpabuf *req;
154
155         req = eap_tls_msg_alloc(data->eap_type, 1, EAP_CODE_REQUEST, id);
156         if (req == NULL) {
157                 wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for "
158                            "request");
159                 eap_tls_state(data, FAILURE);
160                 return NULL;
161         }
162
163         wpabuf_put_u8(req, EAP_TLS_FLAGS_START);
164
165         eap_tls_state(data, CONTINUE);
166
167         return req;
168 }
169
170
171 static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
172 {
173         struct eap_tls_data *data = priv;
174         struct wpabuf *res;
175
176         if (data->ssl.state == FRAG_ACK) {
177                 return eap_server_tls_build_ack(id, data->eap_type, 0);
178         }
179
180         if (data->ssl.state == WAIT_FRAG_ACK) {
181                 res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0,
182                                                id);
183                 goto check_established;
184         }
185
186         switch (data->state) {
187         case START:
188                 return eap_tls_build_start(sm, data, id);
189         case CONTINUE:
190                 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
191                         data->established = 1;
192                 break;
193         default:
194                 wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d",
195                            __func__, data->state);
196                 return NULL;
197         }
198
199         res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0, id);
200
201 check_established:
202         if (data->established && data->ssl.state != WAIT_FRAG_ACK) {
203                 /* TLS handshake has been completed and there are no more
204                  * fragments waiting to be sent out. */
205                 wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
206                 eap_tls_state(data, SUCCESS);
207                 eap_tls_valid_session(sm, data);
208                 if (sm->serial_num) {
209                         char user[128];
210                         int user_len;
211
212                         user_len = os_snprintf(user, sizeof(user), "cert-%s",
213                                                sm->serial_num);
214                         if (eap_user_get(sm, (const u8 *) user, user_len,
215                                          data->phase2) < 0)
216                                 wpa_printf(MSG_DEBUG,
217                                            "EAP-TLS: No user entry found based on the serial number of the client certificate ");
218                         else
219                                 wpa_printf(MSG_DEBUG,
220                                            "EAP-TLS: Updated user entry based on the serial number of the client certificate ");
221                 }
222         }
223
224         return res;
225 }
226
227
228 static Boolean eap_tls_check(struct eap_sm *sm, void *priv,
229                              struct wpabuf *respData)
230 {
231         struct eap_tls_data *data = priv;
232         const u8 *pos;
233         size_t len;
234
235         if (data->eap_type == EAP_UNAUTH_TLS_TYPE)
236                 pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
237                                        EAP_VENDOR_TYPE_UNAUTH_TLS, respData,
238                                        &len);
239         else if (data->eap_type == EAP_WFA_UNAUTH_TLS_TYPE)
240                 pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW,
241                                        EAP_VENDOR_WFA_UNAUTH_TLS, respData,
242                                        &len);
243         else
244                 pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_type,
245                                        respData, &len);
246         if (pos == NULL || len < 1) {
247                 wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
248                 return TRUE;
249         }
250
251         return FALSE;
252 }
253
254
255 static void eap_tls_process_msg(struct eap_sm *sm, void *priv,
256                                 const struct wpabuf *respData)
257 {
258         struct eap_tls_data *data = priv;
259         if (data->state == SUCCESS && wpabuf_len(data->ssl.tls_in) == 0) {
260                 wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS "
261                            "handshake message");
262                 return;
263         }
264         if (eap_server_tls_phase1(sm, &data->ssl) < 0)
265                 eap_tls_state(data, FAILURE);
266 }
267
268
269 static void eap_tls_process(struct eap_sm *sm, void *priv,
270                             struct wpabuf *respData)
271 {
272         struct eap_tls_data *data = priv;
273         const struct wpabuf *buf;
274         const u8 *pos;
275
276         if (eap_server_tls_process(sm, &data->ssl, respData, data,
277                                    data->eap_type, NULL, eap_tls_process_msg) <
278             0) {
279                 eap_tls_state(data, FAILURE);
280                 return;
281         }
282
283         if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
284             !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
285                 return;
286
287         buf = tls_connection_get_success_data(data->ssl.conn);
288         if (!buf || wpabuf_len(buf) < 1) {
289                 wpa_printf(MSG_DEBUG,
290                            "EAP-TLS: No success data in resumed session - reject attempt");
291                 eap_tls_state(data, FAILURE);
292                 return;
293         }
294
295         pos = wpabuf_head(buf);
296         if (*pos != data->eap_type) {
297                 wpa_printf(MSG_DEBUG,
298                            "EAP-TLS: Resumed session for another EAP type (%u) - reject attempt",
299                            *pos);
300                 eap_tls_state(data, FAILURE);
301                 return;
302         }
303
304         wpa_printf(MSG_DEBUG,
305                    "EAP-TLS: Resuming previous session");
306         eap_tls_state(data, SUCCESS);
307         tls_connection_set_success_data_resumed(data->ssl.conn);
308         /* TODO: Cache serial number with session and update EAP user
309          * information based on the cached serial number */
310 }
311
312
313 static Boolean eap_tls_isDone(struct eap_sm *sm, void *priv)
314 {
315         struct eap_tls_data *data = priv;
316         return data->state == SUCCESS || data->state == FAILURE;
317 }
318
319
320 static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
321 {
322         struct eap_tls_data *data = priv;
323         u8 *eapKeyData;
324         const char *label;
325
326         if (data->state != SUCCESS)
327                 return NULL;
328
329         if (data->ssl.tls_v13)
330                 label = "EXPORTER_EAP_TLS_Key_Material";
331         else
332                 label = "client EAP encryption";
333         eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, label,
334                                                NULL, 0,
335                                                EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
336         if (eapKeyData) {
337                 *len = EAP_TLS_KEY_LEN;
338                 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key",
339                             eapKeyData, EAP_TLS_KEY_LEN);
340                 os_memset(eapKeyData + EAP_TLS_KEY_LEN, 0, EAP_EMSK_LEN);
341         } else {
342                 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key");
343         }
344
345         return eapKeyData;
346 }
347
348
349 static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
350 {
351         struct eap_tls_data *data = priv;
352         u8 *eapKeyData, *emsk;
353         const char *label;
354
355         if (data->state != SUCCESS)
356                 return NULL;
357
358         if (data->ssl.tls_v13)
359                 label = "EXPORTER_EAP_TLS_Key_Material";
360         else
361                 label = "client EAP encryption";
362         eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, label,
363                                                NULL, 0,
364                                                EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
365         if (eapKeyData) {
366                 emsk = os_malloc(EAP_EMSK_LEN);
367                 if (emsk)
368                         os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
369                                   EAP_EMSK_LEN);
370                 bin_clear_free(eapKeyData, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
371         } else
372                 emsk = NULL;
373
374         if (emsk) {
375                 *len = EAP_EMSK_LEN;
376                 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK",
377                             emsk, EAP_EMSK_LEN);
378         } else {
379                 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK");
380         }
381
382         return emsk;
383 }
384
385
386 static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv)
387 {
388         struct eap_tls_data *data = priv;
389         return data->state == SUCCESS;
390 }
391
392
393 static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
394 {
395         struct eap_tls_data *data = priv;
396
397         if (data->state != SUCCESS)
398                 return NULL;
399
400         return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_TLS,
401                                                 len);
402 }
403
404
405 int eap_server_tls_register(void)
406 {
407         struct eap_method *eap;
408
409         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
410                                       EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
411         if (eap == NULL)
412                 return -1;
413
414         eap->init = eap_tls_init;
415         eap->reset = eap_tls_reset;
416         eap->buildReq = eap_tls_buildReq;
417         eap->check = eap_tls_check;
418         eap->process = eap_tls_process;
419         eap->isDone = eap_tls_isDone;
420         eap->getKey = eap_tls_getKey;
421         eap->isSuccess = eap_tls_isSuccess;
422         eap->get_emsk = eap_tls_get_emsk;
423         eap->getSessionId = eap_tls_get_session_id;
424
425         return eap_server_method_register(eap);
426 }
427
428
429 #ifdef EAP_SERVER_UNAUTH_TLS
430 int eap_server_unauth_tls_register(void)
431 {
432         struct eap_method *eap;
433
434         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
435                                       EAP_VENDOR_UNAUTH_TLS,
436                                       EAP_VENDOR_TYPE_UNAUTH_TLS,
437                                       "UNAUTH-TLS");
438         if (eap == NULL)
439                 return -1;
440
441         eap->init = eap_unauth_tls_init;
442         eap->reset = eap_tls_reset;
443         eap->buildReq = eap_tls_buildReq;
444         eap->check = eap_tls_check;
445         eap->process = eap_tls_process;
446         eap->isDone = eap_tls_isDone;
447         eap->getKey = eap_tls_getKey;
448         eap->isSuccess = eap_tls_isSuccess;
449         eap->get_emsk = eap_tls_get_emsk;
450
451         return eap_server_method_register(eap);
452 }
453 #endif /* EAP_SERVER_UNAUTH_TLS */
454
455
456 #ifdef CONFIG_HS20
457 int eap_server_wfa_unauth_tls_register(void)
458 {
459         struct eap_method *eap;
460
461         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
462                                       EAP_VENDOR_WFA_NEW,
463                                       EAP_VENDOR_WFA_UNAUTH_TLS,
464                                       "WFA-UNAUTH-TLS");
465         if (eap == NULL)
466                 return -1;
467
468         eap->init = eap_wfa_unauth_tls_init;
469         eap->reset = eap_tls_reset;
470         eap->buildReq = eap_tls_buildReq;
471         eap->check = eap_tls_check;
472         eap->process = eap_tls_process;
473         eap->isDone = eap_tls_isDone;
474         eap->getKey = eap_tls_getKey;
475         eap->isSuccess = eap_tls_isSuccess;
476         eap->get_emsk = eap_tls_get_emsk;
477
478         return eap_server_method_register(eap);
479 }
480 #endif /* CONFIG_HS20 */