894b27f916913693cda587dcf266fec695d4dc47
[libeap.git] / src / eap_server / eap_tls_common.c
1 /*
2  * hostapd / EAP-TLS/PEAP/TTLS/FAST common functions
3  * Copyright (c) 2004-2008, 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 "sha1.h"
21 #include "tls.h"
22
23
24 int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
25                             int verify_peer)
26 {
27         data->eap = sm;
28         data->phase2 = sm->init_phase2;
29
30         data->conn = tls_connection_init(sm->ssl_ctx);
31         if (data->conn == NULL) {
32                 wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
33                            "connection");
34                 return -1;
35         }
36
37         if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer)) {
38                 wpa_printf(MSG_INFO, "SSL: Failed to configure verification "
39                            "of TLS peer certificate");
40                 tls_connection_deinit(sm->ssl_ctx, data->conn);
41                 data->conn = NULL;
42                 return -1;
43         }
44
45         /* TODO: make this configurable */
46         data->tls_out_limit = 1398;
47         if (data->phase2) {
48                 /* Limit the fragment size in the inner TLS authentication
49                  * since the outer authentication with EAP-PEAP does not yet
50                  * support fragmentation */
51                 if (data->tls_out_limit > 100)
52                         data->tls_out_limit -= 100;
53         }
54         return 0;
55 }
56
57
58 void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
59 {
60         tls_connection_deinit(sm->ssl_ctx, data->conn);
61         os_free(data->in_buf);
62         os_free(data->out_buf);
63 }
64
65
66 u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
67                                char *label, size_t len)
68 {
69         struct tls_keys keys;
70         u8 *rnd = NULL, *out;
71
72         out = os_malloc(len);
73         if (out == NULL)
74                 return NULL;
75
76         if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) ==
77             0)
78                 return out;
79
80         if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
81                 goto fail;
82
83         if (keys.client_random == NULL || keys.server_random == NULL ||
84             keys.master_key == NULL)
85                 goto fail;
86
87         rnd = os_malloc(keys.client_random_len + keys.server_random_len);
88         if (rnd == NULL)
89                 goto fail;
90         os_memcpy(rnd, keys.client_random, keys.client_random_len);
91         os_memcpy(rnd + keys.client_random_len, keys.server_random,
92                   keys.server_random_len);
93
94         if (tls_prf(keys.master_key, keys.master_key_len,
95                     label, rnd, keys.client_random_len +
96                     keys.server_random_len, out, len))
97                 goto fail;
98
99         os_free(rnd);
100         return out;
101
102 fail:
103         os_free(out);
104         os_free(rnd);
105         return NULL;
106 }
107
108
109 struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
110                                          int eap_type, int version, u8 id)
111 {
112         struct wpabuf *req;
113         u8 flags;
114         size_t send_len, plen;
115
116         wpa_printf(MSG_DEBUG, "SSL: Generating Request");
117
118         flags = version;
119         send_len = wpabuf_len(data->out_buf) - data->out_used;
120         if (1 + send_len > data->tls_out_limit) {
121                 send_len = data->tls_out_limit - 1;
122                 flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
123                 if (data->out_used == 0) {
124                         flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
125                         send_len -= 4;
126                 }
127         }
128
129         plen = 1 + send_len;
130         if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
131                 plen += 4;
132
133         req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, plen,
134                             EAP_CODE_REQUEST, id);
135         if (req == NULL)
136                 return NULL;
137
138         wpabuf_put_u8(req, flags); /* Flags */
139         if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
140                 wpabuf_put_be32(req, wpabuf_len(data->out_buf));
141
142         wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used,
143                         send_len);
144         data->out_used += send_len;
145
146         if (data->out_used == wpabuf_len(data->out_buf)) {
147                 wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes "
148                            "(message sent completely)",
149                            (unsigned long) send_len);
150                 wpabuf_free(data->out_buf);
151                 data->out_buf = NULL;
152                 data->out_used = 0;
153                 data->state = MSG;
154         } else {
155                 wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes "
156                            "(%lu more to send)", (unsigned long) send_len,
157                            (unsigned long) wpabuf_len(data->out_buf) -
158                            data->out_used);
159                 data->state = WAIT_FRAG_ACK;
160         }
161
162         return req;
163 }
164
165
166 struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version)
167 {
168         struct wpabuf *req;
169
170         req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, 1, EAP_CODE_REQUEST,
171                             id);
172         if (req == NULL)
173                 return NULL;
174         wpa_printf(MSG_DEBUG, "SSL: Building ACK");
175         wpabuf_put_u8(req, version); /* Flags */
176         return req;
177 }
178
179
180 static int eap_server_tls_process_cont(struct eap_ssl_data *data,
181                                        const u8 *buf, size_t len)
182 {
183         /* Process continuation of a pending message */
184         if (len > wpabuf_tailroom(data->in_buf)) {
185                 wpa_printf(MSG_DEBUG, "SSL: Fragment overflow");
186                 return -1;
187         }
188
189         wpabuf_put_data(data->in_buf, buf, len);
190         wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes, waiting for %lu "
191                    "bytes more", (unsigned long) len,
192                    (unsigned long) wpabuf_tailroom(data->in_buf));
193
194         return 0;
195 }
196
197
198 static int eap_server_tls_process_fragment(struct eap_ssl_data *data,
199                                            u8 flags, u32 message_length,
200                                            const u8 *buf, size_t len)
201 {
202         /* Process a fragment that is not the last one of the message */
203         if (data->in_buf == NULL && !(flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)) {
204                 wpa_printf(MSG_DEBUG, "SSL: No Message Length field in a "
205                            "fragmented packet");
206                 return -1;
207         }
208
209         if (data->in_buf == NULL) {
210                 /* First fragment of the message */
211
212                 /* Limit length to avoid rogue peers from causing large
213                  * memory allocations. */
214                 if (message_length > 65536) {
215                         wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size"
216                                    " over 64 kB)");
217                         return -1;
218                 }
219
220                 data->in_buf = wpabuf_alloc(message_length);
221                 if (data->in_buf == NULL) {
222                         wpa_printf(MSG_DEBUG, "SSL: No memory for message");
223                         return -1;
224                 }
225                 wpabuf_put_data(data->in_buf, buf, len);
226                 wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes in first "
227                            "fragment, waiting for %lu bytes more",
228                            (unsigned long) len,
229                            (unsigned long) wpabuf_tailroom(data->in_buf));
230         }
231
232         return 0;
233 }
234
235
236 int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data)
237 {
238         u8 *next;
239         size_t next_len;
240
241         next = tls_connection_server_handshake(
242                 sm->ssl_ctx, data->conn,
243                 wpabuf_mhead(data->in_buf),
244                 wpabuf_len(data->in_buf),
245                 &next_len);
246         if (next == NULL) {
247                 wpa_printf(MSG_INFO, "SSL: TLS processing failed");
248                 return -1;
249         }
250         if (data->out_buf) {
251                 /* This should not happen.. */
252                 wpa_printf(MSG_INFO, "SSL: pending tls_out data when "
253                            "processing new message");
254                 os_free(data->out_buf);
255                 WPA_ASSERT(data->out_buf == NULL);
256         }
257         data->out_buf = wpabuf_alloc_ext_data(next, next_len);
258         if (data->out_buf == NULL) {
259                 os_free(next);
260                 return -1;
261         }
262         return 0;
263 }
264
265
266 int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags,
267                               const u8 **pos, size_t *left)
268 {
269         unsigned int tls_msg_len = 0;
270         const u8 *end = *pos + *left;
271
272         if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
273                 if (*left < 4) {
274                         wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
275                                    "length");
276                         return -1;
277                 }
278                 tls_msg_len = WPA_GET_BE32(*pos);
279                 wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d",
280                            tls_msg_len);
281                 *pos += 4;
282                 *left -= 4;
283         }
284
285         wpa_printf(MSG_DEBUG, "SSL: Received packet: Flags 0x%x "
286                    "Message Length %u", flags, tls_msg_len);
287
288         if (data->state == WAIT_FRAG_ACK) {
289                 if (*left != 0) {
290                         wpa_printf(MSG_DEBUG, "SSL: Unexpected payload in "
291                                    "WAIT_FRAG_ACK state");
292                         return -1;
293                 }
294                 wpa_printf(MSG_DEBUG, "SSL: Fragment acknowledged");
295                 return 1;
296         }
297
298         if (data->in_buf &&
299             eap_server_tls_process_cont(data, *pos, end - *pos) < 0)
300                 return -1;
301                 
302         if (flags & EAP_TLS_FLAGS_MORE_FRAGMENTS) {
303                 if (eap_server_tls_process_fragment(data, flags, tls_msg_len,
304                                                     *pos, end - *pos) < 0)
305                         return -1;
306
307                 data->state = FRAG_ACK;
308                 return 1;
309         }
310
311         if (data->state == FRAG_ACK) {
312                 wpa_printf(MSG_DEBUG, "SSL: All fragments received");
313                 data->state = MSG;
314         }
315
316         if (data->in_buf == NULL) {
317                 /* Wrap unfragmented messages as wpabuf without extra copy */
318                 wpabuf_set(&data->tmpbuf, *pos, end - *pos);
319                 data->in_buf = &data->tmpbuf;
320         }
321
322         return 0;
323 }
324
325
326 void eap_server_tls_free_in_buf(struct eap_ssl_data *data)
327 {
328         if (data->in_buf != &data->tmpbuf)
329                 wpabuf_free(data->in_buf);
330         data->in_buf = NULL;
331 }
332
333
334 struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm,
335                                        struct eap_ssl_data *data,
336                                        const u8 *plain, size_t plain_len)
337 {
338         int res;
339         struct wpabuf *buf;
340         size_t buf_len;
341
342         /* reserve some extra room for encryption overhead */
343         buf_len = plain_len + 200;
344         buf = wpabuf_alloc(buf_len);
345         res = tls_connection_encrypt(sm->ssl_ctx, data->conn,
346                                      plain, plain_len, wpabuf_put(buf, 0),
347                                      buf_len);
348         if (res < 0) {
349                 wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 data");
350                 wpabuf_free(buf);
351                 return NULL;
352         }
353
354         wpabuf_put(buf, res);
355
356         return buf;
357 }