Add advice if a kernel config file cannot be found to remind people that
[dragonfly.git] / contrib / wpa_supplicant-0.4.9 / 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
120                 if (res == -1) {
121                         /*
122                          * The TLS handshake failed. So better forget the old
123                          * PIN. It may be wrong, we can't be sure but trying
124                          * the wrong one again might block it on the card - so
125                          * better ask the user again.
126                          */
127                         free(config->pin);
128                         config->pin = NULL;
129                 }
130
131                 if (resp) {
132                         /* This is likely an alert message, so send it instead
133                          * of just ACKing the error. */
134                         return resp;
135                 }
136                 return eap_tls_build_ack(&data->ssl, respDataLen, id,
137                                          EAP_TYPE_TLS, 0);
138         }
139
140         if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
141                 wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
142                 ret->methodState = METHOD_DONE;
143                 ret->decision = DECISION_UNCOND_SUCC;
144                 free(data->key_data);
145                 data->key_data = eap_tls_derive_key(sm, &data->ssl,
146                                                     "client EAP encryption",
147                                                     EAP_TLS_KEY_LEN);
148                 if (data->key_data) {
149                         wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived key",
150                                         data->key_data, EAP_TLS_KEY_LEN);
151                 } else {
152                         wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key");
153                 }
154         }
155
156         if (res == 1) {
157                 return eap_tls_build_ack(&data->ssl, respDataLen, id,
158                                          EAP_TYPE_TLS, 0);
159         }
160
161         return resp;
162 }
163
164
165 static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv)
166 {
167         struct eap_tls_data *data = priv;
168         return tls_connection_established(sm->ssl_ctx, data->ssl.conn);
169 }
170
171
172 static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv)
173 {
174 }
175
176
177 static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv)
178 {
179         struct eap_tls_data *data = priv;
180         free(data->key_data);
181         data->key_data = NULL;
182         if (eap_tls_reauth_init(sm, &data->ssl)) {
183                 free(data);
184                 return NULL;
185         }
186         return priv;
187 }
188
189
190 static int eap_tls_get_status(struct eap_sm *sm, void *priv, char *buf,
191                               size_t buflen, int verbose)
192 {
193         struct eap_tls_data *data = priv;
194         return eap_tls_status(sm, &data->ssl, buf, buflen, verbose);
195 }
196
197
198 static Boolean eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv)
199 {
200         struct eap_tls_data *data = priv;
201         return data->key_data != NULL;
202 }
203
204
205 static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
206 {
207         struct eap_tls_data *data = priv;
208         u8 *key;
209
210         if (data->key_data == NULL)
211                 return NULL;
212
213         key = malloc(EAP_TLS_KEY_LEN);
214         if (key == NULL)
215                 return NULL;
216
217         *len = EAP_TLS_KEY_LEN;
218         memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
219
220         return key;
221 }
222
223
224 const struct eap_method eap_method_tls =
225 {
226         .method = EAP_TYPE_TLS,
227         .name = "TLS",
228         .init = eap_tls_init,
229         .deinit = eap_tls_deinit,
230         .process = eap_tls_process,
231         .isKeyAvailable = eap_tls_isKeyAvailable,
232         .getKey = eap_tls_getKey,
233         .get_status = eap_tls_get_status,
234         .has_reauth_data = eap_tls_has_reauth_data,
235         .deinit_for_reauth = eap_tls_deinit_for_reauth,
236         .init_for_reauth = eap_tls_init_for_reauth,
237 };