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