~ubuntu-branches/ubuntu/oneiric/wpasupplicant/oneiric

« back to all changes in this revision

Viewing changes to eap_gpsk_common.c

  • Committer: Bazaar Package Importer
  • Author(s): Kel Modderman
  • Date: 2006-10-05 08:04:01 UTC
  • mfrom: (1.2.1 upstream) (2.1.14 edgy)
  • Revision ID: james.westby@ubuntu.com-20061005080401-myfwjtq7di70dyeo
* Update madwifi headers to latest SVN. (Closes: #388316)
* Remove failed attempt at action locking. [debian/functions.sh,
  debian/wpa_action.sh]
* Add hysteresis checking functions, to avoid "event loops" while
  using wpa-roam. [debian/functions.sh, debian/wpa_action.sh]
* Change of co-maintainer email address.
* Add ishex() function to functions.sh to determine wpa-psk value type in
  plaintext or hex. This effectively eliminates the need for the bogus and
  somewhat confusing wpa-passphrase contruct specific to our scripts and
  allows wpa-psk to work with either a 8 to 63 character long plaintext
  string or 64 character long hex string.
* Adjust README.modes to not refer to the redundant wpa-passphrase stuff.
* Add big fat NOTE about acceptable wpa-psk's to top of example gallery.
* Strip surrounding quotes from wpa-ssid if present, instead of just whining
  about them.
* Update email address in copyright blurb of functions.sh, ifupdown.sh and
  wpa_action.sh.  

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