Re-enable hardware UDP/TCP checksum calculation with pseudo header on
[dragonfly/port-amd64.git] / contrib / wpa_supplicant-0.4.9 / eap_psk.c
blob853c79a5e89ac674ce626864ae78aa1940266ff3
1 /*
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
10 * license.
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.
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
22 #include "common.h"
23 #include "eap_i.h"
24 #include "wpa_supplicant.h"
25 #include "config_ssid.h"
26 #include "md5.h"
27 #include "aes_wrap.h"
28 #include "eap_psk_common.h"
31 struct eap_psk_data {
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];
35 u8 *id_s, *id_p;
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");
48 return NULL;
51 data = malloc(sizeof(*data));
52 if (data == NULL)
53 return NULL;
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;
60 if (config->nai) {
61 data->id_p = malloc(config->nai_len);
62 if (data->id_p)
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");
68 free(data);
69 return NULL;
72 return data;
76 static void eap_psk_deinit(struct eap_sm *sm, void *priv)
78 struct eap_psk_data *data = priv;
79 free(data->id_s);
80 free(data->id_p);
81 free(data);
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,
88 size_t *respDataLen)
90 const struct eap_psk_hdr_1 *hdr1;
91 struct eap_psk_hdr_2 *hdr2;
92 u8 *resp, *buf, *pos;
93 size_t buflen;
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));
106 ret->ignore = TRUE;
107 return NULL;
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)",
112 hdr1->flags & 0x03);
113 ret->methodState = METHOD_DONE;
114 ret->decision = DECISION_FAIL;
115 return NULL;
117 wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s,
118 EAP_PSK_RAND_LEN);
119 free(data->id_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);
125 ret->ignore = TRUE;
126 return NULL;
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");
134 ret->ignore = TRUE;
135 return NULL;
138 *respDataLen = sizeof(*hdr2) + data->id_p_len;
139 resp = malloc(*respDataLen);
140 if (resp == NULL)
141 return NULL;
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);
154 if (buf == NULL) {
155 free(resp);
156 return NULL;
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);
166 free(buf);
167 wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_P", hdr2->rand_p,
168 EAP_PSK_RAND_LEN);
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;
175 return resp;
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,
182 size_t *respDataLen)
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;
190 int failed = 0;
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));
202 ret->ignore = TRUE;
203 return NULL;
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)",
210 hdr3->flags & 0x03);
211 ret->methodState = METHOD_DONE;
212 ret->decision = DECISION_FAIL;
213 return NULL;
215 wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr3->rand_s,
216 EAP_PSK_RAND_LEN);
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);
224 ret->ignore = TRUE;
225 return NULL;
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);
231 if (buf == NULL)
232 return NULL;
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);
236 free(buf);
237 if (memcmp(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) {
238 wpa_printf(MSG_WARNING, "EAP-PSK: Invalid MAC_S in third "
239 "message");
240 ret->methodState = METHOD_DONE;
241 ret->decision = DECISION_FAIL;
242 return NULL;
244 wpa_printf(MSG_DEBUG, "EAP-PSK: MAC_S verified successfully");
246 eap_psk_derive_keys(data->kdk, data->rand_p, data->tek,
247 data->key_data);
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,
250 EAP_PSK_MSK_LEN);
252 memset(nonce, 0, 12);
253 memcpy(nonce + 12, pchannel, 4);
254 pchannel += 4;
255 left -= 4;
257 tag = pchannel;
258 pchannel += 16;
259 left -= 16;
261 msg = pchannel;
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;
272 return NULL;
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");
279 free(decrypted);
280 return NULL;
282 wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message",
283 decrypted, left);
285 /* Verify R flag */
286 switch (decrypted[0] >> 6) {
287 case EAP_PSK_R_FLAG_CONT:
288 wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported");
289 failed = 1;
290 break;
291 case EAP_PSK_R_FLAG_DONE_SUCCESS:
292 wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS");
293 break;
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 "
297 "authentication");
298 failed = 1;
299 break;
302 *respDataLen = sizeof(*hdr4) + 4 + 16 + 1;
303 resp = malloc(*respDataLen + 1);
304 if (resp == NULL) {
305 free(decrypted);
306 return NULL;
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);
317 /* nonce++ */
318 inc_byte_array(nonce, sizeof(nonce));
319 memcpy(rpchannel, nonce + 12, 4);
321 data_len = 1;
322 if (decrypted[0] & EAP_PSK_E_FLAG) {
323 wpa_printf(MSG_DEBUG, "EAP-PSK: Unsupported E (Ext) flag");
324 failed = 1;
325 rpchannel[4 + 16] = (EAP_PSK_R_FLAG_DONE_FAILURE << 6) |
326 EAP_PSK_E_FLAG;
327 if (left > 1) {
328 /* Add empty EXT_Payload with same EXT_Type */
329 (*respDataLen)++;
330 hdr4->length = host_to_be16(*respDataLen);
331 rpchannel[4 + 16 + 1] = decrypted[1];
332 data_len++;
334 } else if (failed)
335 rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_FAILURE << 6;
336 else
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",
347 failed ? "un" : "");
348 data->state = PSK_DONE;
349 ret->methodState = METHOD_DONE;
350 ret->decision = failed ? DECISION_FAIL : DECISION_UNCOND_SUCC;
352 free(decrypted);
354 return resp;
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,
361 size_t *respDataLen)
363 struct eap_psk_data *data = priv;
364 const u8 *pos;
365 u8 *resp = NULL;
366 size_t len;
368 pos = eap_hdr_validate(EAP_TYPE_PSK, reqData, reqDataLen, &len);
369 if (pos == NULL) {
370 ret->ignore = TRUE;
371 return NULL;
373 len += sizeof(struct eap_hdr) + 1;
375 ret->ignore = FALSE;
376 ret->methodState = METHOD_MAY_CONT;
377 ret->decision = DECISION_FAIL;
378 ret->allowNotifications = TRUE;
380 switch (data->state) {
381 case PSK_INIT:
382 resp = eap_psk_process_1(sm, data, ret, reqData, len,
383 respDataLen);
384 break;
385 case PSK_MAC_SENT:
386 resp = eap_psk_process_3(sm, data, ret, reqData, len,
387 respDataLen);
388 break;
389 case PSK_DONE:
390 wpa_printf(MSG_DEBUG, "EAP-PSK: in DONE state - ignore "
391 "unexpected message");
392 ret->ignore = TRUE;
393 return NULL;
396 if (ret->methodState == METHOD_DONE) {
397 ret->allowNotifications = FALSE;
400 return resp;
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;
414 u8 *key;
416 if (data->state != PSK_DONE)
417 return NULL;
419 key = malloc(EAP_PSK_MSK_LEN);
420 if (key == NULL)
421 return NULL;
423 *len = EAP_PSK_MSK_LEN;
424 memcpy(key, data->key_data, EAP_PSK_MSK_LEN);
426 return key;
430 const struct eap_method eap_method_psk =
432 .method = EAP_TYPE_PSK,
433 .name = "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,