]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - 6/contrib/wpa_supplicant/eap_tls.c
merge fix for boot-time hang on centos' xen
[FreeBSD/FreeBSD.git] / 6 / contrib / wpa_supplicant / eap_tls.c
1 /*
2  * WPA Supplicant / EAP-TLS (RFC 2716)
3  * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18
19 #include "common.h"
20 #include "eap_i.h"
21 #include "eap_tls_common.h"
22 #include "wpa_supplicant.h"
23 #include "config_ssid.h"
24 #include "tls.h"
25
26
27 static void eap_tls_deinit(struct eap_sm *sm, void *priv);
28
29
30 struct eap_tls_data {
31         struct eap_ssl_data ssl;
32         u8 *key_data;
33 };
34
35
36 static void * eap_tls_init(struct eap_sm *sm)
37 {
38         struct eap_tls_data *data;
39         struct wpa_ssid *config = eap_get_config(sm);
40         if (config == NULL ||
41             ((sm->init_phase2 ? config->private_key2 : config->private_key)
42             == NULL && config->engine == 0)) {
43                 wpa_printf(MSG_INFO, "EAP-TLS: Private key not configured");
44                 return NULL;
45         }
46
47         data = malloc(sizeof(*data));
48         if (data == NULL)
49                 return NULL;
50         memset(data, 0, sizeof(*data));
51
52         if (eap_tls_ssl_init(sm, &data->ssl, config)) {
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, config);
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, config);
65                         sm->ignore = TRUE;
66                 }
67                 return NULL;
68         }
69
70         return data;
71 }
72
73
74 static void eap_tls_deinit(struct eap_sm *sm, void *priv)
75 {
76         struct eap_tls_data *data = priv;
77         if (data == NULL)
78                 return;
79         eap_tls_ssl_deinit(sm, &data->ssl);
80         free(data->key_data);
81         free(data);
82 }
83
84
85 static u8 * eap_tls_process(struct eap_sm *sm, void *priv,
86                             struct eap_method_ret *ret,
87                             const u8 *reqData, size_t reqDataLen,
88                             size_t *respDataLen)
89 {
90         struct wpa_ssid *config = eap_get_config(sm);
91         const struct eap_hdr *req;
92         size_t left;
93         int res;
94         u8 flags, *resp, id;
95         const u8 *pos;
96         struct eap_tls_data *data = priv;
97
98         pos = eap_tls_process_init(sm, &data->ssl, EAP_TYPE_TLS, ret,
99                                    reqData, reqDataLen, &left, &flags);
100         if (pos == NULL)
101                 return NULL;
102         req = (const struct eap_hdr *) reqData;
103         id = req->identifier;
104
105         if (flags & EAP_TLS_FLAGS_START) {
106                 wpa_printf(MSG_DEBUG, "EAP-TLS: Start");
107                 left = 0; /* make sure that this frame is empty, even though it
108                            * should always be, anyway */
109         }
110
111         resp = NULL;
112         res = eap_tls_process_helper(sm, &data->ssl, EAP_TYPE_TLS, 0, id, pos,
113                                      left, &resp, respDataLen);
114
115         if (res < 0) {
116                 wpa_printf(MSG_DEBUG, "EAP-TLS: TLS processing failed");
117                 ret->methodState = METHOD_MAY_CONT;
118                 ret->decision = DECISION_FAIL;
119                 if (resp) {
120                         /* This is likely an alert message, so send it instead
121                          * of just ACKing the error. */
122                         return resp;
123                 }
124                 return eap_tls_build_ack(&data->ssl, respDataLen, id,
125                                          EAP_TYPE_TLS, 0);
126         }
127
128         if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
129                 wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
130                 ret->methodState = METHOD_DONE;
131                 ret->decision = DECISION_UNCOND_SUCC;
132                 free(data->key_data);
133                 data->key_data = eap_tls_derive_key(sm, &data->ssl,
134                                                     "client EAP encryption",
135                                                     EAP_TLS_KEY_LEN);
136                 if (data->key_data) {
137                         wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived key",
138                                         data->key_data, EAP_TLS_KEY_LEN);
139                 } else {
140                         wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key");
141                 }
142         }
143
144         if (res == 1) {
145                 return eap_tls_build_ack(&data->ssl, respDataLen, id,
146                                          EAP_TYPE_TLS, 0);
147         }
148
149         if (res == -1) {
150                 /* The TLS handshake failed. So better forget the old PIN.
151                  * It may be wrong, we can't be sure but trying the wrong one
152                  * again might block it on the card - so better ask the user
153                  * again */
154                 free(config->pin);
155                 config->pin = NULL;
156         }
157
158         return resp;
159 }
160
161
162 static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv)
163 {
164         struct eap_tls_data *data = priv;
165         return tls_connection_established(sm->ssl_ctx, data->ssl.conn);
166 }
167
168
169 static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv)
170 {
171 }
172
173
174 static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv)
175 {
176         struct eap_tls_data *data = priv;
177         free(data->key_data);
178         data->key_data = NULL;
179         if (eap_tls_reauth_init(sm, &data->ssl)) {
180                 free(data);
181                 return NULL;
182         }
183         return priv;
184 }
185
186
187 static int eap_tls_get_status(struct eap_sm *sm, void *priv, char *buf,
188                               size_t buflen, int verbose)
189 {
190         struct eap_tls_data *data = priv;
191         return eap_tls_status(sm, &data->ssl, buf, buflen, verbose);
192 }
193
194
195 static Boolean eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv)
196 {
197         struct eap_tls_data *data = priv;
198         return data->key_data != NULL;
199 }
200
201
202 static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
203 {
204         struct eap_tls_data *data = priv;
205         u8 *key;
206
207         if (data->key_data == NULL)
208                 return NULL;
209
210         key = malloc(EAP_TLS_KEY_LEN);
211         if (key == NULL)
212                 return NULL;
213
214         *len = EAP_TLS_KEY_LEN;
215         memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
216
217         return key;
218 }
219
220
221 const struct eap_method eap_method_tls =
222 {
223         .method = EAP_TYPE_TLS,
224         .name = "TLS",
225         .init = eap_tls_init,
226         .deinit = eap_tls_deinit,
227         .process = eap_tls_process,
228         .isKeyAvailable = eap_tls_isKeyAvailable,
229         .getKey = eap_tls_getKey,
230         .get_status = eap_tls_get_status,
231         .has_reauth_data = eap_tls_has_reauth_data,
232         .deinit_for_reauth = eap_tls_deinit_for_reauth,
233         .init_for_reauth = eap_tls_init_for_reauth,
234 };