Re-initialize hostapd/wpa_supplicant git repository based on 0.6.3 release
[libeap.git] / src / eap_server / eap_tls.c
1 /*
2  * hostapd / EAP-TLS (RFC 2716)
3  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.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 "includes.h"
16
17 #include "common.h"
18 #include "eap_i.h"
19 #include "eap_tls_common.h"
20 #include "tls.h"
21
22
23 static void eap_tls_reset(struct eap_sm *sm, void *priv);
24
25
26 struct eap_tls_data {
27         struct eap_ssl_data ssl;
28         enum { START, CONTINUE, SUCCESS, FAILURE } state;
29 };
30
31
32 static void * eap_tls_init(struct eap_sm *sm)
33 {
34         struct eap_tls_data *data;
35
36         data = os_zalloc(sizeof(*data));
37         if (data == NULL)
38                 return NULL;
39         data->state = START;
40
41         if (eap_server_tls_ssl_init(sm, &data->ssl, 1)) {
42                 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
43                 eap_tls_reset(sm, data);
44                 return NULL;
45         }
46
47         return data;
48 }
49
50
51 static void eap_tls_reset(struct eap_sm *sm, void *priv)
52 {
53         struct eap_tls_data *data = priv;
54         if (data == NULL)
55                 return;
56         eap_server_tls_ssl_deinit(sm, &data->ssl);
57         os_free(data);
58 }
59
60
61 static struct wpabuf * eap_tls_build_start(struct eap_sm *sm,
62                                            struct eap_tls_data *data, u8 id)
63 {
64         struct wpabuf *req;
65
66         req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLS, 1, EAP_CODE_REQUEST,
67                             id);
68         if (req == NULL) {
69                 wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for "
70                            "request");
71                 data->state = FAILURE;
72                 return NULL;
73         }
74
75         wpabuf_put_u8(req, EAP_TLS_FLAGS_START);
76
77         data->state = CONTINUE;
78
79         return req;
80 }
81
82
83 static struct wpabuf * eap_tls_build_req(struct eap_sm *sm,
84                                          struct eap_tls_data *data, u8 id)
85 {
86         int res;
87         struct wpabuf *req;
88
89         res = eap_server_tls_buildReq_helper(sm, &data->ssl, EAP_TYPE_TLS, 0,
90                                              id, &req);
91
92         if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
93                 wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
94                 data->state = SUCCESS;
95         }
96
97         if (res == 1)
98                 return eap_server_tls_build_ack(id, EAP_TYPE_TLS, 0);
99         return req;
100 }
101
102
103 static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
104 {
105         struct eap_tls_data *data = priv;
106
107         switch (data->state) {
108         case START:
109                 return eap_tls_build_start(sm, data, id);
110         case CONTINUE:
111                 return eap_tls_build_req(sm, data, id);
112         default:
113                 wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d",
114                            __func__, data->state);
115                 return NULL;
116         }
117 }
118
119
120 static Boolean eap_tls_check(struct eap_sm *sm, void *priv,
121                              struct wpabuf *respData)
122 {
123         const u8 *pos;
124         size_t len;
125
126         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLS, respData, &len);
127         if (pos == NULL || len < 1) {
128                 wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
129                 return TRUE;
130         }
131
132         return FALSE;
133 }
134
135
136 static void eap_tls_process(struct eap_sm *sm, void *priv,
137                             struct wpabuf *respData)
138 {
139         struct eap_tls_data *data = priv;
140         const u8 *pos;
141         u8 flags;
142         size_t left;
143         unsigned int tls_msg_len;
144
145         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLS, respData, &left);
146         if (pos == NULL || left < 1)
147                 return; /* Should not happen - frame already validated */
148
149         flags = *pos++;
150         left--;
151         wpa_printf(MSG_DEBUG, "EAP-TLS: Received packet(len=%lu) - "
152                    "Flags 0x%02x", (unsigned long) wpabuf_len(respData),
153                    flags);
154         if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
155                 if (left < 4) {
156                         wpa_printf(MSG_INFO, "EAP-TLS: Short frame with TLS "
157                                    "length");
158                         data->state = FAILURE;
159                         return;
160                 }
161                 tls_msg_len = WPA_GET_BE32(pos);
162                 wpa_printf(MSG_DEBUG, "EAP-TLS: TLS Message Length: %d",
163                            tls_msg_len);
164                 if (data->ssl.tls_in_left == 0) {
165                         data->ssl.tls_in_total = tls_msg_len;
166                         data->ssl.tls_in_left = tls_msg_len;
167                         os_free(data->ssl.tls_in);
168                         data->ssl.tls_in = NULL;
169                         data->ssl.tls_in_len = 0;
170                 }
171                 pos += 4;
172                 left -= 4;
173         }
174
175         if (eap_server_tls_process_helper(sm, &data->ssl, pos, left) < 0) {
176                 wpa_printf(MSG_INFO, "EAP-TLS: TLS processing failed");
177                 data->state = FAILURE;
178                 return;
179         }
180
181         if (tls_connection_get_write_alerts(sm->ssl_ctx, data->ssl.conn) > 1) {
182                 wpa_printf(MSG_INFO, "EAP-TLS: Locally detected fatal error "
183                            "in TLS processing");
184                 data->state = FAILURE;
185                 return;
186         }
187 }
188
189
190 static Boolean eap_tls_isDone(struct eap_sm *sm, void *priv)
191 {
192         struct eap_tls_data *data = priv;
193         return data->state == SUCCESS || data->state == FAILURE;
194 }
195
196
197 static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
198 {
199         struct eap_tls_data *data = priv;
200         u8 *eapKeyData;
201
202         if (data->state != SUCCESS)
203                 return NULL;
204
205         eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
206                                                "client EAP encryption",
207                                                EAP_TLS_KEY_LEN);
208         if (eapKeyData) {
209                 *len = EAP_TLS_KEY_LEN;
210                 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key",
211                             eapKeyData, EAP_TLS_KEY_LEN);
212         } else {
213                 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key");
214         }
215
216         return eapKeyData;
217 }
218
219
220 static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
221 {
222         struct eap_tls_data *data = priv;
223         u8 *eapKeyData, *emsk;
224
225         if (data->state != SUCCESS)
226                 return NULL;
227
228         eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
229                                                "client EAP encryption",
230                                                EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
231         if (eapKeyData) {
232                 emsk = os_malloc(EAP_EMSK_LEN);
233                 if (emsk)
234                         os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
235                                   EAP_EMSK_LEN);
236                 os_free(eapKeyData);
237         } else
238                 emsk = NULL;
239
240         if (emsk) {
241                 *len = EAP_EMSK_LEN;
242                 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK",
243                             emsk, EAP_EMSK_LEN);
244         } else {
245                 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK");
246         }
247
248         return emsk;
249 }
250
251
252 static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv)
253 {
254         struct eap_tls_data *data = priv;
255         return data->state == SUCCESS;
256 }
257
258
259 int eap_server_tls_register(void)
260 {
261         struct eap_method *eap;
262         int ret;
263
264         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
265                                       EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
266         if (eap == NULL)
267                 return -1;
268
269         eap->init = eap_tls_init;
270         eap->reset = eap_tls_reset;
271         eap->buildReq = eap_tls_buildReq;
272         eap->check = eap_tls_check;
273         eap->process = eap_tls_process;
274         eap->isDone = eap_tls_isDone;
275         eap->getKey = eap_tls_getKey;
276         eap->isSuccess = eap_tls_isSuccess;
277         eap->get_emsk = eap_tls_get_emsk;
278
279         ret = eap_server_method_register(eap);
280         if (ret)
281                 eap_server_method_free(eap);
282         return ret;
283 }