~ubuntu-branches/ubuntu/precise/wpasupplicant/precise-security

« back to all changes in this revision

Viewing changes to src/radius/radius.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
1
/*
2
 
 * hostapd / RADIUS message processing
3
 
 * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
 
2
 * RADIUS message processing
 
3
 * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
4
4
 *
5
5
 * This program is free software; you can redistribute it and/or modify
6
6
 * it under the terms of the GNU General Public License version 2 as
12
12
 * See README and COPYING for more details.
13
13
 */
14
14
 
15
 
#include "includes.h"
 
15
#include "utils/includes.h"
16
16
 
17
 
#include "common.h"
 
17
#include "utils/common.h"
 
18
#include "utils/wpabuf.h"
 
19
#include "crypto/md5.h"
 
20
#include "crypto/crypto.h"
18
21
#include "radius.h"
19
 
#include "md5.h"
20
 
#include "crypto.h"
 
22
 
 
23
 
 
24
/**
 
25
 * struct radius_msg - RADIUS message structure for new and parsed messages
 
26
 */
 
27
struct radius_msg {
 
28
        /**
 
29
         * buf - Allocated buffer for RADIUS message
 
30
         */
 
31
        struct wpabuf *buf;
 
32
 
 
33
        /**
 
34
         * hdr - Pointer to the RADIUS header in buf
 
35
         */
 
36
        struct radius_hdr *hdr;
 
37
 
 
38
        /**
 
39
         * attr_pos - Array of indexes to attributes
 
40
         *
 
41
         * The values are number of bytes from buf to the beginning of
 
42
         * struct radius_attr_hdr.
 
43
         */
 
44
        size_t *attr_pos;
 
45
 
 
46
        /**
 
47
         * attr_size - Total size of the attribute pointer array
 
48
         */
 
49
        size_t attr_size;
 
50
 
 
51
        /**
 
52
         * attr_used - Total number of attributes in the array
 
53
         */
 
54
        size_t attr_used;
 
55
};
 
56
 
 
57
 
 
58
struct radius_hdr * radius_msg_get_hdr(struct radius_msg *msg)
 
59
{
 
60
        return msg->hdr;
 
61
}
 
62
 
 
63
 
 
64
struct wpabuf * radius_msg_get_buf(struct radius_msg *msg)
 
65
{
 
66
        return msg->buf;
 
67
}
21
68
 
22
69
 
23
70
static struct radius_attr_hdr *
24
71
radius_get_attr_hdr(struct radius_msg *msg, int idx)
25
72
{
26
 
        return (struct radius_attr_hdr *) (msg->buf + msg->attr_pos[idx]);
27
 
}
28
 
 
29
 
 
30
 
struct radius_msg *radius_msg_new(u8 code, u8 identifier)
31
 
{
32
 
        struct radius_msg *msg;
33
 
 
34
 
        msg = os_malloc(sizeof(*msg));
35
 
        if (msg == NULL)
36
 
                return NULL;
37
 
 
38
 
        if (radius_msg_initialize(msg, RADIUS_DEFAULT_MSG_SIZE)) {
39
 
                os_free(msg);
40
 
                return NULL;
41
 
        }
42
 
 
43
 
        radius_msg_set_hdr(msg, code, identifier);
44
 
 
45
 
        return msg;
46
 
}
47
 
 
48
 
 
49
 
int radius_msg_initialize(struct radius_msg *msg, size_t init_len)
50
 
{
51
 
        if (msg == NULL || init_len < sizeof(struct radius_hdr))
52
 
                return -1;
53
 
 
54
 
        os_memset(msg, 0, sizeof(*msg));
55
 
        msg->buf = os_zalloc(init_len);
56
 
        if (msg->buf == NULL)
57
 
                return -1;
58
 
 
59
 
        msg->buf_size = init_len;
60
 
        msg->hdr = (struct radius_hdr *) msg->buf;
61
 
        msg->buf_used = sizeof(*msg->hdr);
62
 
 
 
73
        return (struct radius_attr_hdr *)
 
74
                (wpabuf_mhead_u8(msg->buf) + msg->attr_pos[idx]);
 
75
}
 
76
 
 
77
 
 
78
static void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier)
 
79
{
 
80
        msg->hdr->code = code;
 
81
        msg->hdr->identifier = identifier;
 
82
}
 
83
 
 
84
 
 
85
static int radius_msg_initialize(struct radius_msg *msg)
 
86
{
63
87
        msg->attr_pos =
64
88
                os_zalloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attr_pos));
65
 
        if (msg->attr_pos == NULL) {
66
 
                os_free(msg->buf);
67
 
                msg->buf = NULL;
68
 
                msg->hdr = NULL;
 
89
        if (msg->attr_pos == NULL)
69
90
                return -1;
70
 
        }
71
91
 
72
92
        msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT;
73
93
        msg->attr_used = 0;
76
96
}
77
97
 
78
98
 
79
 
void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier)
 
99
/**
 
100
 * radius_msg_new - Create a new RADIUS message
 
101
 * @code: Code for RADIUS header
 
102
 * @identifier: Identifier for RADIUS header
 
103
 * Returns: Context for RADIUS message or %NULL on failure
 
104
 *
 
105
 * The caller is responsible for freeing the returned data with
 
106
 * radius_msg_free().
 
107
 */
 
108
struct radius_msg * radius_msg_new(u8 code, u8 identifier)
80
109
{
81
 
        msg->hdr->code = code;
82
 
        msg->hdr->identifier = identifier;
 
110
        struct radius_msg *msg;
 
111
 
 
112
        msg = os_zalloc(sizeof(*msg));
 
113
        if (msg == NULL)
 
114
                return NULL;
 
115
 
 
116
        msg->buf = wpabuf_alloc(RADIUS_DEFAULT_MSG_SIZE);
 
117
        if (msg->buf == NULL || radius_msg_initialize(msg)) {
 
118
                radius_msg_free(msg);
 
119
                return NULL;
 
120
        }
 
121
        msg->hdr = wpabuf_put(msg->buf, sizeof(struct radius_hdr));
 
122
 
 
123
        radius_msg_set_hdr(msg, code, identifier);
 
124
 
 
125
        return msg;
83
126
}
84
127
 
85
128
 
 
129
/**
 
130
 * radius_msg_free - Free a RADIUS message
 
131
 * @msg: RADIUS message from radius_msg_new() or radius_msg_parse()
 
132
 */
86
133
void radius_msg_free(struct radius_msg *msg)
87
134
{
88
 
        os_free(msg->buf);
89
 
        msg->buf = NULL;
90
 
        msg->hdr = NULL;
91
 
        msg->buf_size = msg->buf_used = 0;
 
135
        if (msg == NULL)
 
136
                return;
92
137
 
 
138
        wpabuf_free(msg->buf);
93
139
        os_free(msg->attr_pos);
94
 
        msg->attr_pos = NULL;
95
 
        msg->attr_size = msg->attr_used = 0;
 
140
        os_free(msg);
96
141
}
97
142
 
98
143
 
305
350
                                           RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
306
351
                                           auth, MD5_MAC_LEN);
307
352
                if (attr == NULL) {
308
 
                        printf("WARNING: Could not add "
309
 
                               "Message-Authenticator\n");
 
353
                        wpa_printf(MSG_WARNING, "RADIUS: Could not add "
 
354
                                   "Message-Authenticator");
310
355
                        return -1;
311
356
                }
312
 
                msg->hdr->length = htons(msg->buf_used);
313
 
                hmac_md5(secret, secret_len, msg->buf, msg->buf_used,
314
 
                         (u8 *) (attr + 1));
 
357
                msg->hdr->length = htons(wpabuf_len(msg->buf));
 
358
                hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
 
359
                         wpabuf_len(msg->buf), (u8 *) (attr + 1));
315
360
        } else
316
 
                msg->hdr->length = htons(msg->buf_used);
 
361
                msg->hdr->length = htons(wpabuf_len(msg->buf));
317
362
 
318
 
        if (msg->buf_used > 0xffff) {
319
 
                printf("WARNING: too long RADIUS message (%lu)\n",
320
 
                       (unsigned long) msg->buf_used);
 
363
        if (wpabuf_len(msg->buf) > 0xffff) {
 
364
                wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
 
365
                           (unsigned long) wpabuf_len(msg->buf));
321
366
                return -1;
322
367
        }
323
368
        return 0;
339
384
                printf("WARNING: Could not add Message-Authenticator\n");
340
385
                return -1;
341
386
        }
342
 
        msg->hdr->length = htons(msg->buf_used);
 
387
        msg->hdr->length = htons(wpabuf_len(msg->buf));
343
388
        os_memcpy(msg->hdr->authenticator, req_authenticator,
344
389
                  sizeof(msg->hdr->authenticator));
345
 
        hmac_md5(secret, secret_len, msg->buf, msg->buf_used,
346
 
                 (u8 *) (attr + 1));
 
390
        hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
 
391
                 wpabuf_len(msg->buf), (u8 *) (attr + 1));
347
392
 
348
393
        /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
349
394
        addr[0] = (u8 *) msg->hdr;
350
395
        len[0] = 1 + 1 + 2;
351
396
        addr[1] = req_authenticator;
352
397
        len[1] = MD5_MAC_LEN;
353
 
        addr[2] = (u8 *) (msg->hdr + 1);
354
 
        len[2] = msg->buf_used - sizeof(*msg->hdr);
 
398
        addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr);
 
399
        len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
355
400
        addr[3] = secret;
356
401
        len[3] = secret_len;
357
402
        md5_vector(4, addr, len, msg->hdr->authenticator);
358
403
 
359
 
        if (msg->buf_used > 0xffff) {
360
 
                printf("WARNING: too long RADIUS message (%lu)\n",
361
 
                       (unsigned long) msg->buf_used);
 
404
        if (wpabuf_len(msg->buf) > 0xffff) {
 
405
                wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
 
406
                           (unsigned long) wpabuf_len(msg->buf));
362
407
                return -1;
363
408
        }
364
409
        return 0;
371
416
        const u8 *addr[2];
372
417
        size_t len[2];
373
418
 
374
 
        msg->hdr->length = htons(msg->buf_used);
 
419
        msg->hdr->length = htons(wpabuf_len(msg->buf));
375
420
        os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN);
376
 
        addr[0] = msg->buf;
377
 
        len[0] = msg->buf_used;
 
421
        addr[0] = wpabuf_head(msg->buf);
 
422
        len[0] = wpabuf_len(msg->buf);
378
423
        addr[1] = secret;
379
424
        len[1] = secret_len;
380
425
        md5_vector(2, addr, len, msg->hdr->authenticator);
381
426
 
382
 
        if (msg->buf_used > 0xffff) {
383
 
                printf("WARNING: too long RADIUS messages (%lu)\n",
384
 
                       (unsigned long) msg->buf_used);
 
427
        if (wpabuf_len(msg->buf) > 0xffff) {
 
428
                wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)",
 
429
                           (unsigned long) wpabuf_len(msg->buf));
385
430
        }
386
431
}
387
432
 
402
447
                msg->attr_size = nlen;
403
448
        }
404
449
 
405
 
        msg->attr_pos[msg->attr_used++] = (unsigned char *) attr - msg->buf;
 
450
        msg->attr_pos[msg->attr_used++] =
 
451
                (unsigned char *) attr - wpabuf_head_u8(msg->buf);
406
452
 
407
453
        return 0;
408
454
}
420
466
                return NULL;
421
467
        }
422
468
 
423
 
        buf_needed = msg->buf_used + sizeof(*attr) + data_len;
 
469
        buf_needed = sizeof(*attr) + data_len;
424
470
 
425
 
        if (msg->buf_size < buf_needed) {
 
471
        if (wpabuf_tailroom(msg->buf) < buf_needed) {
426
472
                /* allocate more space for message buffer */
427
 
                unsigned char *nbuf;
428
 
                size_t nlen = msg->buf_size;
429
 
 
430
 
                while (nlen < buf_needed)
431
 
                        nlen *= 2;
432
 
                nbuf = os_realloc(msg->buf, nlen);
433
 
                if (nbuf == NULL)
 
473
                if (wpabuf_resize(&msg->buf, buf_needed) < 0)
434
474
                        return NULL;
435
 
                msg->buf = nbuf;
436
 
                msg->hdr = (struct radius_hdr *) msg->buf;
437
 
                os_memset(msg->buf + msg->buf_size, 0, nlen - msg->buf_size);
438
 
                msg->buf_size = nlen;
 
475
                msg->hdr = wpabuf_mhead(msg->buf);
439
476
        }
440
477
 
441
 
        attr = (struct radius_attr_hdr *) (msg->buf + msg->buf_used);
 
478
        attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr));
442
479
        attr->type = type;
443
480
        attr->length = sizeof(*attr) + data_len;
444
 
        if (data_len > 0)
445
 
                os_memcpy(attr + 1, data, data_len);
446
 
 
447
 
        msg->buf_used += sizeof(*attr) + data_len;
 
481
        wpabuf_put_data(msg->buf, data, data_len);
448
482
 
449
483
        if (radius_msg_add_attr_to_array(msg, attr))
450
484
                return NULL;
453
487
}
454
488
 
455
489
 
456
 
struct radius_msg *radius_msg_parse(const u8 *data, size_t len)
 
490
/**
 
491
 * radius_msg_parse - Parse a RADIUS message
 
492
 * @data: RADIUS message to be parsed
 
493
 * @len: Length of data buffer in octets
 
494
 * Returns: Parsed RADIUS message or %NULL on failure
 
495
 *
 
496
 * This parses a RADIUS message and makes a copy of its data. The caller is
 
497
 * responsible for freeing the returned data with radius_msg_free().
 
498
 */
 
499
struct radius_msg * radius_msg_parse(const u8 *data, size_t len)
457
500
{
458
501
        struct radius_msg *msg;
459
502
        struct radius_hdr *hdr;
468
511
 
469
512
        msg_len = ntohs(hdr->length);
470
513
        if (msg_len < sizeof(*hdr) || msg_len > len) {
471
 
                printf("Invalid RADIUS message length\n");
 
514
                wpa_printf(MSG_INFO, "RADIUS: Invalid message length");
472
515
                return NULL;
473
516
        }
474
517
 
475
518
        if (msg_len < len) {
476
 
                printf("Ignored %lu extra bytes after RADIUS message\n",
477
 
                       (unsigned long) len - msg_len);
 
519
                wpa_printf(MSG_DEBUG, "RADIUS: Ignored %lu extra bytes after "
 
520
                           "RADIUS message", (unsigned long) len - msg_len);
478
521
        }
479
522
 
480
 
        msg = os_malloc(sizeof(*msg));
 
523
        msg = os_zalloc(sizeof(*msg));
481
524
        if (msg == NULL)
482
525
                return NULL;
483
526
 
484
 
        if (radius_msg_initialize(msg, msg_len)) {
485
 
                os_free(msg);
 
527
        msg->buf = wpabuf_alloc_copy(data, msg_len);
 
528
        if (msg->buf == NULL || radius_msg_initialize(msg)) {
 
529
                radius_msg_free(msg);
486
530
                return NULL;
487
531
        }
488
 
 
489
 
        os_memcpy(msg->buf, data, msg_len);
490
 
        msg->buf_size = msg->buf_used = msg_len;
 
532
        msg->hdr = wpabuf_mhead(msg->buf);
491
533
 
492
534
        /* parse attributes */
493
 
        pos = (unsigned char *) (msg->hdr + 1);
494
 
        end = msg->buf + msg->buf_used;
 
535
        pos = wpabuf_mhead_u8(msg->buf) + sizeof(struct radius_hdr);
 
536
        end = wpabuf_mhead_u8(msg->buf) + wpabuf_len(msg->buf);
495
537
        while (pos < end) {
496
538
                if ((size_t) (end - pos) < sizeof(*attr))
497
539
                        goto fail;
513
555
 
514
556
 fail:
515
557
        radius_msg_free(msg);
516
 
        os_free(msg);
517
558
        return NULL;
518
559
}
519
560
 
615
656
                os_memcpy(msg->hdr->authenticator, req_auth,
616
657
                          sizeof(msg->hdr->authenticator));
617
658
        }
618
 
        hmac_md5(secret, secret_len, msg->buf, msg->buf_used, auth);
 
659
        hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
 
660
                 wpabuf_len(msg->buf), auth);
619
661
        os_memcpy(attr + 1, orig, MD5_MAC_LEN);
620
662
        if (req_auth) {
621
663
                os_memcpy(msg->hdr->authenticator, orig_authenticator,
654
696
        len[0] = 1 + 1 + 2;
655
697
        addr[1] = sent_msg->hdr->authenticator;
656
698
        len[1] = MD5_MAC_LEN;
657
 
        addr[2] = (u8 *) (msg->hdr + 1);
658
 
        len[2] = msg->buf_used - sizeof(*msg->hdr);
 
699
        addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr);
 
700
        len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
659
701
        addr[3] = secret;
660
702
        len[3] = secret_len;
661
703
        md5_vector(4, addr, len, hash);
1232
1274
 
1233
1275
        return -1;
1234
1276
}
 
1277
 
 
1278
 
 
1279
void radius_free_class(struct radius_class_data *c)
 
1280
{
 
1281
        size_t i;
 
1282
        if (c == NULL)
 
1283
                return;
 
1284
        for (i = 0; i < c->count; i++)
 
1285
                os_free(c->attr[i].data);
 
1286
        os_free(c->attr);
 
1287
        c->attr = NULL;
 
1288
        c->count = 0;
 
1289
}
 
1290
 
 
1291
 
 
1292
int radius_copy_class(struct radius_class_data *dst,
 
1293
                      const struct radius_class_data *src)
 
1294
{
 
1295
        size_t i;
 
1296
 
 
1297
        if (src->attr == NULL)
 
1298
                return 0;
 
1299
 
 
1300
        dst->attr = os_zalloc(src->count * sizeof(struct radius_attr_data));
 
1301
        if (dst->attr == NULL)
 
1302
                return -1;
 
1303
 
 
1304
        dst->count = 0;
 
1305
 
 
1306
        for (i = 0; i < src->count; i++) {
 
1307
                dst->attr[i].data = os_malloc(src->attr[i].len);
 
1308
                if (dst->attr[i].data == NULL)
 
1309
                        break;
 
1310
                dst->count++;
 
1311
                os_memcpy(dst->attr[i].data, src->attr[i].data,
 
1312
                          src->attr[i].len);
 
1313
                dst->attr[i].len = src->attr[i].len;
 
1314
        }
 
1315
 
 
1316
        return 0;
 
1317
}