2 * EAP peer method: EAP-PSK (RFC 4764)
3 * Copyright (c) 2004-2008, Jouni Malinen <j@w1.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.
21 #include "eap_peer/eap_i.h"
23 #include "eap_common/eap_psk_common.h"
27 enum { PSK_INIT
, PSK_MAC_SENT
, PSK_DONE
} state
;
28 u8 rand_p
[EAP_PSK_RAND_LEN
];
29 u8 ak
[EAP_PSK_AK_LEN
], kdk
[EAP_PSK_KDK_LEN
], tek
[EAP_PSK_TEK_LEN
];
31 size_t id_s_len
, id_p_len
;
33 u8 emsk
[EAP_EMSK_LEN
];
37 static void * eap_psk_init(struct eap_sm
*sm
)
39 struct eap_psk_data
*data
;
40 const u8
*identity
, *password
;
41 size_t identity_len
, password_len
;
43 password
= eap_get_config_password(sm
, &password_len
);
44 if (!password
|| password_len
!= 16) {
45 wpa_printf(MSG_INFO
, "EAP-PSK: 16-octet pre-shared key not "
50 data
= os_zalloc(sizeof(*data
));
53 if (eap_psk_key_setup(password
, data
->ak
, data
->kdk
)) {
57 wpa_hexdump_key(MSG_DEBUG
, "EAP-PSK: AK", data
->ak
, EAP_PSK_AK_LEN
);
58 wpa_hexdump_key(MSG_DEBUG
, "EAP-PSK: KDK", data
->kdk
, EAP_PSK_KDK_LEN
);
59 data
->state
= PSK_INIT
;
61 identity
= eap_get_config_identity(sm
, &identity_len
);
63 data
->id_p
= os_malloc(identity_len
);
65 os_memcpy(data
->id_p
, identity
, identity_len
);
66 data
->id_p_len
= identity_len
;
68 if (data
->id_p
== NULL
) {
69 wpa_printf(MSG_INFO
, "EAP-PSK: could not get own identity");
78 static void eap_psk_deinit(struct eap_sm
*sm
, void *priv
)
80 struct eap_psk_data
*data
= priv
;
87 static struct wpabuf
* eap_psk_process_1(struct eap_psk_data
*data
,
88 struct eap_method_ret
*ret
,
89 const struct wpabuf
*reqData
)
91 const struct eap_psk_hdr_1
*hdr1
;
92 struct eap_psk_hdr_2
*hdr2
;
98 wpa_printf(MSG_DEBUG
, "EAP-PSK: in INIT state");
100 cpos
= eap_hdr_validate(EAP_VENDOR_IETF
, EAP_TYPE_PSK
, reqData
, &len
);
101 hdr1
= (const struct eap_psk_hdr_1
*) cpos
;
102 if (cpos
== NULL
|| len
< sizeof(*hdr1
)) {
103 wpa_printf(MSG_INFO
, "EAP-PSK: Invalid first message "
104 "length (%lu; expected %lu or more)",
106 (unsigned long) sizeof(*hdr1
));
110 wpa_printf(MSG_DEBUG
, "EAP-PSK: Flags=0x%x", hdr1
->flags
);
111 if (EAP_PSK_FLAGS_GET_T(hdr1
->flags
) != 0) {
112 wpa_printf(MSG_INFO
, "EAP-PSK: Unexpected T=%d (expected 0)",
113 EAP_PSK_FLAGS_GET_T(hdr1
->flags
));
114 ret
->methodState
= METHOD_DONE
;
115 ret
->decision
= DECISION_FAIL
;
118 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: RAND_S", hdr1
->rand_s
,
121 data
->id_s_len
= len
- sizeof(*hdr1
);
122 data
->id_s
= os_malloc(data
->id_s_len
);
123 if (data
->id_s
== NULL
) {
124 wpa_printf(MSG_ERROR
, "EAP-PSK: Failed to allocate memory for "
125 "ID_S (len=%lu)", (unsigned long) data
->id_s_len
);
129 os_memcpy(data
->id_s
, (u8
*) (hdr1
+ 1), data
->id_s_len
);
130 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-PSK: ID_S",
131 data
->id_s
, data
->id_s_len
);
133 if (os_get_random(data
->rand_p
, EAP_PSK_RAND_LEN
)) {
134 wpa_printf(MSG_ERROR
, "EAP-PSK: Failed to get random data");
139 resp
= eap_msg_alloc(EAP_VENDOR_IETF
, EAP_TYPE_PSK
,
140 sizeof(*hdr2
) + data
->id_p_len
, EAP_CODE_RESPONSE
,
141 eap_get_id(reqData
));
144 hdr2
= wpabuf_put(resp
, sizeof(*hdr2
));
145 hdr2
->flags
= EAP_PSK_FLAGS_SET_T(1); /* T=1 */
146 os_memcpy(hdr2
->rand_s
, hdr1
->rand_s
, EAP_PSK_RAND_LEN
);
147 os_memcpy(hdr2
->rand_p
, data
->rand_p
, EAP_PSK_RAND_LEN
);
148 wpabuf_put_data(resp
, data
->id_p
, data
->id_p_len
);
149 /* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
150 buflen
= data
->id_p_len
+ data
->id_s_len
+ 2 * EAP_PSK_RAND_LEN
;
151 buf
= os_malloc(buflen
);
156 os_memcpy(buf
, data
->id_p
, data
->id_p_len
);
157 pos
= buf
+ data
->id_p_len
;
158 os_memcpy(pos
, data
->id_s
, data
->id_s_len
);
159 pos
+= data
->id_s_len
;
160 os_memcpy(pos
, hdr1
->rand_s
, EAP_PSK_RAND_LEN
);
161 pos
+= EAP_PSK_RAND_LEN
;
162 os_memcpy(pos
, data
->rand_p
, EAP_PSK_RAND_LEN
);
163 if (omac1_aes_128(data
->ak
, buf
, buflen
, hdr2
->mac_p
)) {
169 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: RAND_P", hdr2
->rand_p
,
171 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: MAC_P", hdr2
->mac_p
, EAP_PSK_MAC_LEN
);
172 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-PSK: ID_P",
173 data
->id_p
, data
->id_p_len
);
175 data
->state
= PSK_MAC_SENT
;
181 static struct wpabuf
* eap_psk_process_3(struct eap_psk_data
*data
,
182 struct eap_method_ret
*ret
,
183 const struct wpabuf
*reqData
)
185 const struct eap_psk_hdr_3
*hdr3
;
186 struct eap_psk_hdr_4
*hdr4
;
188 u8
*buf
, *rpchannel
, nonce
[16], *decrypted
;
189 const u8
*pchannel
, *tag
, *msg
;
190 u8 mac
[EAP_PSK_MAC_LEN
];
191 size_t buflen
, left
, data_len
, len
, plen
;
195 wpa_printf(MSG_DEBUG
, "EAP-PSK: in MAC_SENT state");
197 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, EAP_TYPE_PSK
,
199 hdr3
= (const struct eap_psk_hdr_3
*) pos
;
200 if (pos
== NULL
|| len
< sizeof(*hdr3
)) {
201 wpa_printf(MSG_INFO
, "EAP-PSK: Invalid third message "
202 "length (%lu; expected %lu or more)",
204 (unsigned long) sizeof(*hdr3
));
208 left
= len
- sizeof(*hdr3
);
209 pchannel
= (const u8
*) (hdr3
+ 1);
210 wpa_printf(MSG_DEBUG
, "EAP-PSK: Flags=0x%x", hdr3
->flags
);
211 if (EAP_PSK_FLAGS_GET_T(hdr3
->flags
) != 2) {
212 wpa_printf(MSG_INFO
, "EAP-PSK: Unexpected T=%d (expected 2)",
213 EAP_PSK_FLAGS_GET_T(hdr3
->flags
));
214 ret
->methodState
= METHOD_DONE
;
215 ret
->decision
= DECISION_FAIL
;
218 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: RAND_S", hdr3
->rand_s
,
220 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: MAC_S", hdr3
->mac_s
, EAP_PSK_MAC_LEN
);
221 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: PCHANNEL", pchannel
, left
);
223 if (left
< 4 + 16 + 1) {
224 wpa_printf(MSG_INFO
, "EAP-PSK: Too short PCHANNEL data in "
225 "third message (len=%lu, expected 21)",
226 (unsigned long) left
);
231 /* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
232 buflen
= data
->id_s_len
+ EAP_PSK_RAND_LEN
;
233 buf
= os_malloc(buflen
);
236 os_memcpy(buf
, data
->id_s
, data
->id_s_len
);
237 os_memcpy(buf
+ data
->id_s_len
, data
->rand_p
, EAP_PSK_RAND_LEN
);
238 if (omac1_aes_128(data
->ak
, buf
, buflen
, mac
)) {
243 if (os_memcmp(mac
, hdr3
->mac_s
, EAP_PSK_MAC_LEN
) != 0) {
244 wpa_printf(MSG_WARNING
, "EAP-PSK: Invalid MAC_S in third "
246 ret
->methodState
= METHOD_DONE
;
247 ret
->decision
= DECISION_FAIL
;
250 wpa_printf(MSG_DEBUG
, "EAP-PSK: MAC_S verified successfully");
252 if (eap_psk_derive_keys(data
->kdk
, data
->rand_p
, data
->tek
,
253 data
->msk
, data
->emsk
)) {
254 ret
->methodState
= METHOD_DONE
;
255 ret
->decision
= DECISION_FAIL
;
258 wpa_hexdump_key(MSG_DEBUG
, "EAP-PSK: TEK", data
->tek
, EAP_PSK_TEK_LEN
);
259 wpa_hexdump_key(MSG_DEBUG
, "EAP-PSK: MSK", data
->msk
, EAP_MSK_LEN
);
260 wpa_hexdump_key(MSG_DEBUG
, "EAP-PSK: EMSK", data
->emsk
, EAP_EMSK_LEN
);
262 os_memset(nonce
, 0, 12);
263 os_memcpy(nonce
+ 12, pchannel
, 4);
273 wpa_hexdump(MSG_MSGDUMP
, "EAP-PSK: PCHANNEL - nonce",
274 nonce
, sizeof(nonce
));
275 wpa_hexdump(MSG_MSGDUMP
, "EAP-PSK: PCHANNEL - hdr",
276 wpabuf_head(reqData
), 5);
277 wpa_hexdump(MSG_MSGDUMP
, "EAP-PSK: PCHANNEL - cipher msg", msg
, left
);
279 decrypted
= os_malloc(left
);
280 if (decrypted
== NULL
) {
281 ret
->methodState
= METHOD_DONE
;
282 ret
->decision
= DECISION_FAIL
;
285 os_memcpy(decrypted
, msg
, left
);
287 if (aes_128_eax_decrypt(data
->tek
, nonce
, sizeof(nonce
),
288 wpabuf_head(reqData
),
289 sizeof(struct eap_hdr
) + 1 +
290 sizeof(*hdr3
) - EAP_PSK_MAC_LEN
, decrypted
,
292 wpa_printf(MSG_WARNING
, "EAP-PSK: PCHANNEL decryption failed");
296 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: Decrypted PCHANNEL message",
300 switch (decrypted
[0] >> 6) {
301 case EAP_PSK_R_FLAG_CONT
:
302 wpa_printf(MSG_DEBUG
, "EAP-PSK: R flag - CONT - unsupported");
305 case EAP_PSK_R_FLAG_DONE_SUCCESS
:
306 wpa_printf(MSG_DEBUG
, "EAP-PSK: R flag - DONE_SUCCESS");
308 case EAP_PSK_R_FLAG_DONE_FAILURE
:
309 wpa_printf(MSG_DEBUG
, "EAP-PSK: R flag - DONE_FAILURE");
310 wpa_printf(MSG_INFO
, "EAP-PSK: Authentication server rejected "
317 if ((decrypted
[0] & EAP_PSK_E_FLAG
) && left
> 1)
319 plen
= sizeof(*hdr4
) + 4 + 16 + data_len
;
320 resp
= eap_msg_alloc(EAP_VENDOR_IETF
, EAP_TYPE_PSK
, plen
,
321 EAP_CODE_RESPONSE
, eap_get_id(reqData
));
326 hdr4
= wpabuf_put(resp
, sizeof(*hdr4
));
327 hdr4
->flags
= EAP_PSK_FLAGS_SET_T(3); /* T=3 */
328 os_memcpy(hdr4
->rand_s
, hdr3
->rand_s
, EAP_PSK_RAND_LEN
);
329 rpchannel
= wpabuf_put(resp
, 4 + 16 + data_len
);
332 inc_byte_array(nonce
, sizeof(nonce
));
333 os_memcpy(rpchannel
, nonce
+ 12, 4);
335 if (decrypted
[0] & EAP_PSK_E_FLAG
) {
336 wpa_printf(MSG_DEBUG
, "EAP-PSK: Unsupported E (Ext) flag");
338 rpchannel
[4 + 16] = (EAP_PSK_R_FLAG_DONE_FAILURE
<< 6) |
341 /* Add empty EXT_Payload with same EXT_Type */
342 rpchannel
[4 + 16 + 1] = decrypted
[1];
345 rpchannel
[4 + 16] = EAP_PSK_R_FLAG_DONE_FAILURE
<< 6;
347 rpchannel
[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS
<< 6;
349 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: reply message (plaintext)",
350 rpchannel
+ 4 + 16, data_len
);
351 if (aes_128_eax_encrypt(data
->tek
, nonce
, sizeof(nonce
),
353 sizeof(struct eap_hdr
) + 1 + sizeof(*hdr4
),
354 rpchannel
+ 4 + 16, data_len
, rpchannel
+ 4)) {
359 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: reply message (PCHANNEL)",
360 rpchannel
, 4 + 16 + data_len
);
362 wpa_printf(MSG_DEBUG
, "EAP-PSK: Completed %ssuccessfully",
364 data
->state
= PSK_DONE
;
365 ret
->methodState
= METHOD_DONE
;
366 ret
->decision
= failed
? DECISION_FAIL
: DECISION_UNCOND_SUCC
;
374 static struct wpabuf
* eap_psk_process(struct eap_sm
*sm
, void *priv
,
375 struct eap_method_ret
*ret
,
376 const struct wpabuf
*reqData
)
378 struct eap_psk_data
*data
= priv
;
380 struct wpabuf
*resp
= NULL
;
383 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, EAP_TYPE_PSK
, reqData
, &len
);
390 ret
->methodState
= METHOD_MAY_CONT
;
391 ret
->decision
= DECISION_FAIL
;
392 ret
->allowNotifications
= TRUE
;
394 switch (data
->state
) {
396 resp
= eap_psk_process_1(data
, ret
, reqData
);
399 resp
= eap_psk_process_3(data
, ret
, reqData
);
402 wpa_printf(MSG_DEBUG
, "EAP-PSK: in DONE state - ignore "
403 "unexpected message");
408 if (ret
->methodState
== METHOD_DONE
) {
409 ret
->allowNotifications
= FALSE
;
416 static Boolean
eap_psk_isKeyAvailable(struct eap_sm
*sm
, void *priv
)
418 struct eap_psk_data
*data
= priv
;
419 return data
->state
== PSK_DONE
;
423 static u8
* eap_psk_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
425 struct eap_psk_data
*data
= priv
;
428 if (data
->state
!= PSK_DONE
)
431 key
= os_malloc(EAP_MSK_LEN
);
436 os_memcpy(key
, data
->msk
, EAP_MSK_LEN
);
442 static u8
* eap_psk_get_emsk(struct eap_sm
*sm
, void *priv
, size_t *len
)
444 struct eap_psk_data
*data
= priv
;
447 if (data
->state
!= PSK_DONE
)
450 key
= os_malloc(EAP_EMSK_LEN
);
455 os_memcpy(key
, data
->emsk
, EAP_EMSK_LEN
);
461 int eap_peer_psk_register(void)
463 struct eap_method
*eap
;
466 eap
= eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION
,
467 EAP_VENDOR_IETF
, EAP_TYPE_PSK
, "PSK");
471 eap
->init
= eap_psk_init
;
472 eap
->deinit
= eap_psk_deinit
;
473 eap
->process
= eap_psk_process
;
474 eap
->isKeyAvailable
= eap_psk_isKeyAvailable
;
475 eap
->getKey
= eap_psk_getKey
;
476 eap
->get_emsk
= eap_psk_get_emsk
;
478 ret
= eap_peer_method_register(eap
);
480 eap_peer_method_free(eap
);