2 * EAP peer method: EAP-PSK (RFC 4764)
3 * Copyright (c) 2004-2007, 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.
22 #include "config_ssid.h"
25 #include "eap_psk_common.h"
29 enum { PSK_INIT
, PSK_MAC_SENT
, PSK_DONE
} state
;
30 u8 rand_p
[EAP_PSK_RAND_LEN
];
31 u8 ak
[EAP_PSK_AK_LEN
], kdk
[EAP_PSK_KDK_LEN
], tek
[EAP_PSK_TEK_LEN
];
33 size_t id_s_len
, id_p_len
;
35 u8 emsk
[EAP_EMSK_LEN
];
39 static void * eap_psk_init(struct eap_sm
*sm
)
41 struct wpa_ssid
*config
= eap_get_config(sm
);
42 struct eap_psk_data
*data
;
44 if (config
== NULL
|| !config
->eappsk
) {
45 wpa_printf(MSG_INFO
, "EAP-PSK: pre-shared key not configured");
49 data
= os_zalloc(sizeof(*data
));
52 eap_psk_key_setup(config
->eappsk
, data
->ak
, data
->kdk
);
53 wpa_hexdump_key(MSG_DEBUG
, "EAP-PSK: AK", data
->ak
, EAP_PSK_AK_LEN
);
54 wpa_hexdump_key(MSG_DEBUG
, "EAP-PSK: KDK", data
->kdk
, EAP_PSK_KDK_LEN
);
55 data
->state
= PSK_INIT
;
58 data
->id_p
= os_malloc(config
->nai_len
);
60 os_memcpy(data
->id_p
, config
->nai
, config
->nai_len
);
61 data
->id_p_len
= config
->nai_len
;
63 if (data
->id_p
== NULL
) {
64 wpa_printf(MSG_INFO
, "EAP-PSK: could not get own identity");
73 static void eap_psk_deinit(struct eap_sm
*sm
, void *priv
)
75 struct eap_psk_data
*data
= priv
;
82 static u8
* eap_psk_process_1(struct eap_psk_data
*data
,
83 struct eap_method_ret
*ret
,
84 const u8
*reqData
, size_t reqDataLen
,
87 const struct eap_psk_hdr_1
*hdr1
;
88 struct eap_psk_hdr_2
*hdr2
;
92 wpa_printf(MSG_DEBUG
, "EAP-PSK: in INIT state");
94 hdr1
= (const struct eap_psk_hdr_1
*) reqData
;
95 if (reqDataLen
< sizeof(*hdr1
) ||
96 be_to_host16(hdr1
->length
) < sizeof(*hdr1
) ||
97 be_to_host16(hdr1
->length
) > reqDataLen
) {
98 wpa_printf(MSG_INFO
, "EAP-PSK: Invalid first message "
99 "length (%lu %d; expected %lu or more)",
100 (unsigned long) reqDataLen
,
101 be_to_host16(hdr1
->length
),
102 (unsigned long) sizeof(*hdr1
));
106 wpa_printf(MSG_DEBUG
, "EAP-PSK: Flags=0x%x", hdr1
->flags
);
107 if (EAP_PSK_FLAGS_GET_T(hdr1
->flags
) != 0) {
108 wpa_printf(MSG_INFO
, "EAP-PSK: Unexpected T=%d (expected 0)",
109 EAP_PSK_FLAGS_GET_T(hdr1
->flags
));
110 ret
->methodState
= METHOD_DONE
;
111 ret
->decision
= DECISION_FAIL
;
114 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: RAND_S", hdr1
->rand_s
,
117 data
->id_s_len
= be_to_host16(hdr1
->length
) - sizeof(*hdr1
);
118 data
->id_s
= os_malloc(data
->id_s_len
);
119 if (data
->id_s
== NULL
) {
120 wpa_printf(MSG_ERROR
, "EAP-PSK: Failed to allocate memory for "
121 "ID_S (len=%lu)", (unsigned long) data
->id_s_len
);
125 os_memcpy(data
->id_s
, (u8
*) (hdr1
+ 1), data
->id_s_len
);
126 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-PSK: ID_S",
127 data
->id_s
, data
->id_s_len
);
129 if (hostapd_get_rand(data
->rand_p
, EAP_PSK_RAND_LEN
)) {
130 wpa_printf(MSG_ERROR
, "EAP-PSK: Failed to get random data");
135 *respDataLen
= sizeof(*hdr2
) + data
->id_p_len
;
136 resp
= os_malloc(*respDataLen
);
139 hdr2
= (struct eap_psk_hdr_2
*) resp
;
140 hdr2
->code
= EAP_CODE_RESPONSE
;
141 hdr2
->identifier
= hdr1
->identifier
;
142 hdr2
->length
= host_to_be16(*respDataLen
);
143 hdr2
->type
= EAP_TYPE_PSK
;
144 hdr2
->flags
= EAP_PSK_FLAGS_SET_T(1); /* T=1 */
145 os_memcpy(hdr2
->rand_s
, hdr1
->rand_s
, EAP_PSK_RAND_LEN
);
146 os_memcpy(hdr2
->rand_p
, data
->rand_p
, EAP_PSK_RAND_LEN
);
147 os_memcpy((u8
*) (hdr2
+ 1), data
->id_p
, data
->id_p_len
);
148 /* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
149 buflen
= data
->id_p_len
+ data
->id_s_len
+ 2 * EAP_PSK_RAND_LEN
;
150 buf
= os_malloc(buflen
);
155 os_memcpy(buf
, data
->id_p
, data
->id_p_len
);
156 pos
= buf
+ data
->id_p_len
;
157 os_memcpy(pos
, data
->id_s
, data
->id_s_len
);
158 pos
+= data
->id_s_len
;
159 os_memcpy(pos
, hdr1
->rand_s
, EAP_PSK_RAND_LEN
);
160 pos
+= EAP_PSK_RAND_LEN
;
161 os_memcpy(pos
, data
->rand_p
, EAP_PSK_RAND_LEN
);
162 omac1_aes_128(data
->ak
, buf
, buflen
, hdr2
->mac_p
);
164 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: RAND_P", hdr2
->rand_p
,
166 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: MAC_P", hdr2
->mac_p
, EAP_PSK_MAC_LEN
);
167 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-PSK: ID_P",
168 (u8
*) (hdr2
+ 1), data
->id_p_len
);
170 data
->state
= PSK_MAC_SENT
;
176 static u8
* eap_psk_process_3(struct eap_psk_data
*data
,
177 struct eap_method_ret
*ret
,
178 const u8
*reqData
, size_t reqDataLen
,
181 const struct eap_psk_hdr_3
*hdr3
;
182 struct eap_psk_hdr_4
*hdr4
;
183 u8
*resp
, *buf
, *rpchannel
, nonce
[16], *decrypted
;
184 const u8
*pchannel
, *tag
, *msg
;
185 u8 mac
[EAP_PSK_MAC_LEN
];
186 size_t buflen
, left
, data_len
;
189 wpa_printf(MSG_DEBUG
, "EAP-PSK: in MAC_SENT state");
191 hdr3
= (const struct eap_psk_hdr_3
*) reqData
;
192 left
= be_to_host16(hdr3
->length
);
193 if (left
< sizeof(*hdr3
) || reqDataLen
< left
) {
194 wpa_printf(MSG_INFO
, "EAP-PSK: Invalid third message "
195 "length (%lu %d; expected %lu)",
196 (unsigned long) reqDataLen
,
197 be_to_host16(hdr3
->length
),
198 (unsigned long) sizeof(*hdr3
));
202 left
-= sizeof(*hdr3
);
203 pchannel
= (const u8
*) (hdr3
+ 1);
204 wpa_printf(MSG_DEBUG
, "EAP-PSK: Flags=0x%x", hdr3
->flags
);
205 if (EAP_PSK_FLAGS_GET_T(hdr3
->flags
) != 2) {
206 wpa_printf(MSG_INFO
, "EAP-PSK: Unexpected T=%d (expected 2)",
207 EAP_PSK_FLAGS_GET_T(hdr3
->flags
));
208 ret
->methodState
= METHOD_DONE
;
209 ret
->decision
= DECISION_FAIL
;
212 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: RAND_S", hdr3
->rand_s
,
214 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: MAC_S", hdr3
->mac_s
, EAP_PSK_MAC_LEN
);
215 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: PCHANNEL", pchannel
, left
);
217 if (left
< 4 + 16 + 1) {
218 wpa_printf(MSG_INFO
, "EAP-PSK: Too short PCHANNEL data in "
219 "third message (len=%lu, expected 21)",
220 (unsigned long) left
);
225 /* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
226 buflen
= data
->id_s_len
+ EAP_PSK_RAND_LEN
;
227 buf
= os_malloc(buflen
);
230 os_memcpy(buf
, data
->id_s
, data
->id_s_len
);
231 os_memcpy(buf
+ data
->id_s_len
, data
->rand_p
, EAP_PSK_RAND_LEN
);
232 omac1_aes_128(data
->ak
, buf
, buflen
, mac
);
234 if (os_memcmp(mac
, hdr3
->mac_s
, EAP_PSK_MAC_LEN
) != 0) {
235 wpa_printf(MSG_WARNING
, "EAP-PSK: Invalid MAC_S in third "
237 ret
->methodState
= METHOD_DONE
;
238 ret
->decision
= DECISION_FAIL
;
241 wpa_printf(MSG_DEBUG
, "EAP-PSK: MAC_S verified successfully");
243 eap_psk_derive_keys(data
->kdk
, data
->rand_p
, data
->tek
,
244 data
->msk
, data
->emsk
);
245 wpa_hexdump_key(MSG_DEBUG
, "EAP-PSK: TEK", data
->tek
, EAP_PSK_TEK_LEN
);
246 wpa_hexdump_key(MSG_DEBUG
, "EAP-PSK: MSK", data
->msk
, EAP_MSK_LEN
);
247 wpa_hexdump_key(MSG_DEBUG
, "EAP-PSK: EMSK", data
->emsk
, EAP_EMSK_LEN
);
249 os_memset(nonce
, 0, 12);
250 os_memcpy(nonce
+ 12, pchannel
, 4);
260 wpa_hexdump(MSG_MSGDUMP
, "EAP-PSK: PCHANNEL - nonce",
261 nonce
, sizeof(nonce
));
262 wpa_hexdump(MSG_MSGDUMP
, "EAP-PSK: PCHANNEL - hdr", reqData
, 5);
263 wpa_hexdump(MSG_MSGDUMP
, "EAP-PSK: PCHANNEL - cipher msg", msg
, left
);
265 decrypted
= os_malloc(left
);
266 if (decrypted
== NULL
) {
267 ret
->methodState
= METHOD_DONE
;
268 ret
->decision
= DECISION_FAIL
;
271 os_memcpy(decrypted
, msg
, left
);
273 if (aes_128_eax_decrypt(data
->tek
, nonce
, sizeof(nonce
),
274 reqData
, 22, decrypted
, left
, tag
)) {
275 wpa_printf(MSG_WARNING
, "EAP-PSK: PCHANNEL decryption failed");
279 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: Decrypted PCHANNEL message",
283 switch (decrypted
[0] >> 6) {
284 case EAP_PSK_R_FLAG_CONT
:
285 wpa_printf(MSG_DEBUG
, "EAP-PSK: R flag - CONT - unsupported");
288 case EAP_PSK_R_FLAG_DONE_SUCCESS
:
289 wpa_printf(MSG_DEBUG
, "EAP-PSK: R flag - DONE_SUCCESS");
291 case EAP_PSK_R_FLAG_DONE_FAILURE
:
292 wpa_printf(MSG_DEBUG
, "EAP-PSK: R flag - DONE_FAILURE");
293 wpa_printf(MSG_INFO
, "EAP-PSK: Authentication server rejected "
299 *respDataLen
= sizeof(*hdr4
) + 4 + 16 + 1;
300 resp
= os_malloc(*respDataLen
+ 1);
305 hdr4
= (struct eap_psk_hdr_4
*) resp
;
306 hdr4
->code
= EAP_CODE_RESPONSE
;
307 hdr4
->identifier
= hdr3
->identifier
;
308 hdr4
->length
= host_to_be16(*respDataLen
);
309 hdr4
->type
= EAP_TYPE_PSK
;
310 hdr4
->flags
= EAP_PSK_FLAGS_SET_T(3); /* T=3 */
311 os_memcpy(hdr4
->rand_s
, hdr3
->rand_s
, EAP_PSK_RAND_LEN
);
312 rpchannel
= (u8
*) (hdr4
+ 1);
315 inc_byte_array(nonce
, sizeof(nonce
));
316 os_memcpy(rpchannel
, nonce
+ 12, 4);
319 if (decrypted
[0] & EAP_PSK_E_FLAG
) {
320 wpa_printf(MSG_DEBUG
, "EAP-PSK: Unsupported E (Ext) flag");
322 rpchannel
[4 + 16] = (EAP_PSK_R_FLAG_DONE_FAILURE
<< 6) |
325 /* Add empty EXT_Payload with same EXT_Type */
327 hdr4
->length
= host_to_be16(*respDataLen
);
328 rpchannel
[4 + 16 + 1] = decrypted
[1];
332 rpchannel
[4 + 16] = EAP_PSK_R_FLAG_DONE_FAILURE
<< 6;
334 rpchannel
[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS
<< 6;
336 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: reply message (plaintext)",
337 rpchannel
+ 4 + 16, data_len
);
338 aes_128_eax_encrypt(data
->tek
, nonce
, sizeof(nonce
), resp
, 22,
339 rpchannel
+ 4 + 16, data_len
, rpchannel
+ 4);
340 wpa_hexdump(MSG_DEBUG
, "EAP-PSK: reply message (PCHANNEL)",
341 rpchannel
, 4 + 16 + data_len
);
343 wpa_printf(MSG_DEBUG
, "EAP-PSK: Completed %ssuccessfully",
345 data
->state
= PSK_DONE
;
346 ret
->methodState
= METHOD_DONE
;
347 ret
->decision
= failed
? DECISION_FAIL
: DECISION_UNCOND_SUCC
;
355 static u8
* eap_psk_process(struct eap_sm
*sm
, void *priv
,
356 struct eap_method_ret
*ret
,
357 const u8
*reqData
, size_t reqDataLen
,
360 struct eap_psk_data
*data
= priv
;
365 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, EAP_TYPE_PSK
,
366 reqData
, reqDataLen
, &len
);
371 len
+= sizeof(struct eap_hdr
) + 1;
374 ret
->methodState
= METHOD_MAY_CONT
;
375 ret
->decision
= DECISION_FAIL
;
376 ret
->allowNotifications
= TRUE
;
378 switch (data
->state
) {
380 resp
= eap_psk_process_1(data
, ret
, reqData
, len
,
384 resp
= eap_psk_process_3(data
, ret
, reqData
, len
,
388 wpa_printf(MSG_DEBUG
, "EAP-PSK: in DONE state - ignore "
389 "unexpected message");
394 if (ret
->methodState
== METHOD_DONE
) {
395 ret
->allowNotifications
= FALSE
;
402 static Boolean
eap_psk_isKeyAvailable(struct eap_sm
*sm
, void *priv
)
404 struct eap_psk_data
*data
= priv
;
405 return data
->state
== PSK_DONE
;
409 static u8
* eap_psk_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
411 struct eap_psk_data
*data
= priv
;
414 if (data
->state
!= PSK_DONE
)
417 key
= os_malloc(EAP_MSK_LEN
);
422 os_memcpy(key
, data
->msk
, EAP_MSK_LEN
);
428 static u8
* eap_psk_get_emsk(struct eap_sm
*sm
, void *priv
, size_t *len
)
430 struct eap_psk_data
*data
= priv
;
433 if (data
->state
!= PSK_DONE
)
436 key
= os_malloc(EAP_EMSK_LEN
);
441 os_memcpy(key
, data
->emsk
, EAP_EMSK_LEN
);
447 int eap_peer_psk_register(void)
449 struct eap_method
*eap
;
452 eap
= eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION
,
453 EAP_VENDOR_IETF
, EAP_TYPE_PSK
, "PSK");
457 eap
->init
= eap_psk_init
;
458 eap
->deinit
= eap_psk_deinit
;
459 eap
->process
= eap_psk_process
;
460 eap
->isKeyAvailable
= eap_psk_isKeyAvailable
;
461 eap
->getKey
= eap_psk_getKey
;
462 eap
->get_emsk
= eap_psk_get_emsk
;
464 ret
= eap_peer_method_register(eap
);
466 eap_peer_method_free(eap
);