~ubuntu-branches/ubuntu/saucy/wpasupplicant/saucy

« back to all changes in this revision

Viewing changes to src/eap_server/eap_server_tls_common.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathieu Trudel-Lapierre
  • Date: 2010-11-22 09:43:43 UTC
  • mfrom: (1.1.16 upstream)
  • Revision ID: james.westby@ubuntu.com-20101122094343-qgsxaojvmswfri77
Tags: 0.7.3-0ubuntu1
* Get wpasupplicant 0.7.3 from Debian's SVN. Leaving 0.7.3-1 as unreleased
  for now.
* Build-Depend on debhelper 8, since the packaging from Debian uses compat 8.

Show diffs side-by-side

added added

removed removed

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