2 * WPA Supplicant / EAP-PSK (draft-bersani-eap-psk-09.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.
14 * Note: EAP-PSK is an EAP authentication method and as such, completely
15 * different from WPA-PSK. This file is not needed for WPA-PSK functionality.
24 #include "wpa_supplicant.h"
25 #include "config_ssid.h"
28 #include "eap_psk_common.h"
32 enum { PSK_INIT
, PSK_MAC_SENT
, PSK_DONE
} state
;
33 u8 rand_p
[EAP_PSK_RAND_LEN
];
34 u8 ak
[EAP_PSK_AK_LEN
], kdk
[EAP_PSK_KDK_LEN
], tek
[EAP_PSK_TEK_LEN
];
36 size_t id_s_len
, id_p_len
;
37 u8 key_data
[EAP_PSK_MSK_LEN
];
41 static void * eap_psk_init(struct eap_sm
*sm
)
43 struct wpa_ssid
*config
= eap_get_config(sm
);
44 struct eap_psk_data
*data
;
46 if (config
== NULL
|| !config
->eappsk
) {
47 wpa_printf(MSG_INFO
, "EAP-PSK: pre-shared key not configured");
51 data
= malloc(sizeof(*data
));
54 memset(data
, 0, sizeof(*data
));
55 eap_psk_key_setup(config
->eappsk
, data
->ak
, data
->kdk
);
56 wpa_hexdump_key(MSG_DEBUG
, "EAP-PSK: AK", data
->ak
, EAP_PSK_AK_LEN
);
57 wpa_hexdump_key(MSG_DEBUG
, "EAP-PSK: KDK", data
->kdk
, EAP_PSK_KDK_LEN
);
58 data
->state
= PSK_INIT
;
61 data
->id_p
= malloc(config
->nai_len
);
63 memcpy(data
->id_p
, config
->nai
, config
->nai_len
);
64 data
->id_p_len
= config
->nai_len
;
66 if (data
->id_p
== NULL
) {
67 wpa_printf(MSG_INFO
, "EAP-PSK: could not get own identity");
76 static void eap_psk_deinit(struct eap_sm
*sm
, void *priv
)
78 struct eap_psk_data
*data
= priv
;
85 static u8
* eap_psk_process_1(struct eap_sm
*sm
, struct eap_psk_data
*data
,
86 struct eap_method_ret
*ret
,
87 const u8
*reqData
, size_t reqDataLen
,
90 const struct eap_psk_hdr_1
*hdr1
;
91 struct eap_psk_hdr_2
*hdr2
;
95 wpa_printf(MSG_DEBUG
, "EAP-PSK: in INIT state");
97 hdr1
= (const struct eap_psk_hdr_1
*) reqData
;
98 if (reqDataLen
< sizeof(*hdr1
) ||
99 be_to_host16(hdr1
->length
) < sizeof(*hdr1
) ||
100 be_to_host16(hdr1
->length
) > reqDataLen
) {
101 wpa_printf(MSG_INFO
, "EAP-PSK: Invalid first message "
102 "length (%lu %d; expected %lu or more)",
103 (unsigned long) reqDataLen
,
104 be_to_host16(hdr1
->length
),
105 (unsigned long) sizeof(*hdr1
));
109 wpa_printf(MSG_DEBUG
, "EAP-PSK: Flags=0x%x", hdr1
->flags
);
110 if ((hdr1
->flags
& 0x03) != 0) {
111 wpa_printf(MSG_INFO
, "EAP-PSK: Unexpected T=%d (expected 0)",
113 ret
->methodState
= METHOD_DONE
;
114 ret
->decision
= DECISION_FAIL
;
117 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: RAND_S", hdr1
->rand_s
,
120 data
->id_s_len
= be_to_host16(hdr1
->length
) - sizeof(*hdr1
);
121 data
->id_s
= malloc(data
->id_s_len
);
122 if (data
->id_s
== NULL
) {
123 wpa_printf(MSG_ERROR
, "EAP-PSK: Failed to allocate memory for "
124 "ID_S (len=%lu)", (unsigned long) data
->id_s_len
);
128 memcpy(data
->id_s
, (u8
*) (hdr1
+ 1), data
->id_s_len
);
129 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-PSK: ID_S",
130 data
->id_s
, data
->id_s_len
);
132 if (hostapd_get_rand(data
->rand_p
, EAP_PSK_RAND_LEN
)) {
133 wpa_printf(MSG_ERROR
, "EAP-PSK: Failed to get random data");
138 *respDataLen
= sizeof(*hdr2
) + data
->id_p_len
;
139 resp
= malloc(*respDataLen
);
142 hdr2
= (struct eap_psk_hdr_2
*) resp
;
143 hdr2
->code
= EAP_CODE_RESPONSE
;
144 hdr2
->identifier
= hdr1
->identifier
;
145 hdr2
->length
= host_to_be16(*respDataLen
);
146 hdr2
->type
= EAP_TYPE_PSK
;
147 hdr2
->flags
= 1; /* T=1 */
148 memcpy(hdr2
->rand_s
, hdr1
->rand_s
, EAP_PSK_RAND_LEN
);
149 memcpy(hdr2
->rand_p
, data
->rand_p
, EAP_PSK_RAND_LEN
);
150 memcpy((u8
*) (hdr2
+ 1), data
->id_p
, data
->id_p_len
);
151 /* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
152 buflen
= data
->id_p_len
+ data
->id_s_len
+ 2 * EAP_PSK_RAND_LEN
;
153 buf
= malloc(buflen
);
158 memcpy(buf
, data
->id_p
, data
->id_p_len
);
159 pos
= buf
+ data
->id_p_len
;
160 memcpy(pos
, data
->id_s
, data
->id_s_len
);
161 pos
+= data
->id_s_len
;
162 memcpy(pos
, hdr1
->rand_s
, EAP_PSK_RAND_LEN
);
163 pos
+= EAP_PSK_RAND_LEN
;
164 memcpy(pos
, data
->rand_p
, EAP_PSK_RAND_LEN
);
165 omac1_aes_128(data
->ak
, buf
, buflen
, hdr2
->mac_p
);
167 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: RAND_P", hdr2
->rand_p
,
169 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: MAC_P", hdr2
->mac_p
, EAP_PSK_MAC_LEN
);
170 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-PSK: ID_P",
171 (u8
*) (hdr2
+ 1), data
->id_p_len
);
173 data
->state
= PSK_MAC_SENT
;
179 static u8
* eap_psk_process_3(struct eap_sm
*sm
, struct eap_psk_data
*data
,
180 struct eap_method_ret
*ret
,
181 const u8
*reqData
, size_t reqDataLen
,
184 const struct eap_psk_hdr_3
*hdr3
;
185 struct eap_psk_hdr_4
*hdr4
;
186 u8
*resp
, *buf
, *rpchannel
, nonce
[16], *decrypted
;
187 const u8
*pchannel
, *tag
, *msg
;
188 u8 mac
[EAP_PSK_MAC_LEN
];
189 size_t buflen
, left
, data_len
;
192 wpa_printf(MSG_DEBUG
, "EAP-PSK: in MAC_SENT state");
194 hdr3
= (const struct eap_psk_hdr_3
*) reqData
;
195 left
= be_to_host16(hdr3
->length
);
196 if (left
< sizeof(*hdr3
) || reqDataLen
< left
) {
197 wpa_printf(MSG_INFO
, "EAP-PSK: Invalid third message "
198 "length (%lu %d; expected %lu)",
199 (unsigned long) reqDataLen
,
200 be_to_host16(hdr3
->length
),
201 (unsigned long) sizeof(*hdr3
));
205 left
-= sizeof(*hdr3
);
206 pchannel
= (const u8
*) (hdr3
+ 1);
207 wpa_printf(MSG_DEBUG
, "EAP-PSK: Flags=0x%x", hdr3
->flags
);
208 if ((hdr3
->flags
& 0x03) != 2) {
209 wpa_printf(MSG_INFO
, "EAP-PSK: Unexpected T=%d (expected 2)",
211 ret
->methodState
= METHOD_DONE
;
212 ret
->decision
= DECISION_FAIL
;
215 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: RAND_S", hdr3
->rand_s
,
217 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: MAC_S", hdr3
->mac_s
, EAP_PSK_MAC_LEN
);
218 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: PCHANNEL", pchannel
, left
);
220 if (left
< 4 + 16 + 1) {
221 wpa_printf(MSG_INFO
, "EAP-PSK: Too short PCHANNEL data in "
222 "third message (len=%lu, expected 21)",
223 (unsigned long) left
);
228 /* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
229 buflen
= data
->id_s_len
+ EAP_PSK_RAND_LEN
;
230 buf
= malloc(buflen
);
233 memcpy(buf
, data
->id_s
, data
->id_s_len
);
234 memcpy(buf
+ data
->id_s_len
, data
->rand_p
, EAP_PSK_RAND_LEN
);
235 omac1_aes_128(data
->ak
, buf
, buflen
, mac
);
237 if (memcmp(mac
, hdr3
->mac_s
, EAP_PSK_MAC_LEN
) != 0) {
238 wpa_printf(MSG_WARNING
, "EAP-PSK: Invalid MAC_S in third "
240 ret
->methodState
= METHOD_DONE
;
241 ret
->decision
= DECISION_FAIL
;
244 wpa_printf(MSG_DEBUG
, "EAP-PSK: MAC_S verified successfully");
246 eap_psk_derive_keys(data
->kdk
, data
->rand_p
, data
->tek
,
248 wpa_hexdump_key(MSG_DEBUG
, "EAP-PSK: TEK", data
->tek
, EAP_PSK_TEK_LEN
);
249 wpa_hexdump_key(MSG_DEBUG
, "EAP-PSK: MSK", data
->key_data
,
252 memset(nonce
, 0, 12);
253 memcpy(nonce
+ 12, pchannel
, 4);
263 wpa_hexdump(MSG_MSGDUMP
, "EAP-PSK: PCHANNEL - nonce",
264 nonce
, sizeof(nonce
));
265 wpa_hexdump(MSG_MSGDUMP
, "EAP-PSK: PCHANNEL - hdr", reqData
, 5);
266 wpa_hexdump(MSG_MSGDUMP
, "EAP-PSK: PCHANNEL - cipher msg", msg
, left
);
268 decrypted
= malloc(left
);
269 if (decrypted
== NULL
) {
270 ret
->methodState
= METHOD_DONE
;
271 ret
->decision
= DECISION_FAIL
;
274 memcpy(decrypted
, msg
, left
);
276 if (aes_128_eax_decrypt(data
->tek
, nonce
, sizeof(nonce
),
277 reqData
, 22, decrypted
, left
, tag
)) {
278 wpa_printf(MSG_WARNING
, "EAP-PSK: PCHANNEL decryption failed");
282 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: Decrypted PCHANNEL message",
286 switch (decrypted
[0] >> 6) {
287 case EAP_PSK_R_FLAG_CONT
:
288 wpa_printf(MSG_DEBUG
, "EAP-PSK: R flag - CONT - unsupported");
291 case EAP_PSK_R_FLAG_DONE_SUCCESS
:
292 wpa_printf(MSG_DEBUG
, "EAP-PSK: R flag - DONE_SUCCESS");
294 case EAP_PSK_R_FLAG_DONE_FAILURE
:
295 wpa_printf(MSG_DEBUG
, "EAP-PSK: R flag - DONE_FAILURE");
296 wpa_printf(MSG_INFO
, "EAP-PSK: Authentication server rejected "
302 *respDataLen
= sizeof(*hdr4
) + 4 + 16 + 1;
303 resp
= malloc(*respDataLen
+ 1);
308 hdr4
= (struct eap_psk_hdr_4
*) resp
;
309 hdr4
->code
= EAP_CODE_RESPONSE
;
310 hdr4
->identifier
= hdr3
->identifier
;
311 hdr4
->length
= host_to_be16(*respDataLen
);
312 hdr4
->type
= EAP_TYPE_PSK
;
313 hdr4
->flags
= 3; /* T=3 */
314 memcpy(hdr4
->rand_s
, hdr3
->rand_s
, EAP_PSK_RAND_LEN
);
315 rpchannel
= (u8
*) (hdr4
+ 1);
318 inc_byte_array(nonce
, sizeof(nonce
));
319 memcpy(rpchannel
, nonce
+ 12, 4);
322 if (decrypted
[0] & EAP_PSK_E_FLAG
) {
323 wpa_printf(MSG_DEBUG
, "EAP-PSK: Unsupported E (Ext) flag");
325 rpchannel
[4 + 16] = (EAP_PSK_R_FLAG_DONE_FAILURE
<< 6) |
328 /* Add empty EXT_Payload with same EXT_Type */
330 hdr4
->length
= host_to_be16(*respDataLen
);
331 rpchannel
[4 + 16 + 1] = decrypted
[1];
335 rpchannel
[4 + 16] = EAP_PSK_R_FLAG_DONE_FAILURE
<< 6;
337 rpchannel
[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS
<< 6;
339 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: reply message (plaintext)",
340 rpchannel
+ 4 + 16, data_len
);
341 aes_128_eax_encrypt(data
->tek
, nonce
, sizeof(nonce
), resp
, 22,
342 rpchannel
+ 4 + 16, data_len
, rpchannel
+ 4);
343 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: reply message (PCHANNEL)",
344 rpchannel
, 4 + 16 + data_len
);
346 wpa_printf(MSG_DEBUG
, "EAP-PSK: Completed %ssuccessfully",
348 data
->state
= PSK_DONE
;
349 ret
->methodState
= METHOD_DONE
;
350 ret
->decision
= failed
? DECISION_FAIL
: DECISION_UNCOND_SUCC
;
358 static u8
* eap_psk_process(struct eap_sm
*sm
, void *priv
,
359 struct eap_method_ret
*ret
,
360 const u8
*reqData
, size_t reqDataLen
,
363 struct eap_psk_data
*data
= priv
;
368 pos
= eap_hdr_validate(EAP_TYPE_PSK
, reqData
, reqDataLen
, &len
);
373 len
+= sizeof(struct eap_hdr
) + 1;
376 ret
->methodState
= METHOD_MAY_CONT
;
377 ret
->decision
= DECISION_FAIL
;
378 ret
->allowNotifications
= TRUE
;
380 switch (data
->state
) {
382 resp
= eap_psk_process_1(sm
, data
, ret
, reqData
, len
,
386 resp
= eap_psk_process_3(sm
, data
, ret
, reqData
, len
,
390 wpa_printf(MSG_DEBUG
, "EAP-PSK: in DONE state - ignore "
391 "unexpected message");
396 if (ret
->methodState
== METHOD_DONE
) {
397 ret
->allowNotifications
= FALSE
;
404 static Boolean
eap_psk_isKeyAvailable(struct eap_sm
*sm
, void *priv
)
406 struct eap_psk_data
*data
= priv
;
407 return data
->state
== PSK_DONE
;
411 static u8
* eap_psk_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
413 struct eap_psk_data
*data
= priv
;
416 if (data
->state
!= PSK_DONE
)
419 key
= malloc(EAP_PSK_MSK_LEN
);
423 *len
= EAP_PSK_MSK_LEN
;
424 memcpy(key
, data
->key_data
, EAP_PSK_MSK_LEN
);
430 const struct eap_method eap_method_psk
=
432 .method
= EAP_TYPE_PSK
,
434 .init
= eap_psk_init
,
435 .deinit
= eap_psk_deinit
,
436 .process
= eap_psk_process
,
437 .isKeyAvailable
= eap_psk_isKeyAvailable
,
438 .getKey
= eap_psk_getKey
,