2 * WPA Supplicant / EAP-SIM/AKA shared routines
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.
23 #include "eap_sim_common.h"
30 static void eap_sim_prf(const u8 *key, u8 *x, size_t xlen)
38 /* FIPS 186-2 + change notice 1 */
40 memcpy(xkey, key, EAP_SIM_MK_LEN);
41 memset(xkey + EAP_SIM_MK_LEN, 0, 64 - EAP_SIM_MK_LEN);
49 for (j = 0; j < m; j++) {
51 for (i = 0; i < 2; i++) {
52 /* XVAL = (XKEY + XSEED_j) mod 2^b */
54 /* w_i = G(t, XVAL) */
56 sha1_transform((u8 *) _t, xkey);
57 _t[0] = host_to_be32(_t[0]);
58 _t[1] = host_to_be32(_t[1]);
59 _t[2] = host_to_be32(_t[2]);
60 _t[3] = host_to_be32(_t[3]);
61 _t[4] = host_to_be32(_t[4]);
64 /* XKEY = (1 + XKEY + w_i) mod 2^b */
66 for (k = 19; k >= 0; k--) {
67 carry += xkey[k] + xpos[k];
68 xkey[k] = carry & 0xff;
79 void eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk)
82 eap_sim_prf(mk, buf, 120);
84 memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
85 pos += EAP_SIM_K_ENCR_LEN;
86 memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN);
87 pos += EAP_SIM_K_AUT_LEN;
88 memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN);
91 wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_encr",
92 k_encr, EAP_SIM_K_ENCR_LEN);
93 wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_aut",
94 k_aut, EAP_SIM_K_ENCR_LEN);
95 wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MSK",
97 wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Ext. MSK",
98 msk + MSK_LEN, EMSK_LEN);
99 wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material",
100 msk, EAP_SIM_KEYING_DATA_LEN);
104 void eap_sim_derive_keys_reauth(unsigned int _counter,
105 const u8 *identity, size_t identity_len,
106 const u8 *nonce_s, const u8 *mk, u8 *msk)
108 u8 xkey[SHA1_MAC_LEN];
114 len[0] = identity_len;
118 len[2] = EAP_SIM_NONCE_S_LEN;
120 len[3] = EAP_SIM_MK_LEN;
122 counter[0] = _counter >> 8;
123 counter[1] = _counter & 0xff;
125 wpa_printf(MSG_DEBUG, "EAP-SIM: Deriving keying data from reauth");
126 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
127 identity, identity_len);
128 wpa_hexdump(MSG_DEBUG, "EAP-SIM: counter", counter, 2);
129 wpa_hexdump(MSG_DEBUG, "EAP-SIM: NONCE_S", nonce_s,
130 EAP_SIM_NONCE_S_LEN);
131 wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
133 /* XKEY' = SHA1(Identity|counter|NONCE_S|MK) */
134 sha1_vector(4, addr, len, xkey);
135 wpa_hexdump(MSG_DEBUG, "EAP-SIM: XKEY'", xkey, SHA1_MAC_LEN);
137 eap_sim_prf(xkey, msk, EAP_SIM_KEYING_DATA_LEN);
138 wpa_hexdump(MSG_DEBUG, "EAP-SIM: MSK", msk, MSK_LEN);
139 wpa_hexdump(MSG_DEBUG, "EAP-SIM: Ext. MSK", msk + MSK_LEN, EMSK_LEN);
140 wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material",
141 msk, EAP_SIM_KEYING_DATA_LEN);
145 int eap_sim_verify_mac(const u8 *k_aut, u8 *req, size_t req_len, u8 *mac,
146 u8 *extra, size_t extra_len)
148 unsigned char hmac[SHA1_MAC_LEN];
151 u8 rx_mac[EAP_SIM_MAC_LEN];
162 memcpy(rx_mac, mac, EAP_SIM_MAC_LEN);
163 memset(mac, 0, EAP_SIM_MAC_LEN);
164 hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
165 memcpy(mac, rx_mac, EAP_SIM_MAC_LEN);
167 return (memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
171 void eap_sim_add_mac(const u8 *k_aut, u8 *msg, size_t msg_len, u8 *mac,
172 const u8 *extra, size_t extra_len)
174 unsigned char hmac[SHA1_MAC_LEN];
184 memset(mac, 0, EAP_SIM_MAC_LEN);
185 hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
186 memcpy(mac, hmac, EAP_SIM_MAC_LEN);
190 int eap_sim_parse_attr(u8 *start, u8 *end, struct eap_sim_attrs *attr, int aka,
193 u8 *pos = start, *apos;
197 memset(attr, 0, sizeof(*attr));
198 attr->id_req = NO_ID_REQ;
199 attr->notification = -1;
201 attr->selected_version = -1;
202 attr->client_error_code = -1;
206 wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow(1)");
209 wpa_printf(MSG_MSGDUMP, "EAP-SIM: Attribute: Type=%d Len=%d",
211 if (pos + pos[1] * 4 > end) {
212 wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow "
213 "(pos=%p len=%d end=%p)",
214 pos, pos[1] * 4, end);
218 alen = pos[1] * 4 - 2;
219 wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Attribute data",
223 case EAP_SIM_AT_RAND:
224 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RAND");
227 if ((!aka && (alen % GSM_RAND_LEN)) ||
228 (aka && alen != AKA_RAND_LEN)) {
229 wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RAND"
231 (unsigned long) alen);
235 attr->num_chal = alen / GSM_RAND_LEN;
237 case EAP_SIM_AT_AUTN:
238 wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTN");
240 wpa_printf(MSG_DEBUG, "EAP-SIM: "
241 "Unexpected AT_AUTN");
246 if (alen != AKA_AUTN_LEN) {
247 wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTN"
249 (unsigned long) alen);
254 case EAP_SIM_AT_PADDING:
256 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
260 wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_PADDING");
261 for (i = 2; i < alen; i++) {
263 wpa_printf(MSG_INFO, "EAP-SIM: (encr) "
264 "AT_PADDING used a non-zero"
266 wpa_hexdump(MSG_DEBUG, "EAP-SIM: "
267 "(encr) padding bytes",
273 case EAP_SIM_AT_NONCE_MT:
274 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NONCE_MT");
275 if (alen != 2 + EAP_SIM_NONCE_MT_LEN) {
276 wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
277 "AT_NONCE_MT length");
280 attr->nonce_mt = apos + 2;
282 case EAP_SIM_AT_PERMANENT_ID_REQ:
283 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_PERMANENT_ID_REQ");
284 attr->id_req = PERMANENT_ID;
287 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_MAC");
288 if (alen != 2 + EAP_SIM_MAC_LEN) {
289 wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_MAC "
293 attr->mac = apos + 2;
295 case EAP_SIM_AT_NOTIFICATION:
297 wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
298 "AT_NOTIFICATION length %lu",
299 (unsigned long) alen);
302 attr->notification = apos[0] * 256 + apos[1];
303 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NOTIFICATION %d",
306 case EAP_SIM_AT_ANY_ID_REQ:
307 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ANY_ID_REQ");
308 attr->id_req = ANY_ID;
310 case EAP_SIM_AT_IDENTITY:
311 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IDENTITY");
312 attr->identity = apos + 2;
313 attr->identity_len = alen - 2;
315 case EAP_SIM_AT_VERSION_LIST:
317 wpa_printf(MSG_DEBUG, "EAP-AKA: "
318 "Unexpected AT_VERSION_LIST");
321 list_len = apos[0] * 256 + apos[1];
322 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_VERSION_LIST");
323 if (list_len < 2 || list_len > alen - 2) {
324 wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
325 "AT_VERSION_LIST (list_len=%d "
326 "attr_len=%lu)", list_len,
327 (unsigned long) alen);
330 attr->version_list = apos + 2;
331 attr->version_list_len = list_len;
333 case EAP_SIM_AT_SELECTED_VERSION:
334 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION");
336 wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
337 "AT_SELECTED_VERSION length %lu",
338 (unsigned long) alen);
341 attr->selected_version = apos[0] * 256 + apos[1];
342 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION "
343 "%d", attr->selected_version);
345 case EAP_SIM_AT_FULLAUTH_ID_REQ:
346 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_FULLAUTH_ID_REQ");
347 attr->id_req = FULLAUTH_ID;
349 case EAP_SIM_AT_COUNTER:
351 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
356 wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
357 "AT_COUNTER (alen=%lu)",
358 (unsigned long) alen);
361 attr->counter = apos[0] * 256 + apos[1];
362 wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_COUNTER %d",
365 case EAP_SIM_AT_NONCE_S:
367 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
371 wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
373 if (alen != 2 + EAP_SIM_NONCE_S_LEN) {
374 wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
375 "AT_NONCE_S (alen=%lu)",
376 (unsigned long) alen);
379 attr->nonce_s = apos + 2;
381 case EAP_SIM_AT_CLIENT_ERROR_CODE:
383 wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
384 "AT_CLIENT_ERROR_CODE length %lu",
385 (unsigned long) alen);
388 attr->client_error_code = apos[0] * 256 + apos[1];
389 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_CLIENT_ERROR_CODE "
390 "%d", attr->client_error_code);
393 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IV");
394 if (alen != 2 + EAP_SIM_MAC_LEN) {
395 wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_IV "
396 "length %lu", (unsigned long) alen);
401 case EAP_SIM_AT_ENCR_DATA:
402 wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ENCR_DATA");
403 attr->encr_data = apos + 2;
404 attr->encr_data_len = alen - 2;
405 if (attr->encr_data_len % 16) {
406 wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
407 "AT_ENCR_DATA length %lu",
409 attr->encr_data_len);
413 case EAP_SIM_AT_NEXT_PSEUDONYM:
415 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
416 "AT_NEXT_PSEUDONYM");
419 wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
420 "AT_NEXT_PSEUDONYM");
421 plen = apos[0] * 256 + apos[1];
422 if (plen > alen - 2) {
423 wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
424 " AT_NEXT_PSEUDONYM (actual"
425 " len %lu, attr len %lu)",
426 (unsigned long) plen,
427 (unsigned long) alen);
430 attr->next_pseudonym = pos + 4;
431 attr->next_pseudonym_len = plen;
433 case EAP_SIM_AT_NEXT_REAUTH_ID:
435 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
436 "AT_NEXT_REAUTH_ID");
439 wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
440 "AT_NEXT_REAUTH_ID");
441 plen = apos[0] * 256 + apos[1];
442 if (plen > alen - 2) {
443 wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
444 " AT_NEXT_REAUTH_ID (actual"
445 " len %lu, attr len %lu)",
446 (unsigned long) plen,
447 (unsigned long) alen);
450 attr->next_reauth_id = pos + 4;
451 attr->next_reauth_id_len = plen;
455 wpa_printf(MSG_INFO, "EAP-SIM: Unrecognized "
456 "non-skippable attribute %d",
461 wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized skippable"
462 " attribute %d ignored", pos[0]);
469 wpa_printf(MSG_DEBUG, "EAP-SIM: Attributes parsed successfully "
470 "(aka=%d encr=%d)", aka, encr);
476 int eap_sim_parse_encr(const u8 *k_encr, u8 *encr_data, size_t encr_data_len,
477 const u8 *iv, struct eap_sim_attrs *attr, int aka)
480 wpa_printf(MSG_INFO, "EAP-SIM: Encrypted data, but no IV");
483 aes_128_cbc_decrypt(k_encr, iv, encr_data, encr_data_len);
484 wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA",
485 encr_data, encr_data_len);
487 if (eap_sim_parse_attr(encr_data, encr_data + encr_data_len, attr,
489 wpa_printf(MSG_INFO, "EAP-SIM: (encr) Failed to parse "
490 "decrypted AT_ENCR_DATA");
498 #define EAP_SIM_INIT_LEN 128
502 size_t buf_len, used;
503 size_t mac, iv, encr; /* index from buf */
507 struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype)
509 struct eap_sim_msg *msg;
513 msg = malloc(sizeof(*msg));
516 memset(msg, 0, sizeof(*msg));
518 msg->buf = malloc(EAP_SIM_INIT_LEN);
519 if (msg->buf == NULL) {
523 memset(msg->buf, 0, EAP_SIM_INIT_LEN);
524 msg->buf_len = EAP_SIM_INIT_LEN;
525 eap = (struct eap_hdr *) msg->buf;
527 eap->identifier = id;
528 msg->used = sizeof(*eap);
530 pos = (u8 *) (eap + 1);
533 *pos++ = 0; /* Reserved */
534 *pos++ = 0; /* Reserved */
541 u8 * eap_sim_msg_finish(struct eap_sim_msg *msg, size_t *len, const u8 *k_aut,
542 const u8 *extra, size_t extra_len)
550 eap = (struct eap_hdr *) msg->buf;
551 eap->length = host_to_be16(msg->used);
553 if (k_aut && msg->mac) {
554 eap_sim_add_mac(k_aut, msg->buf, msg->used,
555 msg->buf + msg->mac, extra, extra_len);
565 void eap_sim_msg_free(struct eap_sim_msg *msg)
574 static int eap_sim_msg_resize(struct eap_sim_msg *msg, size_t add_len)
576 if (msg->used + add_len > msg->buf_len) {
577 u8 *nbuf = realloc(msg->buf, msg->used + add_len);
581 msg->buf_len = msg->used + add_len;
587 u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr,
588 const u8 *data, size_t len)
590 int attr_len = 2 + len;
597 pad_len = (4 - attr_len % 4) % 4;
599 if (eap_sim_msg_resize(msg, attr_len))
601 start = pos = msg->buf + msg->used;
603 *pos++ = attr_len / 4;
604 memcpy(pos, data, len);
607 memset(pos, 0, pad_len);
609 msg->used += attr_len;
614 u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, u16 value,
615 const u8 *data, size_t len)
617 int attr_len = 4 + len;
624 pad_len = (4 - attr_len % 4) % 4;
626 if (eap_sim_msg_resize(msg, attr_len))
628 start = pos = msg->buf + msg->used;
630 *pos++ = attr_len / 4;
632 *pos++ = value & 0xff;
634 memcpy(pos, data, len);
637 memset(pos, 0, pad_len);
639 msg->used += attr_len;
644 u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr)
646 u8 *pos = eap_sim_msg_add(msg, attr, 0, NULL, EAP_SIM_MAC_LEN);
648 msg->mac = (pos - msg->buf) + 4;
653 int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv,
656 u8 *pos = eap_sim_msg_add(msg, attr_iv, 0, NULL, EAP_SIM_IV_LEN);
659 msg->iv = (pos - msg->buf) + 4;
660 if (hostapd_get_rand(msg->buf + msg->iv, EAP_SIM_IV_LEN)) {
665 pos = eap_sim_msg_add(msg, attr_encr, 0, NULL, 0);
670 msg->encr = pos - msg->buf;
676 int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, int attr_pad)
680 if (k_encr == NULL || msg->iv == 0 || msg->encr == 0)
683 encr_len = msg->used - msg->encr - 4;
686 int pad_len = 16 - (encr_len % 16);
688 wpa_printf(MSG_WARNING, "EAP-SIM: "
689 "eap_sim_msg_add_encr_end - invalid pad_len"
693 wpa_printf(MSG_DEBUG, " *AT_PADDING");
694 pos = eap_sim_msg_add(msg, attr_pad, 0, NULL, pad_len - 4);
697 memset(pos + 4, 0, pad_len - 4);
700 wpa_printf(MSG_DEBUG, " (AT_ENCR_DATA data len %lu)",
701 (unsigned long) encr_len);
702 msg->buf[msg->encr + 1] = encr_len / 4 + 1;
703 aes_128_cbc_encrypt(k_encr, msg->buf + msg->iv,
704 msg->buf + msg->encr + 4, encr_len);
710 void eap_sim_report_notification(void *msg_ctx, int notification, int aka)
712 const char *type = aka ? "AKA" : "SIM";
714 switch (notification) {
715 case EAP_SIM_GENERAL_FAILURE_AFTER_AUTH:
716 wpa_printf(MSG_WARNING, "EAP-%s: General failure "
717 "notification (after authentication)", type);
719 case EAP_SIM_TEMPORARILY_DENIED:
720 wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
721 "User has been temporarily denied access to the "
722 "requested service", type);
724 case EAP_SIM_NOT_SUBSCRIBED:
725 wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
726 "User has not subscribed to the requested service",
729 case EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH:
730 wpa_printf(MSG_WARNING, "EAP-%s: General failure "
731 "notification (before authentication)", type);
733 case EAP_SIM_SUCCESS:
734 wpa_printf(MSG_INFO, "EAP-%s: Successful authentication "
735 "notification", type);
738 if (notification >= 32768) {
739 wpa_printf(MSG_INFO, "EAP-%s: Unrecognized "
740 "non-failure notification %d",
743 wpa_printf(MSG_WARNING, "EAP-%s: Unrecognized "
744 "failure notification %d",
751 #ifdef TEST_MAIN_EAP_SIM_COMMON
752 static int test_eap_sim_prf(void)
754 /* http://csrc.nist.gov/encryption/dss/Examples-1024bit.pdf */
756 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b,
757 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f,
758 0xeb, 0x5a, 0x38, 0xb6
761 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f,
762 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49,
763 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba,
764 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78,
765 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16
769 printf("Testing EAP-SIM PRF (FIPS 186-2 + change notice 1)\n");
770 eap_sim_prf(xkey, buf, sizeof(buf));
771 if (memcmp(w, buf, sizeof(w) != 0)) {
772 printf("eap_sim_prf failed\n");
780 int main(int argc, char *argv[])
784 errors += test_eap_sim_prf();
788 #endif /* TEST_MAIN_EAP_SIM_COMMON */