2 * WPA Supplicant / EAP-PSK (draft-bersani-eap-psk-05.txt)
3 * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
21 #include "wpa_supplicant.h"
22 #include "config_ssid.h"
27 /* draft-bersani-eap-psk-03.txt mode. This is retained for interop testing and
28 * will be removed once an AS that supports draft5 becomes available. */
29 #define EAP_PSK_DRAFT3
31 #define EAP_PSK_RAND_LEN 16
32 #define EAP_PSK_MAC_LEN 16
33 #define EAP_PSK_TEK_LEN 16
34 #define EAP_PSK_MSK_LEN 64
36 #define EAP_PSK_R_FLAG_CONT 1
37 #define EAP_PSK_R_FLAG_DONE_SUCCESS 2
38 #define EAP_PSK_R_FLAG_DONE_FAILURE 3
40 /* EAP-PSK First Message (AS -> Supplicant) */
41 struct eap_psk_hdr_1 {
44 u16 length; /* including code, identifier, and length */
45 u8 type; /* EAP_TYPE_PSK */
46 #ifndef EAP_PSK_DRAFT3
48 #endif /* EAP_PSK_DRAFT3 */
49 u8 rand_s[EAP_PSK_RAND_LEN];
50 #ifndef EAP_PSK_DRAFT3
51 /* Followed by variable length ID_S */
52 #endif /* EAP_PSK_DRAFT3 */
53 } __attribute__ ((packed));
55 /* EAP-PSK Second Message (Supplicant -> AS) */
56 struct eap_psk_hdr_2 {
59 u16 length; /* including code, identifier, and length */
60 u8 type; /* EAP_TYPE_PSK */
61 #ifndef EAP_PSK_DRAFT3
63 u8 rand_s[EAP_PSK_RAND_LEN];
64 #endif /* EAP_PSK_DRAFT3 */
65 u8 rand_p[EAP_PSK_RAND_LEN];
66 u8 mac_p[EAP_PSK_MAC_LEN];
67 /* Followed by variable length ID_P */
68 } __attribute__ ((packed));
70 /* EAP-PSK Third Message (AS -> Supplicant) */
71 struct eap_psk_hdr_3 {
74 u16 length; /* including code, identifier, and length */
75 u8 type; /* EAP_TYPE_PSK */
76 #ifndef EAP_PSK_DRAFT3
78 u8 rand_s[EAP_PSK_RAND_LEN];
79 #endif /* EAP_PSK_DRAFT3 */
80 u8 mac_s[EAP_PSK_MAC_LEN];
81 /* Followed by variable length PCHANNEL */
82 } __attribute__ ((packed));
84 /* EAP-PSK Fourth Message (Supplicant -> AS) */
85 struct eap_psk_hdr_4 {
88 u16 length; /* including code, identifier, and length */
89 u8 type; /* EAP_TYPE_PSK */
90 #ifndef EAP_PSK_DRAFT3
92 u8 rand_s[EAP_PSK_RAND_LEN];
93 #endif /* EAP_PSK_DRAFT3 */
94 /* Followed by variable length PCHANNEL */
95 } __attribute__ ((packed));
100 enum { PSK_INIT, PSK_MAC_SENT, PSK_DONE } state;
101 u8 rand_s[EAP_PSK_RAND_LEN];
102 u8 rand_p[EAP_PSK_RAND_LEN];
103 u8 ak[16], kdk[16], tek[EAP_PSK_TEK_LEN];
105 size_t id_s_len, id_p_len;
106 u8 key_data[EAP_PSK_MSK_LEN];
110 #define aes_block_size 16
113 static void eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk)
115 memset(ak, 0, aes_block_size);
116 aes_128_encrypt_block(psk, ak, ak);
117 memcpy(kdk, ak, aes_block_size);
118 ak[aes_block_size - 1] ^= 0x01;
119 kdk[aes_block_size - 1] ^= 0x02;
120 aes_128_encrypt_block(psk, ak, ak);
121 aes_128_encrypt_block(psk, kdk, kdk);
125 static void eap_psk_derive_keys(const u8 *kdk, const u8 *rb, u8 *tek, u8 *msk)
127 u8 hash[aes_block_size];
131 aes_128_encrypt_block(kdk, rb, hash);
133 hash[aes_block_size - 1] ^= counter;
134 aes_128_encrypt_block(kdk, hash, tek);
135 hash[aes_block_size - 1] ^= counter;
138 for (i = 0; i < EAP_PSK_MSK_LEN / aes_block_size; i++) {
139 hash[aes_block_size - 1] ^= counter;
140 aes_128_encrypt_block(kdk, hash, &msk[i * aes_block_size]);
141 hash[aes_block_size - 1] ^= counter;
147 static void * eap_psk_init(struct eap_sm *sm)
149 struct wpa_ssid *config = eap_get_config(sm);
150 struct eap_psk_data *data;
152 if (config == NULL || !config->eappsk) {
153 wpa_printf(MSG_INFO, "EAP-PSK: pre-shared key not configured");
157 data = malloc(sizeof(*data));
160 memset(data, 0, sizeof(*data));
161 eap_psk_key_setup(config->eappsk, data->ak, data->kdk);
162 wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, 16);
163 wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, 16);
164 data->state = PSK_INIT;
167 data->id_p = malloc(config->nai_len);
169 memcpy(data->id_p, config->nai, config->nai_len);
170 data->id_p_len = config->nai_len;
172 if (data->id_p == NULL) {
173 wpa_printf(MSG_INFO, "EAP-PSK: could not get own identity");
178 #ifdef EAP_PSK_DRAFT3
179 if (config->server_nai) {
180 data->id_s = malloc(config->server_nai_len);
182 memcpy(data->id_s, config->server_nai,
183 config->server_nai_len);
184 data->id_s_len = config->server_nai_len;
186 if (data->id_s == NULL) {
187 wpa_printf(MSG_INFO, "EAP-PSK: could not get server identity");
192 #endif /* EAP_PSK_DRAFT3 */
198 static void eap_psk_deinit(struct eap_sm *sm, void *priv)
200 struct eap_psk_data *data = priv;
207 static u8 * eap_psk_process_1(struct eap_sm *sm, struct eap_psk_data *data,
208 struct eap_method_ret *ret,
209 u8 *reqData, size_t reqDataLen,
212 struct eap_psk_hdr_1 *hdr1;
213 struct eap_psk_hdr_2 *hdr2;
214 u8 *resp, *buf, *pos;
217 wpa_printf(MSG_DEBUG, "EAP-PSK: in INIT state");
219 hdr1 = (struct eap_psk_hdr_1 *) reqData;
220 if (reqDataLen < sizeof(*hdr1) ||
221 be_to_host16(hdr1->length) < sizeof(*hdr1) ||
222 be_to_host16(hdr1->length) > reqDataLen) {
223 wpa_printf(MSG_INFO, "EAP-PSK: Invalid first message "
224 "length (%lu %d; expected %lu or more)",
225 (unsigned long) reqDataLen,
226 be_to_host16(hdr1->length),
227 (unsigned long) sizeof(*hdr1));
231 #ifndef EAP_PSK_DRAFT3
232 wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr1->flags);
233 if ((hdr1->flags & 0x03) != 0) {
234 wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 0)",
236 ret->methodState = METHOD_DONE;
237 ret->decision = DECISION_FAIL;
240 #endif /* EAP_PSK_DRAFT3 */
241 wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s,
243 memcpy(data->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN);
244 #ifndef EAP_PSK_DRAFT3
246 data->id_s_len = be_to_host16(hdr1->length) - sizeof(*hdr1);
247 data->id_s = malloc(data->id_s_len);
248 if (data->id_s == NULL) {
249 wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory for "
250 "ID_S (len=%d)", data->id_s_len);
254 memcpy(data->id_s, (u8 *) (hdr1 + 1), data->id_s_len);
255 wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S",
256 data->id_s, data->id_s_len);
257 #endif /* EAP_PSK_DRAFT3 */
259 if (hostapd_get_rand(data->rand_p, EAP_PSK_RAND_LEN)) {
260 wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data");
265 *respDataLen = sizeof(*hdr2) + data->id_p_len;
266 resp = malloc(*respDataLen);
269 hdr2 = (struct eap_psk_hdr_2 *) resp;
270 hdr2->code = EAP_CODE_RESPONSE;
271 hdr2->identifier = hdr1->identifier;
272 hdr2->length = host_to_be16(*respDataLen);
273 hdr2->type = EAP_TYPE_PSK;
274 #ifndef EAP_PSK_DRAFT3
275 hdr2->flags = 1; /* T=1 */
276 memcpy(hdr2->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN);
277 #endif /* EAP_PSK_DRAFT3 */
278 memcpy(hdr2->rand_p, data->rand_p, EAP_PSK_RAND_LEN);
279 memcpy((u8 *) (hdr2 + 1), data->id_p, data->id_p_len);
280 /* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
281 buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN;
282 buf = malloc(buflen);
287 memcpy(buf, data->id_p, data->id_p_len);
288 pos = buf + data->id_p_len;
289 memcpy(pos, data->id_s, data->id_s_len);
290 pos += data->id_s_len;
291 memcpy(pos, data->rand_s, EAP_PSK_RAND_LEN);
292 pos += EAP_PSK_RAND_LEN;
293 memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
294 omac1_aes_128(data->ak, buf, buflen, hdr2->mac_p);
296 wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_P", hdr2->rand_p,
298 wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", hdr2->mac_p, EAP_PSK_MAC_LEN);
299 wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_P",
300 (u8 *) (hdr2 + 1), data->id_p_len);
302 data->state = PSK_MAC_SENT;
308 static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data,
309 struct eap_method_ret *ret,
310 u8 *reqData, size_t reqDataLen,
313 struct eap_psk_hdr_3 *hdr3;
314 struct eap_psk_hdr_4 *hdr4;
315 u8 *resp, *buf, *pchannel, *tag, *msg, nonce[16];
316 u8 mac[EAP_PSK_MAC_LEN];
320 wpa_printf(MSG_DEBUG, "EAP-PSK: in MAC_SENT state");
322 hdr3 = (struct eap_psk_hdr_3 *) reqData;
323 left = be_to_host16(hdr3->length);
324 if (left < sizeof(*hdr3) || reqDataLen < left) {
325 wpa_printf(MSG_INFO, "EAP-PSK: Invalid third message "
326 "length (%lu %d; expected %lu)",
327 (unsigned long) reqDataLen,
328 be_to_host16(hdr3->length),
329 (unsigned long) sizeof(*hdr3));
333 left -= sizeof(*hdr3);
334 pchannel = (u8 *) (hdr3 + 1);
335 #ifndef EAP_PSK_DRAFT3
336 wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr3->flags);
337 if ((hdr3->flags & 0x03) != 2) {
338 wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 2)",
340 ret->methodState = METHOD_DONE;
341 ret->decision = DECISION_FAIL;
344 wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr3->rand_s,
346 /* TODO: would not need to store RAND_S since it is available in this
347 * message. For now, since we store this anyway, verify that it matches
348 * with whatever the server is sending. */
349 if (memcmp(hdr3->rand_s, data->rand_s, EAP_PSK_RAND_LEN) != 0) {
350 wpa_printf(MSG_ERROR, "EAP-PSK: RAND_S did not match");
351 ret->methodState = METHOD_DONE;
352 ret->decision = DECISION_FAIL;
355 #endif /* EAP_PSK_DRAFT3 */
356 wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_S", hdr3->mac_s, EAP_PSK_MAC_LEN);
357 wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL", pchannel, left);
359 if (left < 4 + 16 + 1) {
360 wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in "
361 "third message (len=%lu, expected 21)",
362 (unsigned long) left);
367 /* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
368 buflen = data->id_s_len + EAP_PSK_RAND_LEN;
369 buf = malloc(buflen);
372 memcpy(buf, data->id_s, data->id_s_len);
373 memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN);
374 omac1_aes_128(data->ak, buf, buflen, mac);
376 if (memcmp(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) {
377 wpa_printf(MSG_WARNING, "EAP-PSK: Invalid MAC_S in third "
379 ret->methodState = METHOD_DONE;
380 ret->decision = DECISION_FAIL;
383 wpa_printf(MSG_DEBUG, "EAP-PSK: MAC_S verified successfully");
385 eap_psk_derive_keys(data->kdk, data->rand_p, data->tek,
387 wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN);
388 wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->key_data,
391 memset(nonce, 0, 12);
392 memcpy(nonce + 12, pchannel, 4);
402 wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - nonce",
403 nonce, sizeof(nonce));
404 wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - hdr", reqData, 5);
405 wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - cipher msg", msg, left);
407 #ifdef EAP_PSK_DRAFT3
408 if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce),
409 reqData, 5, msg, left, tag))
410 #else /* EAP_PSK_DRAFT3 */
411 if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce),
412 reqData, 22, msg, left, tag))
413 #endif /* EAP_PSK_DRAFT3 */
415 wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed");
418 wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message",
422 switch (msg[0] >> 6) {
423 case EAP_PSK_R_FLAG_CONT:
424 wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported");
426 case EAP_PSK_R_FLAG_DONE_SUCCESS:
427 wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS");
429 case EAP_PSK_R_FLAG_DONE_FAILURE:
430 wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE");
431 wpa_printf(MSG_INFO, "EAP-PSK: Authentication server rejected "
437 *respDataLen = sizeof(*hdr4) + 4 + 16 + 1;
438 resp = malloc(*respDataLen);
441 hdr4 = (struct eap_psk_hdr_4 *) resp;
442 hdr4->code = EAP_CODE_RESPONSE;
443 hdr4->identifier = hdr3->identifier;
444 hdr4->length = host_to_be16(*respDataLen);
445 hdr4->type = EAP_TYPE_PSK;
446 #ifndef EAP_PSK_DRAFT3
447 hdr4->flags = 3; /* T=3 */
448 memcpy(hdr4->rand_s, hdr3->rand_s, EAP_PSK_RAND_LEN);
449 #endif /* EAP_PSK_DRAFT3 */
450 pchannel = (u8 *) (hdr4 + 1);
453 inc_byte_array(nonce, sizeof(nonce));
454 memcpy(pchannel, nonce + 12, 4);
456 pchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6;
458 wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (plaintext)",
459 pchannel + 4 + 16, 1);
460 #ifdef EAP_PSK_DRAFT3
461 aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), resp, 5,
462 pchannel + 4 + 16, 1, pchannel + 4);
463 #else /* EAP_PSK_DRAFT3 */
464 aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), resp, 22,
465 pchannel + 4 + 16, 1, pchannel + 4);
466 #endif /* EAP_PSK_DRAFT3 */
467 wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (PCHANNEL)",
468 pchannel, 4 + 16 + 1);
470 wpa_printf(MSG_DEBUG, "EAP-PSK: Completed %ssuccessfully",
472 data->state = PSK_DONE;
473 ret->methodState = METHOD_DONE;
474 ret->decision = failed ? DECISION_FAIL : DECISION_UNCOND_SUCC;
480 static u8 * eap_psk_process(struct eap_sm *sm, void *priv,
481 struct eap_method_ret *ret,
482 u8 *reqData, size_t reqDataLen,
485 struct eap_psk_data *data = priv;
487 u8 *pos, *resp = NULL;
490 req = (struct eap_hdr *) reqData;
491 pos = (u8 *) (req + 1);
492 if (reqDataLen < sizeof(*req) + 1 || *pos != EAP_TYPE_PSK ||
493 (len = be_to_host16(req->length)) > reqDataLen) {
494 wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame");
500 ret->methodState = METHOD_CONT;
501 ret->decision = DECISION_FAIL;
502 ret->allowNotifications = TRUE;
504 switch (data->state) {
506 resp = eap_psk_process_1(sm, data, ret, reqData, len,
510 resp = eap_psk_process_3(sm, data, ret, reqData, len,
514 wpa_printf(MSG_DEBUG, "EAP-PSK: in DONE state - ignore "
515 "unexpected message");
520 if (ret->methodState == METHOD_DONE) {
521 ret->allowNotifications = FALSE;
528 static Boolean eap_psk_isKeyAvailable(struct eap_sm *sm, void *priv)
530 struct eap_psk_data *data = priv;
531 return data->state == PSK_DONE;
535 static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len)
537 struct eap_psk_data *data = priv;
540 if (data->state != PSK_DONE)
543 key = malloc(EAP_PSK_MSK_LEN);
547 *len = EAP_PSK_MSK_LEN;
548 memcpy(key, data->key_data, EAP_PSK_MSK_LEN);
554 const struct eap_method eap_method_psk =
556 .method = EAP_TYPE_PSK,
558 .init = eap_psk_init,
559 .deinit = eap_psk_deinit,
560 .process = eap_psk_process,
561 .isKeyAvailable = eap_psk_isKeyAvailable,
562 .getKey = eap_psk_getKey,