~ubuntu-branches/ubuntu/hardy/wpasupplicant/hardy

« back to all changes in this revision

Viewing changes to 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
 * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
 
3
 * Copyright (c) 2004-2006, 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 "config_ssid.h"
 
21
#include "md5.h"
 
22
#include "sha1.h"
 
23
#include "tls.h"
 
24
#include "config.h"
 
25
 
 
26
 
 
27
static int eap_tls_check_blob(struct eap_sm *sm, const char **name,
 
28
                              const u8 **data, size_t *data_len)
 
29
{
 
30
        const struct wpa_config_blob *blob;
 
31
 
 
32
        if (*name == NULL || os_strncmp(*name, "blob://", 7) != 0)
 
33
                return 0;
 
34
 
 
35
        blob = eap_get_config_blob(sm, *name + 7);
 
36
        if (blob == NULL) {
 
37
                wpa_printf(MSG_ERROR, "%s: Named configuration blob '%s' not "
 
38
                           "found", __func__, *name + 7);
 
39
                return -1;
 
40
        }
 
41
 
 
42
        *name = NULL;
 
43
        *data = blob->data;
 
44
        *data_len = blob->len;
 
45
 
 
46
        return 0;
 
47
}
 
48
 
 
49
 
 
50
static void eap_tls_params_from_conf1(struct tls_connection_params *params,
 
51
                                      struct wpa_ssid *config)
 
52
{
 
53
        params->ca_cert = (char *) config->ca_cert;
 
54
        params->ca_path = (char *) config->ca_path;
 
55
        params->client_cert = (char *) config->client_cert;
 
56
        params->private_key = (char *) config->private_key;
 
57
        params->private_key_passwd = (char *) config->private_key_passwd;
 
58
        params->dh_file = (char *) config->dh_file;
 
59
        params->subject_match = (char *) config->subject_match;
 
60
        params->altsubject_match = (char *) config->altsubject_match;
 
61
        params->engine_id = config->engine_id;
 
62
        params->pin = config->pin;
 
63
        params->key_id = config->key_id;
 
64
}
 
65
 
 
66
 
 
67
static void eap_tls_params_from_conf2(struct tls_connection_params *params,
 
68
                                      struct wpa_ssid *config)
 
69
{
 
70
        params->ca_cert = (char *) config->ca_cert2;
 
71
        params->ca_path = (char *) config->ca_path2;
 
72
        params->client_cert = (char *) config->client_cert2;
 
73
        params->private_key = (char *) config->private_key2;
 
74
        params->private_key_passwd = (char *) config->private_key2_passwd;
 
75
        params->dh_file = (char *) config->dh_file2;
 
76
        params->subject_match = (char *) config->subject_match2;
 
77
        params->altsubject_match = (char *) config->altsubject_match2;
 
78
}
 
79
 
 
80
 
 
81
static int eap_tls_params_from_conf(struct eap_sm *sm,
 
82
                                    struct eap_ssl_data *data,
 
83
                                    struct tls_connection_params *params,
 
84
                                    struct wpa_ssid *config, int phase2)
 
85
{
 
86
        os_memset(params, 0, sizeof(*params));
 
87
        params->engine = config->engine;
 
88
        if (phase2)
 
89
                eap_tls_params_from_conf2(params, config);
 
90
        else
 
91
                eap_tls_params_from_conf1(params, config);
 
92
        params->tls_ia = data->tls_ia;
 
93
 
 
94
 
 
95
        if (eap_tls_check_blob(sm, &params->ca_cert, &params->ca_cert_blob,
 
96
                               &params->ca_cert_blob_len) ||
 
97
            eap_tls_check_blob(sm, &params->client_cert,
 
98
                               &params->client_cert_blob,
 
99
                               &params->client_cert_blob_len) ||
 
100
            eap_tls_check_blob(sm, &params->private_key,
 
101
                               &params->private_key_blob,
 
102
                               &params->private_key_blob_len) ||
 
103
            eap_tls_check_blob(sm, &params->dh_file, &params->dh_blob,
 
104
                               &params->dh_blob_len)) {
 
105
                wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs");
 
106
                return -1;
 
107
        }
 
108
 
 
109
        return 0;
 
110
}
 
111
 
 
112
 
 
113
static int eap_tls_init_connection(struct eap_sm *sm,
 
114
                                   struct eap_ssl_data *data,
 
115
                                   struct wpa_ssid *config,
 
116
                                   struct tls_connection_params *params)
 
117
{
 
118
        int res;
 
119
 
 
120
        data->conn = tls_connection_init(sm->ssl_ctx);
 
121
        if (data->conn == NULL) {
 
122
                wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
 
123
                           "connection");
 
124
                return -1;
 
125
        }
 
126
 
 
127
        res = tls_connection_set_params(sm->ssl_ctx, data->conn, params);
 
128
        if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) {
 
129
                /* At this point with the pkcs11 engine the PIN might be wrong.
 
130
                 * We reset the PIN in the configuration to be sure to not use
 
131
                 * it again and the calling function must request a new one */
 
132
                os_free(config->pin);
 
133
                config->pin = NULL;
 
134
        } else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) {
 
135
                wpa_printf(MSG_INFO, "TLS: Failed to load private key");
 
136
                /* We don't know exactly but maybe the PIN was wrong,
 
137
                 * so ask for a new one. */
 
138
                os_free(config->pin);
 
139
                config->pin = NULL;
 
140
                eap_sm_request_pin(sm);
 
141
                sm->ignore = TRUE;
 
142
                return -1;
 
143
        } else if (res) {
 
144
                wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection "
 
145
                           "parameters");
 
146
                return -1;
 
147
        }
 
148
 
 
149
        return 0;
 
150
}
 
151
 
 
152
 
 
153
/**
 
154
 * eap_tls_ssl_init - Initialize shared TLS functionality
 
155
 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
 
156
 * @data: Data for TLS processing
 
157
 * @config: Pointer to the network configuration
 
158
 * Returns: 0 on success, -1 on failure
 
159
 *
 
160
 * This function is used to initialize shared TLS functionality for EAP-TLS,
 
161
 * EAP-PEAP, EAP-TTLS, and EAP-FAST.
 
162
 */
 
163
int eap_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
 
164
                     struct wpa_ssid *config)
 
165
{
 
166
        int ret = -1;
 
167
        struct tls_connection_params params;
 
168
 
 
169
        if (config == NULL)
 
170
                return -1;
 
171
 
 
172
        data->eap = sm;
 
173
        data->phase2 = sm->init_phase2;
 
174
        if (eap_tls_params_from_conf(sm, data, &params, config, data->phase2) <
 
175
            0)
 
176
                goto done;
 
177
 
 
178
        if (eap_tls_init_connection(sm, data, config, &params) < 0)
 
179
                goto done;
 
180
 
 
181
        data->tls_out_limit = config->fragment_size;
 
182
        if (data->phase2) {
 
183
                /* Limit the fragment size in the inner TLS authentication
 
184
                 * since the outer authentication with EAP-PEAP does not yet
 
185
                 * support fragmentation */
 
186
                if (data->tls_out_limit > 100)
 
187
                        data->tls_out_limit -= 100;
 
188
        }
 
189
 
 
190
        if (config->phase1 &&
 
191
            os_strstr(config->phase1, "include_tls_length=1")) {
 
192
                wpa_printf(MSG_DEBUG, "TLS: Include TLS Message Length in "
 
193
                           "unfragmented packets");
 
194
                data->include_tls_length = 1;
 
195
        }
 
196
 
 
197
        ret = 0;
 
198
 
 
199
done:
 
200
        return ret;
 
201
}
 
202
 
 
203
 
 
204
/**
 
205
 * eap_tls_ssl_deinit - Deinitialize shared TLS functionality
 
206
 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
 
207
 * @data: Data for TLS processing
 
208
 *
 
209
 * This function deinitializes shared TLS functionality that was initialized
 
210
 * with eap_tls_ssl_init().
 
211
 */
 
212
void eap_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
 
213
{
 
214
        tls_connection_deinit(sm->ssl_ctx, data->conn);
 
215
        os_free(data->tls_in);
 
216
        os_free(data->tls_out);
 
217
}
 
218
 
 
219
 
 
220
/**
 
221
 * eap_tls_derive_key - Derive a key based on TLS session data
 
222
 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
 
223
 * @data: Data for TLS processing
 
224
 * @label: Label string for deriving the keys, e.g., "client EAP encryption"
 
225
 * @len: Length of the key material to generate (usually 64 for MSK)
 
226
 * Returns: Pointer to allocated key on success or %NULL on failure
 
227
 *
 
228
 * This function uses TLS-PRF to generate pseudo-random data based on the TLS
 
229
 * session data (client/server random and master key). Each key type may use a
 
230
 * different label to bind the key usage into the generated material.
 
231
 *
 
232
 * The caller is responsible for freeing the returned buffer.
 
233
 */
 
234
u8 * eap_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
 
235
                        const char *label, size_t len)
 
236
{
 
237
        struct tls_keys keys;
 
238
        u8 *rnd = NULL, *out;
 
239
 
 
240
        out = os_malloc(len);
 
241
        if (out == NULL)
 
242
                return NULL;
 
243
 
 
244
        /* First, try to use TLS library function for PRF, if available. */
 
245
        if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) ==
 
246
            0)
 
247
                return out;
 
248
 
 
249
        /*
 
250
         * TLS library did not support key generation, so get the needed TLS
 
251
         * session parameters and use an internal implementation of TLS PRF to
 
252
         * derive the key.
 
253
         */
 
254
        if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
 
255
                goto fail;
 
256
 
 
257
        if (keys.client_random == NULL || keys.server_random == NULL ||
 
258
            keys.master_key == NULL)
 
259
                goto fail;
 
260
 
 
261
        rnd = os_malloc(keys.client_random_len + keys.server_random_len);
 
262
        if (rnd == NULL)
 
263
                goto fail;
 
264
        os_memcpy(rnd, keys.client_random, keys.client_random_len);
 
265
        os_memcpy(rnd + keys.client_random_len, keys.server_random,
 
266
                  keys.server_random_len);
 
267
 
 
268
        if (tls_prf(keys.master_key, keys.master_key_len,
 
269
                    label, rnd, keys.client_random_len +
 
270
                    keys.server_random_len, out, len))
 
271
                goto fail;
 
272
 
 
273
        os_free(rnd);
 
274
        return out;
 
275
 
 
276
fail:
 
277
        os_free(out);
 
278
        os_free(rnd);
 
279
        return NULL;
 
280
}
 
281
 
 
282
 
 
283
/**
 
284
 * eap_tls_data_reassemble - Reassemble TLS data
 
285
 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
 
286
 * @data: Data for TLS processing
 
287
 * @in_data: Next incoming TLS segment
 
288
 * @in_len: Length of in_data
 
289
 * @out_len: Variable for returning output data length
 
290
 * @need_more_input: Variable for returning whether more input data is needed
 
291
 * to reassemble this TLS packet
 
292
 * Returns: Pointer to output data, %NULL on error or when more data is needed
 
293
 * for the full message (in which case, *need_more_input is also set to 1).
 
294
 *
 
295
 * This function reassembles TLS fragments. Caller must not free the returned
 
296
 * data buffer since an internal pointer to it is maintained.
 
297
 */
 
298
const u8 * eap_tls_data_reassemble(
 
299
        struct eap_sm *sm, struct eap_ssl_data *data, const u8 *in_data,
 
300
        size_t in_len, size_t *out_len, int *need_more_input)
 
301
{
 
302
        u8 *buf;
 
303
 
 
304
        *need_more_input = 0;
 
305
 
 
306
        if (data->tls_in_left > in_len || data->tls_in) {
 
307
                if (data->tls_in_len + in_len == 0) {
 
308
                        os_free(data->tls_in);
 
309
                        data->tls_in = NULL;
 
310
                        data->tls_in_len = 0;
 
311
                        wpa_printf(MSG_WARNING, "SSL: Invalid reassembly "
 
312
                                   "state: tls_in_left=%lu tls_in_len=%lu "
 
313
                                   "in_len=%lu",
 
314
                                   (unsigned long) data->tls_in_left,
 
315
                                   (unsigned long) data->tls_in_len,
 
316
                                   (unsigned long) in_len);
 
317
                        return NULL;
 
318
                }
 
319
                if (data->tls_in_len + in_len > 65536) {
 
320
                        /* Limit length to avoid rogue servers from causing
 
321
                         * large memory allocations. */
 
322
                        os_free(data->tls_in);
 
323
                        data->tls_in = NULL;
 
324
                        data->tls_in_len = 0;
 
325
                        wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size"
 
326
                                   " over 64 kB)");
 
327
                        return NULL;
 
328
                }
 
329
                buf = os_realloc(data->tls_in, data->tls_in_len + in_len);
 
330
                if (buf == NULL) {
 
331
                        os_free(data->tls_in);
 
332
                        data->tls_in = NULL;
 
333
                        data->tls_in_len = 0;
 
334
                        wpa_printf(MSG_INFO, "SSL: Could not allocate memory "
 
335
                                   "for TLS data");
 
336
                        return NULL;
 
337
                }
 
338
                os_memcpy(buf + data->tls_in_len, in_data, in_len);
 
339
                data->tls_in = buf;
 
340
                data->tls_in_len += in_len;
 
341
                if (in_len > data->tls_in_left) {
 
342
                        wpa_printf(MSG_INFO, "SSL: more data than TLS message "
 
343
                                   "length indicated");
 
344
                        data->tls_in_left = 0;
 
345
                        return NULL;
 
346
                }
 
347
                data->tls_in_left -= in_len;
 
348
                if (data->tls_in_left > 0) {
 
349
                        wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input "
 
350
                                   "data", (unsigned long) data->tls_in_left);
 
351
                        *need_more_input = 1;
 
352
                        return NULL;
 
353
                }
 
354
        } else {
 
355
                data->tls_in_left = 0;
 
356
                data->tls_in = os_malloc(in_len ? in_len : 1);
 
357
                if (data->tls_in == NULL)
 
358
                        return NULL;
 
359
                os_memcpy(data->tls_in, in_data, in_len);
 
360
                data->tls_in_len = in_len;
 
361
        }
 
362
 
 
363
        *out_len = data->tls_in_len;
 
364
        return data->tls_in;
 
365
}
 
366
 
 
367
 
 
368
static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data,
 
369
                                 const u8 *in_data, size_t in_len,
 
370
                                 u8 **out_data, size_t *out_len)
 
371
{
 
372
        const u8 *msg;
 
373
        size_t msg_len;
 
374
        int need_more_input;
 
375
        u8 *appl_data;
 
376
        size_t appl_data_len;
 
377
 
 
378
        msg = eap_tls_data_reassemble(sm, data, in_data, in_len,
 
379
                                      &msg_len, &need_more_input);
 
380
        if (msg == NULL)
 
381
                return need_more_input ? 1 : -1;
 
382
 
 
383
        /* Full TLS message reassembled - continue handshake processing */
 
384
        if (data->tls_out) {
 
385
                /* This should not happen.. */
 
386
                wpa_printf(MSG_INFO, "SSL: eap_tls_process_helper - pending "
 
387
                           "tls_out data even though tls_out_len = 0");
 
388
                os_free(data->tls_out);
 
389
                WPA_ASSERT(data->tls_out == NULL);
 
390
        }
 
391
        appl_data = NULL;
 
392
        data->tls_out = tls_connection_handshake(sm->ssl_ctx, data->conn,
 
393
                                                 msg, msg_len,
 
394
                                                 &data->tls_out_len,
 
395
                                                 &appl_data, &appl_data_len);
 
396
 
 
397
        /* Clear reassembled input data (if the buffer was needed). */
 
398
        data->tls_in_left = data->tls_in_total = data->tls_in_len = 0;
 
399
        os_free(data->tls_in);
 
400
        data->tls_in = NULL;
 
401
 
 
402
        if (appl_data &&
 
403
            tls_connection_established(sm->ssl_ctx, data->conn) &&
 
404
            !tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
 
405
                wpa_hexdump_key(MSG_MSGDUMP, "SSL: Application data",
 
406
                                appl_data, appl_data_len);
 
407
                *out_data = appl_data;
 
408
                *out_len = appl_data_len;
 
409
                return 2;
 
410
        }
 
411
 
 
412
        os_free(appl_data);
 
413
 
 
414
        return 0;
 
415
}
 
416
 
 
417
 
 
418
static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type,
 
419
                                  int peap_version, u8 id, int ret,
 
420
                                  u8 **out_data, size_t *out_len)
 
421
{
 
422
        size_t len;
 
423
        u8 *pos, *flags;
 
424
        int more_fragments, length_included;
 
425
        
 
426
        wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total "
 
427
                   "%lu bytes)",
 
428
                   (unsigned long) data->tls_out_len - data->tls_out_pos,
 
429
                   (unsigned long) data->tls_out_len);
 
430
 
 
431
        len = data->tls_out_len - data->tls_out_pos;
 
432
        if (len > data->tls_out_limit) {
 
433
                more_fragments = 1;
 
434
                len = data->tls_out_limit;
 
435
                wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments "
 
436
                           "will follow", (unsigned long) len);
 
437
        } else
 
438
                more_fragments = 0;
 
439
 
 
440
        length_included = data->tls_out_pos == 0 &&
 
441
                (data->tls_out_len > data->tls_out_limit ||
 
442
                 data->include_tls_length);
 
443
 
 
444
        *out_data = (u8 *)
 
445
                eap_msg_alloc(EAP_VENDOR_IETF, eap_type, out_len,
 
446
                              1 + length_included * 4 + len, EAP_CODE_RESPONSE,
 
447
                              id, &pos);
 
448
        if (*out_data == NULL)
 
449
                return -1;
 
450
 
 
451
        flags = pos++;
 
452
        *flags = peap_version;
 
453
        if (more_fragments)
 
454
                *flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
 
455
        if (length_included) {
 
456
                *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
 
457
                WPA_PUT_BE32(pos, data->tls_out_len);
 
458
                pos += 4;
 
459
        }
 
460
 
 
461
        os_memcpy(pos, &data->tls_out[data->tls_out_pos], len);
 
462
        data->tls_out_pos += len;
 
463
 
 
464
        if (!more_fragments) {
 
465
                data->tls_out_len = 0;
 
466
                data->tls_out_pos = 0;
 
467
                os_free(data->tls_out);
 
468
                data->tls_out = NULL;
 
469
        }
 
470
 
 
471
        return ret;
 
472
}
 
473
 
 
474
 
 
475
/**
 
476
 * eap_tls_process_helper - Process TLS handshake message
 
477
 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
 
478
 * @data: Data for TLS processing
 
479
 * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
 
480
 * @peap_version: Version number for EAP-PEAP/TTLS
 
481
 * @id: EAP identifier for the response
 
482
 * @in_data: Message received from the server
 
483
 * @in_len: Length of in_data
 
484
 * @out_data: Buffer for returning a pointer to the response message
 
485
 * @out_len: Buffer for returning the length of the response message
 
486
 * Returns: 0 on success, 1 if more input data is needed, or -1 on failure
 
487
 *
 
488
 * This function can be used to process TLS handshake messages. It reassembles
 
489
 * the received fragments and uses a TLS library to process the messages. The
 
490
 * response data from the TLS library is fragmented to suitable output messages
 
491
 * that the caller can send out.
 
492
 *
 
493
 * out_data is used to return the response message if the return value of this
 
494
 * function is 0 or -1. In case of failure, the message is likely a TLS alarm
 
495
 * message. The caller is responsible for freeing the allocated buffer if
 
496
 * *out_data is not %NULL.
 
497
 */
 
498
int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
 
499
                           EapType eap_type, int peap_version,
 
500
                           u8 id, const u8 *in_data, size_t in_len,
 
501
                           u8 **out_data, size_t *out_len)
 
502
{
 
503
        int ret = 0;
 
504
 
 
505
        WPA_ASSERT(data->tls_out_len == 0 || in_len == 0);
 
506
        *out_len = 0;
 
507
        *out_data = NULL;
 
508
 
 
509
        if (data->tls_out_len == 0) {
 
510
                /* No more data to send out - expect to receive more data from
 
511
                 * the AS. */
 
512
                int res = eap_tls_process_input(sm, data, in_data, in_len,
 
513
                                                out_data, out_len);
 
514
                if (res)
 
515
                        return res;
 
516
        }
 
517
 
 
518
        if (data->tls_out == NULL) {
 
519
                data->tls_out_len = 0;
 
520
                return -1;
 
521
        }
 
522
 
 
523
        if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
 
524
                wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
 
525
                           "report error");
 
526
                ret = -1;
 
527
                /* TODO: clean pin if engine used? */
 
528
        }
 
529
 
 
530
        if (data->tls_out_len == 0) {
 
531
                /* TLS negotiation should now be complete since all other cases
 
532
                 * needing more data should have been caught above based on
 
533
                 * the TLS Message Length field. */
 
534
                wpa_printf(MSG_DEBUG, "SSL: No data to be sent out");
 
535
                os_free(data->tls_out);
 
536
                data->tls_out = NULL;
 
537
                return 1;
 
538
        }
 
539
 
 
540
        return eap_tls_process_output(data, eap_type, peap_version, id, ret,
 
541
                                      out_data, out_len);
 
542
}
 
543
 
 
544
 
 
545
/**
 
546
 * eap_tls_build_ack - Build a TLS ACK frames
 
547
 * @data: Data for TLS processing
 
548
 * @respDataLen: Buffer for returning the length of the response message
 
549
 * @id: EAP identifier for the response
 
550
 * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
 
551
 * @peap_version: Version number for EAP-PEAP/TTLS
 
552
 * Returns: Pointer to allocated ACK frames or %NULL on failure
 
553
 */
 
554
u8 * eap_tls_build_ack(struct eap_ssl_data *data, size_t *respDataLen, u8 id,
 
555
                       EapType eap_type, int peap_version)
 
556
{
 
557
        struct eap_hdr *resp;
 
558
        u8 *pos;
 
559
 
 
560
        resp = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, respDataLen,
 
561
                             1, EAP_CODE_RESPONSE, id, &pos);
 
562
        if (resp == NULL)
 
563
                return NULL;
 
564
        wpa_printf(MSG_DEBUG, "SSL: Building ACK");
 
565
        *pos = peap_version; /* Flags */
 
566
        return (u8 *) resp;
 
567
}
 
568
 
 
569
 
 
570
/**
 
571
 * eap_tls_reauth_init - Re-initialize shared TLS for session resumption
 
572
 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
 
573
 * @data: Data for TLS processing
 
574
 * Returns: 0 on success, -1 on failure
 
575
 */
 
576
int eap_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data)
 
577
{
 
578
        os_free(data->tls_in);
 
579
        data->tls_in = NULL;
 
580
        data->tls_in_len = data->tls_in_left = data->tls_in_total = 0;
 
581
        os_free(data->tls_out);
 
582
        data->tls_out = NULL;
 
583
        data->tls_out_len = data->tls_out_pos = 0;
 
584
 
 
585
        return tls_connection_shutdown(sm->ssl_ctx, data->conn);
 
586
}
 
587
 
 
588
 
 
589
/**
 
590
 * eap_tls_status - Get TLS status
 
591
 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
 
592
 * @data: Data for TLS processing
 
593
 * @buf: Buffer for status information
 
594
 * @buflen: Maximum buffer length
 
595
 * @verbose: Whether to include verbose status information
 
596
 * Returns: Number of bytes written to buf.
 
597
 */
 
598
int eap_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, char *buf,
 
599
                   size_t buflen, int verbose)
 
600
{
 
601
        char name[128];
 
602
        int len = 0, ret;
 
603
 
 
604
        if (tls_get_cipher(sm->ssl_ctx, data->conn, name, sizeof(name)) == 0) {
 
605
                ret = os_snprintf(buf + len, buflen - len,
 
606
                                  "EAP TLS cipher=%s\n", name);
 
607
                if (ret < 0 || (size_t) ret >= buflen - len)
 
608
                        return len;
 
609
                len += ret;
 
610
        }
 
611
 
 
612
        return len;
 
613
}
 
614
 
 
615
 
 
616
/**
 
617
 * eap_tls_process_init - Initial validation and processing of EAP requests
 
618
 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
 
619
 * @data: Data for TLS processing
 
620
 * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
 
621
 * @ret: Return values from EAP request validation and processing
 
622
 * @reqData: EAP request to be processed (eapReqData)
 
623
 * @reqDataLen: Length of the EAP request
 
624
 * @len: Buffer for returning length of the remaining payload
 
625
 * @flags: Buffer for returning TLS flags
 
626
 * Returns: Buffer to payload after TLS flags and length or %NULL on failure
 
627
 */
 
628
const u8 * eap_tls_process_init(struct eap_sm *sm, struct eap_ssl_data *data,
 
629
                                EapType eap_type, struct eap_method_ret *ret,
 
630
                                const u8 *reqData, size_t reqDataLen,
 
631
                                size_t *len, u8 *flags)
 
632
{
 
633
        const u8 *pos;
 
634
        size_t left;
 
635
        unsigned int tls_msg_len;
 
636
 
 
637
        if (tls_get_errors(sm->ssl_ctx)) {
 
638
                wpa_printf(MSG_INFO, "SSL: TLS errors detected");
 
639
                ret->ignore = TRUE;
 
640
                return NULL;
 
641
        }
 
642
 
 
643
        pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData, reqDataLen,
 
644
                               &left);
 
645
        if (pos == NULL) {
 
646
                ret->ignore = TRUE;
 
647
                return NULL;
 
648
        }
 
649
        *flags = *pos++;
 
650
        left--;
 
651
        wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - "
 
652
                   "Flags 0x%02x", (unsigned long) reqDataLen, *flags);
 
653
        if (*flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
 
654
                if (left < 4) {
 
655
                        wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
 
656
                                   "length");
 
657
                        ret->ignore = TRUE;
 
658
                        return NULL;
 
659
                }
 
660
                tls_msg_len = WPA_GET_BE32(pos);
 
661
                wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d",
 
662
                           tls_msg_len);
 
663
                if (data->tls_in_left == 0) {
 
664
                        data->tls_in_total = tls_msg_len;
 
665
                        data->tls_in_left = tls_msg_len;
 
666
                        os_free(data->tls_in);
 
667
                        data->tls_in = NULL;
 
668
                        data->tls_in_len = 0;
 
669
                }
 
670
                pos += 4;
 
671
                left -= 4;
 
672
        }
 
673
 
 
674
        ret->ignore = FALSE;
 
675
        ret->methodState = METHOD_MAY_CONT;
 
676
        ret->decision = DECISION_FAIL;
 
677
        ret->allowNotifications = TRUE;
 
678
 
 
679
        *len = (size_t) left;
 
680
        return pos;
 
681
}