]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wpa_supplicant/eap_tls.c
This commit was generated by cvs2svn to compensate for changes in r154184,
[FreeBSD/FreeBSD.git] / 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) {
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                 return NULL;
56         }
57
58         return data;
59 }
60
61
62 static void eap_tls_deinit(struct eap_sm *sm, void *priv)
63 {
64         struct eap_tls_data *data = priv;
65         if (data == NULL)
66                 return;
67         eap_tls_ssl_deinit(sm, &data->ssl);
68         free(data->key_data);
69         free(data);
70 }
71
72
73 static u8 * eap_tls_process(struct eap_sm *sm, void *priv,
74                             struct eap_method_ret *ret,
75                             u8 *reqData, size_t reqDataLen,
76                             size_t *respDataLen)
77 {
78         struct eap_hdr *req;
79         int left, res;
80         unsigned int tls_msg_len;
81         u8 flags, *pos, *resp, id;
82         struct eap_tls_data *data = priv;
83
84         if (tls_get_errors(sm->ssl_ctx)) {
85                 wpa_printf(MSG_INFO, "EAP-TLS: TLS errors detected");
86                 ret->ignore = TRUE;
87                 return NULL;
88         }
89
90         req = (struct eap_hdr *) reqData;
91         pos = (u8 *) (req + 1);
92         if (reqDataLen < sizeof(*req) + 2 || *pos != EAP_TYPE_TLS) {
93                 wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
94                 ret->ignore = TRUE;
95                 return NULL;
96         }
97         id = req->identifier;
98         pos++;
99         flags = *pos++;
100         left = be_to_host16(req->length) - sizeof(struct eap_hdr) - 2;
101         wpa_printf(MSG_DEBUG, "EAP-TLS: Received packet(len=%lu) - "
102                    "Flags 0x%02x", (unsigned long) reqDataLen, flags);
103         if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
104                 if (left < 4) {
105                         wpa_printf(MSG_INFO, "EAP-TLS: Short frame with TLS "
106                                    "length");
107                         ret->ignore = TRUE;
108                         return NULL;
109                 }
110                 tls_msg_len = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) |
111                         pos[3];
112                 wpa_printf(MSG_DEBUG, "EAP-TLS: TLS Message Length: %d",
113                            tls_msg_len);
114                 if (data->ssl.tls_in_left == 0) {
115                         data->ssl.tls_in_total = tls_msg_len;
116                         data->ssl.tls_in_left = tls_msg_len;
117                         free(data->ssl.tls_in);
118                         data->ssl.tls_in = NULL;
119                         data->ssl.tls_in_len = 0;
120                 }
121                 pos += 4;
122                 left -= 4;
123         }
124
125         ret->ignore = FALSE;
126
127         ret->methodState = METHOD_CONT;
128         ret->decision = DECISION_COND_SUCC;
129         ret->allowNotifications = TRUE;
130
131         if (flags & EAP_TLS_FLAGS_START) {
132                 wpa_printf(MSG_DEBUG, "EAP-TLS: Start");
133                 left = 0; /* make sure that this frame is empty, even though it
134                            * should always be, anyway */
135         }
136
137         resp = NULL;
138         res = eap_tls_process_helper(sm, &data->ssl, EAP_TYPE_TLS, 0, id, pos,
139                                      left, &resp, respDataLen);
140
141         if (res < 0) {
142                 wpa_printf(MSG_DEBUG, "EAP-TLS: TLS processing failed");
143                 ret->methodState = METHOD_MAY_CONT;
144                 ret->decision = DECISION_FAIL;
145                 return eap_tls_build_ack(&data->ssl, respDataLen, id,
146                                          EAP_TYPE_TLS, 0);
147         }
148
149         if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
150                 wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
151                 ret->methodState = METHOD_DONE;
152                 ret->decision = DECISION_UNCOND_SUCC;
153                 free(data->key_data);
154                 data->key_data = eap_tls_derive_key(sm, &data->ssl,
155                                                     "client EAP encryption",
156                                                     EAP_TLS_KEY_LEN);
157                 if (data->key_data) {
158                         wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived key",
159                                         data->key_data, EAP_TLS_KEY_LEN);
160                 } else {
161                         wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key");
162                 }
163         }
164
165         if (res == 1) {
166                 return eap_tls_build_ack(&data->ssl, respDataLen, id,
167                                          EAP_TYPE_TLS, 0);
168         }
169         return resp;
170 }
171
172
173 static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv)
174 {
175         struct eap_tls_data *data = priv;
176         return tls_connection_established(sm->ssl_ctx, data->ssl.conn);
177 }
178
179
180 static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv)
181 {
182 }
183
184
185 static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv)
186 {
187         struct eap_tls_data *data = priv;
188         free(data->key_data);
189         data->key_data = NULL;
190         if (eap_tls_reauth_init(sm, &data->ssl)) {
191                 free(data);
192                 return NULL;
193         }
194         return priv;
195 }
196
197
198 static int eap_tls_get_status(struct eap_sm *sm, void *priv, char *buf,
199                               size_t buflen, int verbose)
200 {
201         struct eap_tls_data *data = priv;
202         return eap_tls_status(sm, &data->ssl, buf, buflen, verbose);
203 }
204
205
206 static Boolean eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv)
207 {
208         struct eap_tls_data *data = priv;
209         return data->key_data != NULL;
210 }
211
212
213 static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
214 {
215         struct eap_tls_data *data = priv;
216         u8 *key;
217
218         if (data->key_data == NULL)
219                 return NULL;
220
221         key = malloc(EAP_TLS_KEY_LEN);
222         if (key == NULL)
223                 return NULL;
224
225         *len = EAP_TLS_KEY_LEN;
226         memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
227
228         return key;
229 }
230
231
232 const struct eap_method eap_method_tls =
233 {
234         .method = EAP_TYPE_TLS,
235         .name = "TLS",
236         .init = eap_tls_init,
237         .deinit = eap_tls_deinit,
238         .process = eap_tls_process,
239         .isKeyAvailable = eap_tls_isKeyAvailable,
240         .getKey = eap_tls_getKey,
241         .get_status = eap_tls_get_status,
242         .has_reauth_data = eap_tls_has_reauth_data,
243         .deinit_for_reauth = eap_tls_deinit_for_reauth,
244         .init_for_reauth = eap_tls_init_for_reauth,
245 };