source: rtems-libbsd/freebsd/contrib/wpa/src/eap_peer/eap_tls.c @ 9c9d11b

55-freebsd-126-freebsd-12
Last change on this file since 9c9d11b was 9c9d11b, checked in by Sichen Zhao <1473996754@…>, on 08/01/17 at 12:43:41

Import wpa from FreeBSD

  • Property mode set to 100644
File size: 9.9 KB
Line 
1#include <machine/rtems-bsd-user-space.h>
2
3/*
4 * EAP peer method: EAP-TLS (RFC 2716)
5 * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
6 *
7 * This software may be distributed under the terms of the BSD license.
8 * See README for more details.
9 */
10
11#include "includes.h"
12
13#include "common.h"
14#include "crypto/tls.h"
15#include "eap_i.h"
16#include "eap_tls_common.h"
17#include "eap_config.h"
18
19
20static void eap_tls_deinit(struct eap_sm *sm, void *priv);
21
22
23struct eap_tls_data {
24        struct eap_ssl_data ssl;
25        u8 *key_data;
26        u8 *session_id;
27        size_t id_len;
28        void *ssl_ctx;
29        u8 eap_type;
30};
31
32
33static void * eap_tls_init(struct eap_sm *sm)
34{
35        struct eap_tls_data *data;
36        struct eap_peer_config *config = eap_get_config(sm);
37        if (config == NULL ||
38            ((sm->init_phase2 ? config->private_key2 : config->private_key)
39             == NULL &&
40             (sm->init_phase2 ? config->engine2 : config->engine) == 0)) {
41                wpa_printf(MSG_INFO, "EAP-TLS: Private key not configured");
42                return NULL;
43        }
44
45        data = os_zalloc(sizeof(*data));
46        if (data == NULL)
47                return NULL;
48
49        data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
50                sm->ssl_ctx;
51
52        if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TLS)) {
53                wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
54                eap_tls_deinit(sm, data);
55                if (config->engine) {
56                        wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting Smartcard "
57                                   "PIN");
58                        eap_sm_request_pin(sm);
59                        sm->ignore = TRUE;
60                } else if (config->private_key && !config->private_key_passwd)
61                {
62                        wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting private "
63                                   "key passphrase");
64                        eap_sm_request_passphrase(sm);
65                        sm->ignore = TRUE;
66                }
67                return NULL;
68        }
69
70        data->eap_type = EAP_TYPE_TLS;
71
72        return data;
73}
74
75
76#ifdef EAP_UNAUTH_TLS
77static void * eap_unauth_tls_init(struct eap_sm *sm)
78{
79        struct eap_tls_data *data;
80        struct eap_peer_config *config = eap_get_config(sm);
81
82        data = os_zalloc(sizeof(*data));
83        if (data == NULL)
84                return NULL;
85
86        data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
87                sm->ssl_ctx;
88
89        if (eap_peer_tls_ssl_init(sm, &data->ssl, config,
90                                  EAP_UNAUTH_TLS_TYPE)) {
91                wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
92                eap_tls_deinit(sm, data);
93                return NULL;
94        }
95
96        data->eap_type = EAP_UNAUTH_TLS_TYPE;
97
98        return data;
99}
100#endif /* EAP_UNAUTH_TLS */
101
102
103#ifdef CONFIG_HS20
104static void * eap_wfa_unauth_tls_init(struct eap_sm *sm)
105{
106        struct eap_tls_data *data;
107        struct eap_peer_config *config = eap_get_config(sm);
108
109        data = os_zalloc(sizeof(*data));
110        if (data == NULL)
111                return NULL;
112
113        data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
114                sm->ssl_ctx;
115
116        if (eap_peer_tls_ssl_init(sm, &data->ssl, config,
117                                  EAP_WFA_UNAUTH_TLS_TYPE)) {
118                wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
119                eap_tls_deinit(sm, data);
120                return NULL;
121        }
122
123        data->eap_type = EAP_WFA_UNAUTH_TLS_TYPE;
124
125        return data;
126}
127#endif /* CONFIG_HS20 */
128
129
130static void eap_tls_free_key(struct eap_tls_data *data)
131{
132        if (data->key_data) {
133                bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
134                data->key_data = NULL;
135        }
136}
137
138
139static void eap_tls_deinit(struct eap_sm *sm, void *priv)
140{
141        struct eap_tls_data *data = priv;
142        if (data == NULL)
143                return;
144        eap_peer_tls_ssl_deinit(sm, &data->ssl);
145        eap_tls_free_key(data);
146        os_free(data->session_id);
147        os_free(data);
148}
149
150
151static struct wpabuf * eap_tls_failure(struct eap_sm *sm,
152                                       struct eap_tls_data *data,
153                                       struct eap_method_ret *ret, int res,
154                                       struct wpabuf *resp, u8 id)
155{
156        wpa_printf(MSG_DEBUG, "EAP-TLS: TLS processing failed");
157
158        ret->methodState = METHOD_DONE;
159        ret->decision = DECISION_FAIL;
160
161        if (resp) {
162                /*
163                 * This is likely an alert message, so send it instead of just
164                 * ACKing the error.
165                 */
166                return resp;
167        }
168
169        return eap_peer_tls_build_ack(id, data->eap_type, 0);
170}
171
172
173static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data,
174                            struct eap_method_ret *ret)
175{
176        wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
177
178        ret->methodState = METHOD_DONE;
179        ret->decision = DECISION_UNCOND_SUCC;
180
181        eap_tls_free_key(data);
182        data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
183                                                 "client EAP encryption",
184                                                 EAP_TLS_KEY_LEN +
185                                                 EAP_EMSK_LEN);
186        if (data->key_data) {
187                wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived key",
188                                data->key_data, EAP_TLS_KEY_LEN);
189                wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived EMSK",
190                                data->key_data + EAP_TLS_KEY_LEN,
191                                EAP_EMSK_LEN);
192        } else {
193                wpa_printf(MSG_INFO, "EAP-TLS: Failed to derive key");
194        }
195
196        os_free(data->session_id);
197        data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl,
198                                                          EAP_TYPE_TLS,
199                                                          &data->id_len);
200        if (data->session_id) {
201                wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived Session-Id",
202                            data->session_id, data->id_len);
203        } else {
204                wpa_printf(MSG_ERROR, "EAP-TLS: Failed to derive Session-Id");
205        }
206}
207
208
209static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
210                                       struct eap_method_ret *ret,
211                                       const struct wpabuf *reqData)
212{
213        size_t left;
214        int res;
215        struct wpabuf *resp;
216        u8 flags, id;
217        const u8 *pos;
218        struct eap_tls_data *data = priv;
219        struct wpabuf msg;
220
221        pos = eap_peer_tls_process_init(sm, &data->ssl, data->eap_type, ret,
222                                        reqData, &left, &flags);
223        if (pos == NULL)
224                return NULL;
225        id = eap_get_id(reqData);
226
227        if (flags & EAP_TLS_FLAGS_START) {
228                wpa_printf(MSG_DEBUG, "EAP-TLS: Start");
229                left = 0; /* make sure that this frame is empty, even though it
230                           * should always be, anyway */
231        }
232
233        resp = NULL;
234        wpabuf_set(&msg, pos, left);
235        res = eap_peer_tls_process_helper(sm, &data->ssl, data->eap_type, 0,
236                                          id, &msg, &resp);
237
238        if (res < 0) {
239                return eap_tls_failure(sm, data, ret, res, resp, id);
240        }
241
242        if (tls_connection_established(data->ssl_ctx, data->ssl.conn))
243                eap_tls_success(sm, data, ret);
244
245        if (res == 1) {
246                wpabuf_free(resp);
247                return eap_peer_tls_build_ack(id, data->eap_type, 0);
248        }
249
250        return resp;
251}
252
253
254static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv)
255{
256        struct eap_tls_data *data = priv;
257        return tls_connection_established(data->ssl_ctx, data->ssl.conn);
258}
259
260
261static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv)
262{
263}
264
265
266static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv)
267{
268        struct eap_tls_data *data = priv;
269        eap_tls_free_key(data);
270        os_free(data->session_id);
271        data->session_id = NULL;
272        if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
273                os_free(data);
274                return NULL;
275        }
276        return priv;
277}
278
279
280static int eap_tls_get_status(struct eap_sm *sm, void *priv, char *buf,
281                              size_t buflen, int verbose)
282{
283        struct eap_tls_data *data = priv;
284        return eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
285}
286
287
288static Boolean eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv)
289{
290        struct eap_tls_data *data = priv;
291        return data->key_data != NULL;
292}
293
294
295static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
296{
297        struct eap_tls_data *data = priv;
298        u8 *key;
299
300        if (data->key_data == NULL)
301                return NULL;
302
303        key = os_malloc(EAP_TLS_KEY_LEN);
304        if (key == NULL)
305                return NULL;
306
307        *len = EAP_TLS_KEY_LEN;
308        os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
309
310        return key;
311}
312
313
314static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
315{
316        struct eap_tls_data *data = priv;
317        u8 *key;
318
319        if (data->key_data == NULL)
320                return NULL;
321
322        key = os_malloc(EAP_EMSK_LEN);
323        if (key == NULL)
324                return NULL;
325
326        *len = EAP_EMSK_LEN;
327        os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
328
329        return key;
330}
331
332
333static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
334{
335        struct eap_tls_data *data = priv;
336        u8 *id;
337
338        if (data->session_id == NULL)
339                return NULL;
340
341        id = os_malloc(data->id_len);
342        if (id == NULL)
343                return NULL;
344
345        *len = data->id_len;
346        os_memcpy(id, data->session_id, data->id_len);
347
348        return id;
349}
350
351
352int eap_peer_tls_register(void)
353{
354        struct eap_method *eap;
355        int ret;
356
357        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
358                                    EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
359        if (eap == NULL)
360                return -1;
361
362        eap->init = eap_tls_init;
363        eap->deinit = eap_tls_deinit;
364        eap->process = eap_tls_process;
365        eap->isKeyAvailable = eap_tls_isKeyAvailable;
366        eap->getKey = eap_tls_getKey;
367        eap->getSessionId = eap_tls_get_session_id;
368        eap->get_status = eap_tls_get_status;
369        eap->has_reauth_data = eap_tls_has_reauth_data;
370        eap->deinit_for_reauth = eap_tls_deinit_for_reauth;
371        eap->init_for_reauth = eap_tls_init_for_reauth;
372        eap->get_emsk = eap_tls_get_emsk;
373
374        ret = eap_peer_method_register(eap);
375        if (ret)
376                eap_peer_method_free(eap);
377        return ret;
378}
379
380
381#ifdef EAP_UNAUTH_TLS
382int eap_peer_unauth_tls_register(void)
383{
384        struct eap_method *eap;
385        int ret;
386
387        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
388                                    EAP_VENDOR_UNAUTH_TLS,
389                                    EAP_VENDOR_TYPE_UNAUTH_TLS, "UNAUTH-TLS");
390        if (eap == NULL)
391                return -1;
392
393        eap->init = eap_unauth_tls_init;
394        eap->deinit = eap_tls_deinit;
395        eap->process = eap_tls_process;
396        eap->isKeyAvailable = eap_tls_isKeyAvailable;
397        eap->getKey = eap_tls_getKey;
398        eap->get_status = eap_tls_get_status;
399        eap->has_reauth_data = eap_tls_has_reauth_data;
400        eap->deinit_for_reauth = eap_tls_deinit_for_reauth;
401        eap->init_for_reauth = eap_tls_init_for_reauth;
402        eap->get_emsk = eap_tls_get_emsk;
403
404        ret = eap_peer_method_register(eap);
405        if (ret)
406                eap_peer_method_free(eap);
407        return ret;
408}
409#endif /* EAP_UNAUTH_TLS */
410
411
412#ifdef CONFIG_HS20
413int eap_peer_wfa_unauth_tls_register(void)
414{
415        struct eap_method *eap;
416        int ret;
417
418        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
419                                    EAP_VENDOR_WFA_NEW,
420                                    EAP_VENDOR_WFA_UNAUTH_TLS,
421                                    "WFA-UNAUTH-TLS");
422        if (eap == NULL)
423                return -1;
424
425        eap->init = eap_wfa_unauth_tls_init;
426        eap->deinit = eap_tls_deinit;
427        eap->process = eap_tls_process;
428        eap->isKeyAvailable = eap_tls_isKeyAvailable;
429        eap->getKey = eap_tls_getKey;
430        eap->get_status = eap_tls_get_status;
431        eap->has_reauth_data = eap_tls_has_reauth_data;
432        eap->deinit_for_reauth = eap_tls_deinit_for_reauth;
433        eap->init_for_reauth = eap_tls_init_for_reauth;
434        eap->get_emsk = eap_tls_get_emsk;
435
436        ret = eap_peer_method_register(eap);
437        if (ret)
438                eap_peer_method_free(eap);
439        return ret;
440}
441#endif /* CONFIG_HS20 */
Note: See TracBrowser for help on using the repository browser.