~ubuntu-branches/ubuntu/vivid/wpasupplicant/vivid

« back to all changes in this revision

Viewing changes to eap_gpsk_common.c

  • Committer: Bazaar Package Importer
  • Author(s): Kel Modderman
  • Date: 2008-03-12 20:03:04 UTC
  • mfrom: (1.1.10 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20080312200304-4331y9wj46pdd34z
Tags: 0.6.3-1
* New upstream release.
* Drop patches applied upstream:
  - debian/patches/30_wpa_gui_qt4_eventhistoryui_rework.patch
  - debian/patches/31_wpa_gui_qt4_eventhistory_always_scrollbar.patch
  - debian/patches/32_wpa_gui_qt4_eventhistory_scroll_with_events.patch
  - debian/patches/40_dbus_ssid_data.patch
* Tidy up the clean target of debian/rules. Now that the madwifi headers are
  handled differently we no longer need to do any cleanup.
* Fix formatting error in debian/ifupdown/wpa_action.8 to make lintian
  quieter.
* Add patch to fix formatting errors in manpages build from sgml source. Use
  <emphasis> tags to hightlight keywords instead of surrounding them in
  strong quotes.
  - debian/patches/41_manpage_format_fixes.patch
* wpasupplicant binary package no longer suggests pcscd, guessnet, iproute
  or wireless-tools, nor does it recommend dhcp3-client. These are not
  needed.
* Add debian/patches/10_silence_siocsiwauth_icotl_failure.patch to disable
  ioctl failure messages that occur under normal conditions.
* Cherry pick two upstream git commits concerning the dbus interface:
  - debian/patches/11_avoid_dbus_version_namespace.patch
  - debian/patches/12_fix_potential_use_after_free.patch
* Add debian/patches/42_manpage_explain_available_drivers.patch to explain
  that not all of the driver backends are available in the provided
  wpa_supplicant binary, and that the canonical list of supported driver
  backends can be retrieved from the wpa_supplicant -h (help) output.
  (Closes: #466910)
* Add debian/patches/20_wpa_gui_qt4_disable_link_prl.patch to remove
  link_prl CONFIG compile flag added by qmake-qt4 >= 4.3.4-2 to avoid excess
  linking.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * EAP server/peer: EAP-GPSK shared routines
3
 
 * Copyright (c) 2006-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_defs.h"
19
 
#include "aes_wrap.h"
20
 
#include "crypto.h"
21
 
#include "sha1.h"
22
 
#include "sha256.h"
23
 
#include "eap_gpsk_common.h"
24
 
 
25
 
 
26
 
/**
27
 
 * eap_gpsk_supported_ciphersuite - Check whether ciphersuite is supported
28
 
 * @vendor: CSuite/Vendor
29
 
 * @specifier: CSuite/Specifier
30
 
 * Returns: 1 if ciphersuite is support, or 0 if not
31
 
 */
32
 
int eap_gpsk_supported_ciphersuite(int vendor, int specifier)
33
 
{
34
 
        if (vendor == EAP_GPSK_VENDOR_IETF &&
35
 
            specifier == EAP_GPSK_CIPHER_AES)
36
 
                return 1;
37
 
#ifdef EAP_GPSK_SHA256
38
 
        if (vendor == EAP_GPSK_VENDOR_IETF &&
39
 
            specifier == EAP_GPSK_CIPHER_SHA256)
40
 
                return 1;
41
 
#endif /* EAP_GPSK_SHA256 */
42
 
        return 0;
43
 
}
44
 
 
45
 
 
46
 
static int eap_gpsk_gkdf(const u8 *psk /* Y */, size_t psk_len,
47
 
                         const u8 *data /* Z */, size_t data_len,
48
 
                         u8 *buf, size_t len /* X */)
49
 
{
50
 
        u8 *opos;
51
 
        size_t i, n, hashlen, left, clen;
52
 
        u8 ibuf[2], hash[SHA1_MAC_LEN];
53
 
        const u8 *addr[3];
54
 
        size_t vlen[3];
55
 
 
56
 
        hashlen = SHA1_MAC_LEN;
57
 
        /* M_i = Hash-Function (i || Y || Z); */
58
 
        addr[0] = ibuf;
59
 
        vlen[0] = sizeof(ibuf);
60
 
        addr[1] = psk;
61
 
        vlen[1] = psk_len;
62
 
        addr[2] = data;
63
 
        vlen[2] = data_len;
64
 
 
65
 
        opos = buf;
66
 
        left = len;
67
 
        n = (len + hashlen - 1) / hashlen;
68
 
        for (i = 1; i <= n; i++) {
69
 
                WPA_PUT_BE16(ibuf, i);
70
 
                sha1_vector(3, addr, vlen, hash);
71
 
                clen = left > hashlen ? hashlen : left;
72
 
                os_memcpy(opos, hash, clen);
73
 
                opos += clen;
74
 
                left -= clen;
75
 
        }
76
 
 
77
 
        return 0;
78
 
}
79
 
 
80
 
 
81
 
static int eap_gpsk_derive_keys_aes(const u8 *psk, size_t psk_len,
82
 
                                    const u8 *seed, size_t seed_len,
83
 
                                    u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len,
84
 
                                    u8 *pk, size_t *pk_len)
85
 
{
86
 
#define EAP_GPSK_SK_LEN_AES 16
87
 
#define EAP_GPSK_PK_LEN_AES 16
88
 
        u8 zero_string[1], mk[32], *pos, *data;
89
 
        u8 kdf_out[EAP_MSK_LEN + EAP_EMSK_LEN + EAP_GPSK_SK_LEN_AES +
90
 
                   EAP_GPSK_PK_LEN_AES];
91
 
        size_t data_len;
92
 
 
93
 
        /*
94
 
         * inputString = RAND_Client || ID_Client || RAND_Server || ID_Server
95
 
         *            (= seed)
96
 
         * KS = 16, PL = psk_len, CSuite_Sel = 0x000000 0x000001
97
 
         * MK = GKDF-32 (0x00, PL || PSK || CSuite_Sel || inputString)
98
 
         * MSK = GKDF-160 (MK, inputString)[0..63]
99
 
         * EMSK = GKDF-160 (MK, inputString)[64..127]
100
 
         * SK = GKDF-160 (MK, inputString)[128..143]
101
 
         * PK = GKDF-160 (MK, inputString)[144..159]
102
 
         * MID = GKDF-16(0x00, "Method ID" || EAP_Method_Type || CSuite_Sel ||
103
 
         *               inputString)
104
 
         * Hash-Function = SHA-1 (see [RFC3174])
105
 
         * hashlen = 20 octets (160 bits)
106
 
         */
107
 
 
108
 
        os_memset(zero_string, 0, sizeof(zero_string));
109
 
 
110
 
        data_len = 2 + psk_len + 6 + seed_len;
111
 
        data = os_malloc(data_len);
112
 
        if (data == NULL)
113
 
                return -1;
114
 
        pos = data;
115
 
        WPA_PUT_BE16(pos, psk_len);
116
 
        pos += 2;
117
 
        os_memcpy(pos, psk, psk_len);
118
 
        pos += psk_len;
119
 
        WPA_PUT_BE24(pos, 0); /* CSuite/Vendor = IETF */
120
 
        pos += 3;
121
 
        WPA_PUT_BE24(pos, EAP_GPSK_CIPHER_AES); /* CSuite/Specifier */
122
 
        pos += 3;
123
 
        os_memcpy(pos, seed, seed_len); /* inputString */
124
 
        wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: Data to MK derivation (AES)",
125
 
                        data, data_len);
126
 
 
127
 
        if (eap_gpsk_gkdf(zero_string, sizeof(zero_string), data, data_len,
128
 
                          mk, sizeof(mk)) < 0) {
129
 
                os_free(data);
130
 
                return -1;
131
 
        }
132
 
        os_free(data);
133
 
        wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MK", mk, sizeof(mk));
134
 
 
135
 
        if (eap_gpsk_gkdf(mk, sizeof(mk), seed, seed_len,
136
 
                          kdf_out, sizeof(kdf_out)) < 0)
137
 
                return -1;
138
 
 
139
 
        pos = kdf_out;
140
 
        wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MSK", pos, EAP_MSK_LEN);
141
 
        os_memcpy(msk, pos, EAP_MSK_LEN);
142
 
        pos += EAP_MSK_LEN;
143
 
 
144
 
        wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: EMSK", pos, EAP_EMSK_LEN);
145
 
        os_memcpy(emsk, pos, EAP_EMSK_LEN);
146
 
        pos += EAP_EMSK_LEN;
147
 
 
148
 
        wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: SK", pos, EAP_GPSK_SK_LEN_AES);
149
 
        os_memcpy(sk, pos, EAP_GPSK_SK_LEN_AES);
150
 
        *sk_len = EAP_GPSK_SK_LEN_AES;
151
 
        pos += EAP_GPSK_SK_LEN_AES;
152
 
 
153
 
        wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PK", pos, EAP_GPSK_PK_LEN_AES);
154
 
        os_memcpy(pk, pos, EAP_GPSK_PK_LEN_AES);
155
 
        *pk_len = EAP_GPSK_PK_LEN_AES;
156
 
 
157
 
        return 0;
158
 
}
159
 
 
160
 
 
161
 
#ifdef EAP_GPSK_SHA256
162
 
static int eap_gpsk_gkdf_sha256(const u8 *psk /* Y */, size_t psk_len,
163
 
                                const u8 *data /* Z */, size_t data_len,
164
 
                                u8 *buf, size_t len /* X */)
165
 
{
166
 
        u8 *opos;
167
 
        size_t i, n, hashlen, left, clen;
168
 
        u8 ibuf[2], hash[SHA256_MAC_LEN];
169
 
        const u8 *addr[3];
170
 
        size_t vlen[3];
171
 
 
172
 
        hashlen = SHA256_MAC_LEN;
173
 
        /* M_i = Hash-Function (i || Y || Z); */
174
 
        addr[0] = ibuf;
175
 
        vlen[0] = sizeof(ibuf);
176
 
        addr[1] = psk;
177
 
        vlen[1] = psk_len;
178
 
        addr[2] = data;
179
 
        vlen[2] = data_len;
180
 
 
181
 
        opos = buf;
182
 
        left = len;
183
 
        n = (len + hashlen - 1) / hashlen;
184
 
        for (i = 1; i <= n; i++) {
185
 
                WPA_PUT_BE16(ibuf, i);
186
 
                sha256_vector(3, addr, vlen, hash);
187
 
                clen = left > hashlen ? hashlen : left;
188
 
                os_memcpy(opos, hash, clen);
189
 
                opos += clen;
190
 
                left -= clen;
191
 
        }
192
 
 
193
 
        return 0;
194
 
}
195
 
 
196
 
 
197
 
static int eap_gpsk_derive_keys_sha256(const u8 *psk, size_t psk_len,
198
 
                                       const u8 *seed, size_t seed_len,
199
 
                                       u8 *msk, u8 *emsk,
200
 
                                       u8 *sk, size_t *sk_len,
201
 
                                       u8 *pk, size_t *pk_len)
202
 
{
203
 
#define EAP_GPSK_SK_LEN_SHA256 SHA256_MAC_LEN
204
 
#define EAP_GPSK_PK_LEN_SHA256 SHA256_MAC_LEN
205
 
        u8 mk[SHA256_MAC_LEN], zero_string[1], *pos, *data;
206
 
        u8 kdf_out[EAP_MSK_LEN + EAP_EMSK_LEN + EAP_GPSK_SK_LEN_SHA256 +
207
 
                   EAP_GPSK_PK_LEN_SHA256];
208
 
        size_t data_len;
209
 
 
210
 
        /*
211
 
         * inputString = RAND_Client || ID_Client || RAND_Server || ID_Server
212
 
         *            (= seed)
213
 
         * KS = 32, PL = psk_len, CSuite_Sel = 0x000000 0x000002
214
 
         * MK = GKDF-32 (0x00, PL || PSK || CSuite_Sel || inputString)
215
 
         * MSK = GKDF-192 (MK, inputString)[0..63]
216
 
         * EMSK = GKDF-192 (MK, inputString)[64..127]
217
 
         * SK = GKDF-192 (MK, inputString)[128..159]
218
 
         * PK = GKDF-192 (MK, inputString)[160..191]
219
 
         * MID = GKDF-16(0x00, "Method ID" || EAP_Method_Type || CSuite_Sel ||
220
 
         *               inputString)
221
 
         * Hash-Function = SHA256 (see [RFC4634])
222
 
         * hashlen = 32 octets (256 bits)
223
 
         */
224
 
 
225
 
        os_memset(zero_string, 0, sizeof(zero_string));
226
 
 
227
 
        data_len = 2 + psk_len + 6 + seed_len;
228
 
        data = os_malloc(data_len);
229
 
        if (data == NULL)
230
 
                return -1;
231
 
        pos = data;
232
 
        WPA_PUT_BE16(pos, psk_len);
233
 
        pos += 2;
234
 
        os_memcpy(pos, psk, psk_len);
235
 
        pos += psk_len;
236
 
        WPA_PUT_BE24(pos, 0); /* CSuite/Vendor = IETF */
237
 
        pos += 3;
238
 
        WPA_PUT_BE24(pos, EAP_GPSK_CIPHER_SHA256); /* CSuite/Specifier */
239
 
        pos += 3;
240
 
        os_memcpy(pos, seed, seed_len); /* inputString */
241
 
        wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: Data to MK derivation (SHA256)",
242
 
                        data, data_len);
243
 
 
244
 
        if (eap_gpsk_gkdf_sha256(zero_string, sizeof(zero_string),
245
 
                                 data, data_len, mk, sizeof(mk)) < 0) {
246
 
                os_free(data);
247
 
                return -1;
248
 
        }
249
 
        os_free(data);
250
 
        wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MK", mk, sizeof(mk));
251
 
 
252
 
        if (eap_gpsk_gkdf_sha256(mk, sizeof(mk), seed, seed_len,
253
 
                                 kdf_out, sizeof(kdf_out)) < 0)
254
 
                return -1;
255
 
 
256
 
        pos = kdf_out;
257
 
        wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MSK", pos, EAP_MSK_LEN);
258
 
        os_memcpy(msk, pos, EAP_MSK_LEN);
259
 
        pos += EAP_MSK_LEN;
260
 
 
261
 
        wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: EMSK", pos, EAP_EMSK_LEN);
262
 
        os_memcpy(emsk, pos, EAP_EMSK_LEN);
263
 
        pos += EAP_EMSK_LEN;
264
 
 
265
 
        wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: SK",
266
 
                        pos, EAP_GPSK_SK_LEN_SHA256);
267
 
        os_memcpy(sk, pos, EAP_GPSK_SK_LEN_SHA256);
268
 
        *sk_len = EAP_GPSK_SK_LEN_AES;
269
 
        pos += EAP_GPSK_SK_LEN_AES;
270
 
 
271
 
        wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PK",
272
 
                        pos, EAP_GPSK_PK_LEN_SHA256);
273
 
        os_memcpy(pk, pos, EAP_GPSK_PK_LEN_SHA256);
274
 
        *pk_len = EAP_GPSK_PK_LEN_SHA256;
275
 
 
276
 
        return 0;
277
 
}
278
 
#endif /* EAP_GPSK_SHA256 */
279
 
 
280
 
 
281
 
/**
282
 
 * eap_gpsk_derive_keys - Derive EAP-GPSK keys
283
 
 * @psk: Pre-shared key (at least 16 bytes if AES is used)
284
 
 * @psk_len: Length of psk in bytes
285
 
 * @vendor: CSuite/Vendor
286
 
 * @specifier: CSuite/Specifier
287
 
 * @rand_client: 32-byte RAND_Client
288
 
 * @rand_server: 32-byte RAND_Server
289
 
 * @id_client: ID_Client
290
 
 * @id_client_len: Length of ID_Client
291
 
 * @id_server: ID_Server
292
 
 * @id_server_len: Length of ID_Server
293
 
 * @msk: Buffer for 64-byte MSK
294
 
 * @emsk: Buffer for 64-byte EMSK
295
 
 * @sk: Buffer for SK (at least EAP_GPSK_MAX_SK_LEN bytes)
296
 
 * @sk_len: Buffer for returning length of SK
297
 
 * @pk: Buffer for SK (at least EAP_GPSK_MAX_PK_LEN bytes)
298
 
 * @pk_len: Buffer for returning length of PK
299
 
 * Returns: 0 on success, -1 on failure
300
 
 */
301
 
int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
302
 
                         int specifier,
303
 
                         const u8 *rand_client, const u8 *rand_server,
304
 
                         const u8 *id_client, size_t id_client_len,
305
 
                         const u8 *id_server, size_t id_server_len,
306
 
                         u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len,
307
 
                         u8 *pk, size_t *pk_len)
308
 
{
309
 
        u8 *seed, *pos;
310
 
        size_t seed_len;
311
 
        int ret;
312
 
 
313
 
        wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving keys (%d:%d)",
314
 
                   vendor, specifier);
315
 
 
316
 
        if (vendor != EAP_GPSK_VENDOR_IETF)
317
 
                return -1;
318
 
 
319
 
        wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PSK", psk, psk_len);
320
 
 
321
 
        /* Seed = RAND_Client || ID_Client || RAND_Server || ID_Server */
322
 
        seed_len = 2 * EAP_GPSK_RAND_LEN + id_server_len + id_client_len;
323
 
        seed = os_malloc(seed_len);
324
 
        if (seed == NULL) {
325
 
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory "
326
 
                           "for key derivation");
327
 
                return -1;
328
 
        }
329
 
 
330
 
        pos = seed;
331
 
        os_memcpy(pos, rand_client, EAP_GPSK_RAND_LEN);
332
 
        pos += EAP_GPSK_RAND_LEN;
333
 
        os_memcpy(pos, id_client, id_client_len);
334
 
        pos += id_client_len;
335
 
        os_memcpy(pos, rand_server, EAP_GPSK_RAND_LEN);
336
 
        pos += EAP_GPSK_RAND_LEN;
337
 
        os_memcpy(pos, id_server, id_server_len);
338
 
        pos += id_server_len;
339
 
        wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, seed_len);
340
 
 
341
 
        switch (specifier) {
342
 
        case EAP_GPSK_CIPHER_AES:
343
 
                ret = eap_gpsk_derive_keys_aes(psk, psk_len, seed, seed_len,
344
 
                                               msk, emsk, sk, sk_len,
345
 
                                               pk, pk_len);
346
 
                break;
347
 
#ifdef EAP_GPSK_SHA256
348
 
        case EAP_GPSK_CIPHER_SHA256:
349
 
                ret = eap_gpsk_derive_keys_sha256(psk, psk_len, seed, seed_len,
350
 
                                                  msk, emsk, sk, sk_len,
351
 
                                                  pk, pk_len);
352
 
                break;
353
 
#endif /* EAP_GPSK_SHA256 */
354
 
        default:
355
 
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d:%d used in "
356
 
                           "key derivation", vendor, specifier);
357
 
                ret = -1;
358
 
                break;
359
 
        }
360
 
 
361
 
        os_free(seed);
362
 
 
363
 
        return ret;
364
 
}
365
 
 
366
 
 
367
 
/**
368
 
 * eap_gpsk_mic_len - Get the length of the MIC
369
 
 * @vendor: CSuite/Vendor
370
 
 * @specifier: CSuite/Specifier
371
 
 * Returns: MIC length in bytes
372
 
 */
373
 
size_t eap_gpsk_mic_len(int vendor, int specifier)
374
 
{
375
 
        if (vendor != EAP_GPSK_VENDOR_IETF)
376
 
                return 0;
377
 
 
378
 
        switch (specifier) {
379
 
        case EAP_GPSK_CIPHER_AES:
380
 
                return 16;
381
 
#ifdef EAP_GPSK_SHA256
382
 
        case EAP_GPSK_CIPHER_SHA256:
383
 
                return 32;
384
 
#endif /* EAP_GPSK_SHA256 */
385
 
        default:
386
 
                return 0;
387
 
        }
388
 
}
389
 
 
390
 
 
391
 
static int eap_gpsk_compute_mic_aes(const u8 *sk, size_t sk_len,
392
 
                                    const u8 *data, size_t len, u8 *mic)
393
 
{
394
 
        if (sk_len != 16) {
395
 
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid SK length %d for "
396
 
                           "AES-CMAC MIC", sk_len);
397
 
                return -1;
398
 
        }
399
 
 
400
 
        return omac1_aes_128(sk, data, len, mic);
401
 
}
402
 
 
403
 
 
404
 
/**
405
 
 * eap_gpsk_compute_mic - Compute EAP-GPSK MIC for an EAP packet
406
 
 * @sk: Session key SK from eap_gpsk_derive_keys()
407
 
 * @sk_len: SK length in bytes from eap_gpsk_derive_keys()
408
 
 * @vendor: CSuite/Vendor
409
 
 * @specifier: CSuite/Specifier
410
 
 * @data: Input data to MIC
411
 
 * @len: Input data length in bytes
412
 
 * @mic: Buffer for the computed MIC, eap_gpsk_mic_len(cipher) bytes
413
 
 * Returns: 0 on success, -1 on failure
414
 
 */
415
 
int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor,
416
 
                         int specifier, const u8 *data, size_t len, u8 *mic)
417
 
{
418
 
        int ret;
419
 
 
420
 
        if (vendor != EAP_GPSK_VENDOR_IETF)
421
 
                return -1;
422
 
 
423
 
        switch (specifier) {
424
 
        case EAP_GPSK_CIPHER_AES:
425
 
                ret = eap_gpsk_compute_mic_aes(sk, sk_len, data, len, mic);
426
 
                break;
427
 
#ifdef EAP_GPSK_SHA256
428
 
        case EAP_GPSK_CIPHER_SHA256:
429
 
                hmac_sha256(sk, sk_len, data, len, mic);
430
 
                ret = 0;
431
 
                break;
432
 
#endif /* EAP_GPSK_SHA256 */
433
 
        default:
434
 
                wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d:%d used in "
435
 
                           "MIC computation", vendor, specifier);
436
 
                ret = -1;
437
 
                break;
438
 
        }
439
 
 
440
 
        return ret;
441
 
}