~ubuntu-branches/ubuntu/gutsy/wpasupplicant/gutsy

« back to all changes in this revision

Viewing changes to src/eap_server/eap_tls_common.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler, Alexander Sack
  • Date: 2007-08-26 16:06:57 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20070826160657-2m8pxoweuxe8f93t
Tags: 0.6.0+0.5.8-0ubuntu1
* New upstream release
* remove patch 11_erroneous_manpage_ref, applied upstream
* remove patch 25_wpas_dbus_unregister_iface_fix, applied upstream

[ Alexander Sack ]
* bumping upstream version to replace development version 0.6.0 with
  this package from stable release branch.
* attempt to fix wierd timeout and high latency issues by going
  back to stable upstream version (0.5.9) (LP: #140763,
  LP: #141233).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * hostapd / EAP-TLS/PEAP/TTLS common functions
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 "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
 
        free(data->tls_in);
62
 
        free(data->tls_out);
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 = 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 = malloc(keys.client_random_len + keys.server_random_len);
88
 
        if (rnd == NULL)
89
 
                goto fail;
90
 
        memcpy(rnd, keys.client_random, keys.client_random_len);
91
 
        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
 
        free(rnd);
100
 
        return out;
101
 
 
102
 
fail:
103
 
        free(out);
104
 
        free(rnd);
105
 
        return NULL;
106
 
}
107
 
 
108
 
 
109
 
int eap_server_tls_data_reassemble(struct eap_sm *sm,
110
 
                                   struct eap_ssl_data *data,
111
 
                                   u8 **in_data, size_t *in_len)
112
 
{
113
 
        u8 *buf;
114
 
 
115
 
        if (data->tls_in_left > *in_len || data->tls_in) {
116
 
                if (data->tls_in_len + *in_len > 65536) {
117
 
                        /* Limit length to avoid rogue peers from causing large
118
 
                         * memory allocations. */
119
 
                        free(data->tls_in);
120
 
                        data->tls_in = NULL;
121
 
                        data->tls_in_len = 0;
122
 
                        wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size"
123
 
                                   " over 64 kB)");
124
 
                        return -1;
125
 
                }
126
 
                buf = realloc(data->tls_in, data->tls_in_len + *in_len);
127
 
                if (buf == NULL) {
128
 
                        free(data->tls_in);
129
 
                        data->tls_in = NULL;
130
 
                        data->tls_in_len = 0;
131
 
                        wpa_printf(MSG_INFO, "SSL: Could not allocate memory "
132
 
                                   "for TLS data");
133
 
                        return -1;
134
 
                }
135
 
                memcpy(buf + data->tls_in_len, *in_data, *in_len);
136
 
                data->tls_in = buf;
137
 
                data->tls_in_len += *in_len;
138
 
                if (*in_len > data->tls_in_left) {
139
 
                        wpa_printf(MSG_INFO, "SSL: more data than TLS message "
140
 
                                   "length indicated");
141
 
                        data->tls_in_left = 0;
142
 
                        return -1;
143
 
                }
144
 
                data->tls_in_left -= *in_len;
145
 
                if (data->tls_in_left > 0) {
146
 
                        wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input "
147
 
                                   "data", (unsigned long) data->tls_in_left);
148
 
                        return 1;
149
 
                }
150
 
 
151
 
                *in_data = data->tls_in;
152
 
                *in_len = data->tls_in_len;
153
 
        } else
154
 
                data->tls_in_left = 0;
155
 
 
156
 
        return 0;
157
 
}
158
 
 
159
 
 
160
 
int eap_server_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
161
 
                                  u8 *in_data, size_t in_len)
162
 
{
163
 
        WPA_ASSERT(data->tls_out_len == 0 || in_len == 0);
164
 
 
165
 
        if (data->tls_out_len == 0) {
166
 
                /* No more data to send out - expect to receive more data from
167
 
                 * the peer. */
168
 
                int res = eap_server_tls_data_reassemble(sm, data, &in_data,
169
 
                                                         &in_len);
170
 
                if (res < 0 || res == 1) {
171
 
                        wpa_printf(MSG_DEBUG, "SSL: data reassembly failed");
172
 
                        return res;
173
 
                }
174
 
                /* Full TLS message reassembled - continue handshake processing
175
 
                 */
176
 
                if (data->tls_out) {
177
 
                        /* This should not happen.. */
178
 
                        wpa_printf(MSG_INFO, "SSL: eap_tls_process_helper - "
179
 
                                   "pending tls_out data even though "
180
 
                                   "tls_out_len = 0");
181
 
                        free(data->tls_out);
182
 
                        WPA_ASSERT(data->tls_out == NULL);
183
 
                }
184
 
                data->tls_out = tls_connection_server_handshake(
185
 
                        sm->ssl_ctx, data->conn, in_data, in_len,
186
 
                        &data->tls_out_len);
187
 
 
188
 
                /* Clear reassembled input data (if the buffer was needed). */
189
 
                data->tls_in_left = data->tls_in_total = data->tls_in_len = 0;
190
 
                free(data->tls_in);
191
 
                data->tls_in = NULL;
192
 
        }
193
 
 
194
 
        if (data->tls_out == NULL) {
195
 
                wpa_printf(MSG_DEBUG, "SSL: failed to generate output data");
196
 
                data->tls_out_len = 0;
197
 
                return -1;
198
 
        }
199
 
        if (data->tls_out_len == 0) {
200
 
                /* TLS negotiation should now be complete since all other cases
201
 
                 * needing more that should have been catched above based on
202
 
                 * the TLS Message Length field. */
203
 
                wpa_printf(MSG_DEBUG, "SSL: No data to be sent out");
204
 
                free(data->tls_out);
205
 
                data->tls_out = NULL;
206
 
 
207
 
                if (tls_connection_get_read_alerts(sm->ssl_ctx, data->conn)) {
208
 
                        wpa_printf(MSG_DEBUG, "SSL: Remote end sent a fatal "
209
 
                                   "alert - abort handshake");
210
 
                        return -1;
211
 
                }
212
 
 
213
 
                return 1;
214
 
        }
215
 
 
216
 
        wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total "
217
 
                   "%lu bytes)",
218
 
                   (unsigned long) data->tls_out_len - data->tls_out_pos,
219
 
                   (unsigned long) data->tls_out_len);
220
 
 
221
 
        return 0;
222
 
}
223
 
 
224
 
 
225
 
int eap_server_tls_buildReq_helper(struct eap_sm *sm,
226
 
                                   struct eap_ssl_data *data,
227
 
                                   int eap_type, int peap_version, u8 id,
228
 
                                   u8 **out_data, size_t *out_len)
229
 
{
230
 
        size_t len;
231
 
        u8 *pos, *flags;
232
 
        struct eap_hdr *req;
233
 
 
234
 
        *out_len = 0;
235
 
 
236
 
        req = malloc(sizeof(struct eap_hdr) + 2 + 4 + data->tls_out_limit);
237
 
        if (req == NULL) {
238
 
                *out_data = NULL;
239
 
                return -1;
240
 
        }
241
 
        req->code = EAP_CODE_REQUEST;
242
 
        req->identifier = id;
243
 
        pos = (u8 *) (req + 1);
244
 
        *pos++ = eap_type;
245
 
        flags = pos++;
246
 
        *flags = peap_version;
247
 
        if (data->tls_out_pos == 0 &&
248
 
            data->tls_out_len > data->tls_out_limit) {
249
 
                *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
250
 
                WPA_PUT_BE32(pos, data->tls_out_len);
251
 
                pos += 4;
252
 
        }
253
 
 
254
 
        len = data->tls_out_len - data->tls_out_pos;
255
 
        if (len > data->tls_out_limit) {
256
 
                *flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
257
 
                len = data->tls_out_limit;
258
 
                wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments "
259
 
                           "will follow", (unsigned long) len);
260
 
        }
261
 
        memcpy(pos, &data->tls_out[data->tls_out_pos], len);
262
 
        data->tls_out_pos += len;
263
 
        *out_len = (pos - (u8 *) req) + len;
264
 
        req->length = host_to_be16(*out_len);
265
 
        *out_data = (u8 *) req;
266
 
 
267
 
        if (!(*flags & EAP_TLS_FLAGS_MORE_FRAGMENTS)) {
268
 
                data->tls_out_len = 0;
269
 
                data->tls_out_pos = 0;
270
 
                free(data->tls_out);
271
 
                data->tls_out = NULL;
272
 
        }
273
 
 
274
 
        return 0;
275
 
}
276
 
 
277
 
 
278
 
u8 * eap_server_tls_build_ack(size_t *reqDataLen, u8 id, int eap_type,
279
 
                              int peap_version)
280
 
{
281
 
        struct eap_hdr *req;
282
 
        u8 *pos;
283
 
 
284
 
        *reqDataLen = sizeof(struct eap_hdr) + 2;
285
 
        req = malloc(*reqDataLen);
286
 
        if (req == NULL)
287
 
                return NULL;
288
 
        wpa_printf(MSG_DEBUG, "SSL: Building ACK");
289
 
        req->code = EAP_CODE_REQUEST;
290
 
        req->identifier = id;
291
 
        req->length = host_to_be16(*reqDataLen);
292
 
        pos = (u8 *) (req + 1);
293
 
        *pos++ = eap_type; /* Type */
294
 
        *pos = peap_version; /* Flags */
295
 
        return (u8 *) req;
296
 
}