2 * EAP peer method: EAP-SIM (RFC 4186)
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.
18 #include "pcsc_funcs.h"
19 #include "crypto/milenage.h"
20 #include "eap_peer/eap_i.h"
21 #include "eap_config.h"
22 #include "eap_common/eap_sim_common.h"
29 size_t min_num_chal
, num_chal
;
31 u8 kc
[3][EAP_SIM_KC_LEN
];
32 u8 sres
[3][EAP_SIM_SRES_LEN
];
33 u8 nonce_mt
[EAP_SIM_NONCE_MT_LEN
], nonce_s
[EAP_SIM_NONCE_S_LEN
];
34 u8 mk
[EAP_SIM_MK_LEN
];
35 u8 k_aut
[EAP_SIM_K_AUT_LEN
];
36 u8 k_encr
[EAP_SIM_K_ENCR_LEN
];
37 u8 msk
[EAP_SIM_KEYING_DATA_LEN
];
38 u8 emsk
[EAP_EMSK_LEN
];
39 u8 rand
[3][GSM_RAND_LEN
];
41 int num_id_req
, num_notification
;
47 unsigned int counter
, counter_too_small
;
48 u8
*last_eap_identity
;
49 size_t last_eap_identity_len
;
51 CONTINUE
, RESULT_SUCCESS
, RESULT_FAILURE
, SUCCESS
, FAILURE
53 int result_ind
, use_result_ind
;
57 #ifndef CONFIG_NO_STDOUT_DEBUG
58 static const char * eap_sim_state_txt(int state
)
64 return "RESULT_SUCCESS";
66 return "RESULT_FAILURE";
75 #endif /* CONFIG_NO_STDOUT_DEBUG */
78 static void eap_sim_state(struct eap_sim_data
*data
, int state
)
80 wpa_printf(MSG_DEBUG
, "EAP-SIM: %s -> %s",
81 eap_sim_state_txt(data
->state
),
82 eap_sim_state_txt(state
));
87 static void * eap_sim_init(struct eap_sm
*sm
)
89 struct eap_sim_data
*data
;
90 struct eap_peer_config
*config
= eap_get_config(sm
);
92 data
= os_zalloc(sizeof(*data
));
96 if (os_get_random(data
->nonce_mt
, EAP_SIM_NONCE_MT_LEN
)) {
97 wpa_printf(MSG_WARNING
, "EAP-SIM: Failed to get random data "
103 data
->min_num_chal
= 2;
104 if (config
&& config
->phase1
) {
105 char *pos
= os_strstr(config
->phase1
, "sim_min_num_chal=");
107 data
->min_num_chal
= atoi(pos
+ 17);
108 if (data
->min_num_chal
< 2 || data
->min_num_chal
> 3) {
109 wpa_printf(MSG_WARNING
, "EAP-SIM: Invalid "
110 "sim_min_num_chal configuration "
111 "(%lu, expected 2 or 3)",
112 (unsigned long) data
->min_num_chal
);
116 wpa_printf(MSG_DEBUG
, "EAP-SIM: Set minimum number of "
118 (unsigned long) data
->min_num_chal
);
121 data
->result_ind
= os_strstr(config
->phase1
, "result_ind=1") !=
125 eap_sim_state(data
, CONTINUE
);
131 static void eap_sim_deinit(struct eap_sm
*sm
, void *priv
)
133 struct eap_sim_data
*data
= priv
;
135 os_free(data
->ver_list
);
136 os_free(data
->pseudonym
);
137 os_free(data
->reauth_id
);
138 os_free(data
->last_eap_identity
);
144 static int eap_sim_gsm_auth(struct eap_sm
*sm
, struct eap_sim_data
*data
)
146 struct eap_peer_config
*conf
;
148 wpa_printf(MSG_DEBUG
, "EAP-SIM: GSM authentication algorithm");
150 conf
= eap_get_config(sm
);
154 if (scard_gsm_auth(sm
->scard_ctx
, data
->rand
[0],
155 data
->sres
[0], data
->kc
[0]) ||
156 scard_gsm_auth(sm
->scard_ctx
, data
->rand
[1],
157 data
->sres
[1], data
->kc
[1]) ||
158 (data
->num_chal
> 2 &&
159 scard_gsm_auth(sm
->scard_ctx
, data
->rand
[2],
160 data
->sres
[2], data
->kc
[2]))) {
161 wpa_printf(MSG_DEBUG
, "EAP-SIM: GSM SIM "
162 "authentication could not be completed");
168 #ifdef CONFIG_SIM_SIMULATOR
169 if (conf
->password
) {
173 wpa_printf(MSG_DEBUG
, "EAP-SIM: Use internal GSM-Milenage "
174 "implementation for authentication");
175 if (conf
->password_len
< 65) {
176 wpa_printf(MSG_DEBUG
, "EAP-SIM: invalid GSM-Milenage "
180 pos
= (const char *) conf
->password
;
181 if (hexstr2bin(pos
, k
, 16))
188 if (hexstr2bin(pos
, opc
, 16))
191 for (i
= 0; i
< data
->num_chal
; i
++) {
192 if (gsm_milenage(opc
, k
, data
->rand
[i
],
193 data
->sres
[i
], data
->kc
[i
])) {
194 wpa_printf(MSG_DEBUG
, "EAP-SIM: "
195 "GSM-Milenage authentication "
196 "could not be completed");
199 wpa_hexdump(MSG_DEBUG
, "EAP-SIM: RAND",
200 data
->rand
[i
], GSM_RAND_LEN
);
201 wpa_hexdump_key(MSG_DEBUG
, "EAP-SIM: SRES",
202 data
->sres
[i
], EAP_SIM_SRES_LEN
);
203 wpa_hexdump_key(MSG_DEBUG
, "EAP-SIM: Kc",
204 data
->kc
[i
], EAP_SIM_KC_LEN
);
208 #endif /* CONFIG_SIM_SIMULATOR */
210 #ifdef CONFIG_SIM_HARDCODED
211 /* These hardcoded Kc and SRES values are used for testing. RAND to
212 * KC/SREC mapping is very bogus as far as real authentication is
213 * concerned, but it is quite useful for cases where the AS is rotating
214 * the order of pre-configured values. */
218 wpa_printf(MSG_DEBUG
, "EAP-SIM: Use hardcoded Kc and SRES "
219 "values for testing");
221 for (i
= 0; i
< data
->num_chal
; i
++) {
222 if (data
->rand
[i
][0] == 0xaa) {
223 os_memcpy(data
->kc
[i
],
224 "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7",
226 os_memcpy(data
->sres
[i
], "\xd1\xd2\xd3\xd4",
228 } else if (data
->rand
[i
][0] == 0xbb) {
229 os_memcpy(data
->kc
[i
],
230 "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7",
232 os_memcpy(data
->sres
[i
], "\xe1\xe2\xe3\xe4",
235 os_memcpy(data
->kc
[i
],
236 "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7",
238 os_memcpy(data
->sres
[i
], "\xf1\xf2\xf3\xf4",
246 #else /* CONFIG_SIM_HARDCODED */
248 wpa_printf(MSG_DEBUG
, "EAP-SIM: No GSM authentication algorithm "
252 #endif /* CONFIG_SIM_HARDCODED */
256 static int eap_sim_supported_ver(int version
)
258 return version
== EAP_SIM_VERSION
;
262 #define CLEAR_PSEUDONYM 0x01
263 #define CLEAR_REAUTH_ID 0x02
264 #define CLEAR_EAP_ID 0x04
266 static void eap_sim_clear_identities(struct eap_sim_data
*data
, int id
)
268 wpa_printf(MSG_DEBUG
, "EAP-SIM: forgetting old%s%s%s",
269 id
& CLEAR_PSEUDONYM
? " pseudonym" : "",
270 id
& CLEAR_REAUTH_ID
? " reauth_id" : "",
271 id
& CLEAR_EAP_ID
? " eap_id" : "");
272 if (id
& CLEAR_PSEUDONYM
) {
273 os_free(data
->pseudonym
);
274 data
->pseudonym
= NULL
;
275 data
->pseudonym_len
= 0;
277 if (id
& CLEAR_REAUTH_ID
) {
278 os_free(data
->reauth_id
);
279 data
->reauth_id
= NULL
;
280 data
->reauth_id_len
= 0;
282 if (id
& CLEAR_EAP_ID
) {
283 os_free(data
->last_eap_identity
);
284 data
->last_eap_identity
= NULL
;
285 data
->last_eap_identity_len
= 0;
290 static int eap_sim_learn_ids(struct eap_sim_data
*data
,
291 struct eap_sim_attrs
*attr
)
293 if (attr
->next_pseudonym
) {
294 os_free(data
->pseudonym
);
295 data
->pseudonym
= os_malloc(attr
->next_pseudonym_len
);
296 if (data
->pseudonym
== NULL
) {
297 wpa_printf(MSG_INFO
, "EAP-SIM: (encr) No memory for "
301 os_memcpy(data
->pseudonym
, attr
->next_pseudonym
,
302 attr
->next_pseudonym_len
);
303 data
->pseudonym_len
= attr
->next_pseudonym_len
;
304 wpa_hexdump_ascii(MSG_DEBUG
,
305 "EAP-SIM: (encr) AT_NEXT_PSEUDONYM",
307 data
->pseudonym_len
);
310 if (attr
->next_reauth_id
) {
311 os_free(data
->reauth_id
);
312 data
->reauth_id
= os_malloc(attr
->next_reauth_id_len
);
313 if (data
->reauth_id
== NULL
) {
314 wpa_printf(MSG_INFO
, "EAP-SIM: (encr) No memory for "
318 os_memcpy(data
->reauth_id
, attr
->next_reauth_id
,
319 attr
->next_reauth_id_len
);
320 data
->reauth_id_len
= attr
->next_reauth_id_len
;
321 wpa_hexdump_ascii(MSG_DEBUG
,
322 "EAP-SIM: (encr) AT_NEXT_REAUTH_ID",
324 data
->reauth_id_len
);
331 static struct wpabuf
* eap_sim_client_error(struct eap_sim_data
*data
, u8 id
,
334 struct eap_sim_msg
*msg
;
336 eap_sim_state(data
, FAILURE
);
337 data
->num_id_req
= 0;
338 data
->num_notification
= 0;
340 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, id
, EAP_TYPE_SIM
,
341 EAP_SIM_SUBTYPE_CLIENT_ERROR
);
342 eap_sim_msg_add(msg
, EAP_SIM_AT_CLIENT_ERROR_CODE
, err
, NULL
, 0);
343 return eap_sim_msg_finish(msg
, NULL
, NULL
, 0);
347 static struct wpabuf
* eap_sim_response_start(struct eap_sm
*sm
,
348 struct eap_sim_data
*data
, u8 id
,
349 enum eap_sim_id_req id_req
)
351 const u8
*identity
= NULL
;
352 size_t identity_len
= 0;
353 struct eap_sim_msg
*msg
;
356 if (id_req
== ANY_ID
&& data
->reauth_id
) {
357 identity
= data
->reauth_id
;
358 identity_len
= data
->reauth_id_len
;
360 } else if ((id_req
== ANY_ID
|| id_req
== FULLAUTH_ID
) &&
362 identity
= data
->pseudonym
;
363 identity_len
= data
->pseudonym_len
;
364 eap_sim_clear_identities(data
, CLEAR_REAUTH_ID
);
365 } else if (id_req
!= NO_ID_REQ
) {
366 identity
= eap_get_config_identity(sm
, &identity_len
);
368 eap_sim_clear_identities(data
, CLEAR_PSEUDONYM
|
372 if (id_req
!= NO_ID_REQ
)
373 eap_sim_clear_identities(data
, CLEAR_EAP_ID
);
375 wpa_printf(MSG_DEBUG
, "Generating EAP-SIM Start (id=%d)", id
);
376 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, id
,
377 EAP_TYPE_SIM
, EAP_SIM_SUBTYPE_START
);
379 wpa_hexdump(MSG_DEBUG
, " AT_NONCE_MT",
380 data
->nonce_mt
, EAP_SIM_NONCE_MT_LEN
);
381 eap_sim_msg_add(msg
, EAP_SIM_AT_NONCE_MT
, 0,
382 data
->nonce_mt
, EAP_SIM_NONCE_MT_LEN
);
383 wpa_printf(MSG_DEBUG
, " AT_SELECTED_VERSION %d",
384 data
->selected_version
);
385 eap_sim_msg_add(msg
, EAP_SIM_AT_SELECTED_VERSION
,
386 data
->selected_version
, NULL
, 0);
390 wpa_hexdump_ascii(MSG_DEBUG
, " AT_IDENTITY",
391 identity
, identity_len
);
392 eap_sim_msg_add(msg
, EAP_SIM_AT_IDENTITY
, identity_len
,
393 identity
, identity_len
);
396 return eap_sim_msg_finish(msg
, NULL
, NULL
, 0);
400 static struct wpabuf
* eap_sim_response_challenge(struct eap_sim_data
*data
,
403 struct eap_sim_msg
*msg
;
405 wpa_printf(MSG_DEBUG
, "Generating EAP-SIM Challenge (id=%d)", id
);
406 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, id
, EAP_TYPE_SIM
,
407 EAP_SIM_SUBTYPE_CHALLENGE
);
408 if (data
->use_result_ind
) {
409 wpa_printf(MSG_DEBUG
, " AT_RESULT_IND");
410 eap_sim_msg_add(msg
, EAP_SIM_AT_RESULT_IND
, 0, NULL
, 0);
412 wpa_printf(MSG_DEBUG
, " AT_MAC");
413 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
414 return eap_sim_msg_finish(msg
, data
->k_aut
, (u8
*) data
->sres
,
415 data
->num_chal
* EAP_SIM_SRES_LEN
);
419 static struct wpabuf
* eap_sim_response_reauth(struct eap_sim_data
*data
,
420 u8 id
, int counter_too_small
)
422 struct eap_sim_msg
*msg
;
423 unsigned int counter
;
425 wpa_printf(MSG_DEBUG
, "Generating EAP-SIM Reauthentication (id=%d)",
427 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, id
, EAP_TYPE_SIM
,
428 EAP_SIM_SUBTYPE_REAUTHENTICATION
);
429 wpa_printf(MSG_DEBUG
, " AT_IV");
430 wpa_printf(MSG_DEBUG
, " AT_ENCR_DATA");
431 eap_sim_msg_add_encr_start(msg
, EAP_SIM_AT_IV
, EAP_SIM_AT_ENCR_DATA
);
433 if (counter_too_small
) {
434 wpa_printf(MSG_DEBUG
, " *AT_COUNTER_TOO_SMALL");
435 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER_TOO_SMALL
, 0, NULL
, 0);
436 counter
= data
->counter_too_small
;
438 counter
= data
->counter
;
440 wpa_printf(MSG_DEBUG
, " *AT_COUNTER %d", counter
);
441 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER
, counter
, NULL
, 0);
443 if (eap_sim_msg_add_encr_end(msg
, data
->k_encr
, EAP_SIM_AT_PADDING
)) {
444 wpa_printf(MSG_WARNING
, "EAP-SIM: Failed to encrypt "
446 eap_sim_msg_free(msg
);
449 if (data
->use_result_ind
) {
450 wpa_printf(MSG_DEBUG
, " AT_RESULT_IND");
451 eap_sim_msg_add(msg
, EAP_SIM_AT_RESULT_IND
, 0, NULL
, 0);
453 wpa_printf(MSG_DEBUG
, " AT_MAC");
454 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
455 return eap_sim_msg_finish(msg
, data
->k_aut
, data
->nonce_s
,
456 EAP_SIM_NONCE_S_LEN
);
460 static struct wpabuf
* eap_sim_response_notification(struct eap_sim_data
*data
,
461 u8 id
, u16 notification
)
463 struct eap_sim_msg
*msg
;
464 u8
*k_aut
= (notification
& 0x4000) == 0 ? data
->k_aut
: NULL
;
466 wpa_printf(MSG_DEBUG
, "Generating EAP-SIM Notification (id=%d)", id
);
467 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, id
,
468 EAP_TYPE_SIM
, EAP_SIM_SUBTYPE_NOTIFICATION
);
469 if (k_aut
&& data
->reauth
) {
470 wpa_printf(MSG_DEBUG
, " AT_IV");
471 wpa_printf(MSG_DEBUG
, " AT_ENCR_DATA");
472 eap_sim_msg_add_encr_start(msg
, EAP_SIM_AT_IV
,
473 EAP_SIM_AT_ENCR_DATA
);
474 wpa_printf(MSG_DEBUG
, " *AT_COUNTER %d", data
->counter
);
475 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER
, data
->counter
,
477 if (eap_sim_msg_add_encr_end(msg
, data
->k_encr
,
478 EAP_SIM_AT_PADDING
)) {
479 wpa_printf(MSG_WARNING
, "EAP-SIM: Failed to encrypt "
481 eap_sim_msg_free(msg
);
486 wpa_printf(MSG_DEBUG
, " AT_MAC");
487 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
489 return eap_sim_msg_finish(msg
, k_aut
, (u8
*) "", 0);
493 static struct wpabuf
* eap_sim_process_start(struct eap_sm
*sm
,
494 struct eap_sim_data
*data
, u8 id
,
495 struct eap_sim_attrs
*attr
)
497 int selected_version
= -1, id_error
;
501 wpa_printf(MSG_DEBUG
, "EAP-SIM: subtype Start");
502 if (attr
->version_list
== NULL
) {
503 wpa_printf(MSG_INFO
, "EAP-SIM: No AT_VERSION_LIST in "
505 return eap_sim_client_error(data
, id
,
506 EAP_SIM_UNSUPPORTED_VERSION
);
509 os_free(data
->ver_list
);
510 data
->ver_list
= os_malloc(attr
->version_list_len
);
511 if (data
->ver_list
== NULL
) {
512 wpa_printf(MSG_DEBUG
, "EAP-SIM: Failed to allocate "
513 "memory for version list");
514 return eap_sim_client_error(data
, id
,
515 EAP_SIM_UNABLE_TO_PROCESS_PACKET
);
517 os_memcpy(data
->ver_list
, attr
->version_list
, attr
->version_list_len
);
518 data
->ver_list_len
= attr
->version_list_len
;
519 pos
= data
->ver_list
;
520 for (i
= 0; i
< data
->ver_list_len
/ 2; i
++) {
521 int ver
= pos
[0] * 256 + pos
[1];
523 if (eap_sim_supported_ver(ver
)) {
524 selected_version
= ver
;
528 if (selected_version
< 0) {
529 wpa_printf(MSG_INFO
, "EAP-SIM: Could not find a supported "
531 return eap_sim_client_error(data
, id
,
532 EAP_SIM_UNSUPPORTED_VERSION
);
534 wpa_printf(MSG_DEBUG
, "EAP-SIM: Selected Version %d",
536 data
->selected_version
= selected_version
;
539 switch (attr
->id_req
) {
543 if (data
->num_id_req
> 0)
548 if (data
->num_id_req
> 1)
553 if (data
->num_id_req
> 2)
559 wpa_printf(MSG_INFO
, "EAP-SIM: Too many ID requests "
560 "used within one authentication");
561 return eap_sim_client_error(data
, id
,
562 EAP_SIM_UNABLE_TO_PROCESS_PACKET
);
565 return eap_sim_response_start(sm
, data
, id
, attr
->id_req
);
569 static struct wpabuf
* eap_sim_process_challenge(struct eap_sm
*sm
,
570 struct eap_sim_data
*data
,
572 const struct wpabuf
*reqData
,
573 struct eap_sim_attrs
*attr
)
577 struct eap_sim_attrs eattr
;
579 wpa_printf(MSG_DEBUG
, "EAP-SIM: subtype Challenge");
581 if (!attr
->mac
|| !attr
->rand
) {
582 wpa_printf(MSG_WARNING
, "EAP-SIM: Challenge message "
583 "did not include%s%s",
584 !attr
->mac
? " AT_MAC" : "",
585 !attr
->rand
? " AT_RAND" : "");
586 return eap_sim_client_error(data
, id
,
587 EAP_SIM_UNABLE_TO_PROCESS_PACKET
);
590 wpa_printf(MSG_DEBUG
, "EAP-SIM: %lu challenges",
591 (unsigned long) attr
->num_chal
);
592 if (attr
->num_chal
< data
->min_num_chal
) {
593 wpa_printf(MSG_INFO
, "EAP-SIM: Insufficient number of "
594 "challenges (%lu)", (unsigned long) attr
->num_chal
);
595 return eap_sim_client_error(data
, id
,
596 EAP_SIM_INSUFFICIENT_NUM_OF_CHAL
);
598 if (attr
->num_chal
> 3) {
599 wpa_printf(MSG_INFO
, "EAP-SIM: Too many challenges "
600 "(%lu)", (unsigned long) attr
->num_chal
);
601 return eap_sim_client_error(data
, id
,
602 EAP_SIM_UNABLE_TO_PROCESS_PACKET
);
605 /* Verify that RANDs are different */
606 if (os_memcmp(attr
->rand
, attr
->rand
+ GSM_RAND_LEN
,
607 GSM_RAND_LEN
) == 0 ||
608 (attr
->num_chal
> 2 &&
609 (os_memcmp(attr
->rand
, attr
->rand
+ 2 * GSM_RAND_LEN
,
610 GSM_RAND_LEN
) == 0 ||
611 os_memcmp(attr
->rand
+ GSM_RAND_LEN
,
612 attr
->rand
+ 2 * GSM_RAND_LEN
,
613 GSM_RAND_LEN
) == 0))) {
614 wpa_printf(MSG_INFO
, "EAP-SIM: Same RAND used multiple times");
615 return eap_sim_client_error(data
, id
,
616 EAP_SIM_RAND_NOT_FRESH
);
619 os_memcpy(data
->rand
, attr
->rand
, attr
->num_chal
* GSM_RAND_LEN
);
620 data
->num_chal
= attr
->num_chal
;
622 if (eap_sim_gsm_auth(sm
, data
)) {
623 wpa_printf(MSG_WARNING
, "EAP-SIM: GSM authentication failed");
624 return eap_sim_client_error(data
, id
,
625 EAP_SIM_UNABLE_TO_PROCESS_PACKET
);
627 if (data
->last_eap_identity
) {
628 identity
= data
->last_eap_identity
;
629 identity_len
= data
->last_eap_identity_len
;
630 } else if (data
->pseudonym
) {
631 identity
= data
->pseudonym
;
632 identity_len
= data
->pseudonym_len
;
634 identity
= eap_get_config_identity(sm
, &identity_len
);
635 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-SIM: Selected identity for MK "
636 "derivation", identity
, identity_len
);
637 eap_sim_derive_mk(identity
, identity_len
, data
->nonce_mt
,
638 data
->selected_version
, data
->ver_list
,
639 data
->ver_list_len
, data
->num_chal
,
640 (const u8
*) data
->kc
, data
->mk
);
641 eap_sim_derive_keys(data
->mk
, data
->k_encr
, data
->k_aut
, data
->msk
,
643 if (eap_sim_verify_mac(data
->k_aut
, reqData
, attr
->mac
, data
->nonce_mt
,
644 EAP_SIM_NONCE_MT_LEN
)) {
645 wpa_printf(MSG_WARNING
, "EAP-SIM: Challenge message "
646 "used invalid AT_MAC");
647 return eap_sim_client_error(data
, id
,
648 EAP_SIM_UNABLE_TO_PROCESS_PACKET
);
651 /* Old reauthentication and pseudonym identities must not be used
652 * anymore. In other words, if no new identities are received, full
653 * authentication will be used on next reauthentication. */
654 eap_sim_clear_identities(data
, CLEAR_PSEUDONYM
| CLEAR_REAUTH_ID
|
657 if (attr
->encr_data
) {
659 decrypted
= eap_sim_parse_encr(data
->k_encr
, attr
->encr_data
,
660 attr
->encr_data_len
, attr
->iv
,
662 if (decrypted
== NULL
) {
663 return eap_sim_client_error(
664 data
, id
, EAP_SIM_UNABLE_TO_PROCESS_PACKET
);
666 eap_sim_learn_ids(data
, &eattr
);
670 if (data
->result_ind
&& attr
->result_ind
)
671 data
->use_result_ind
= 1;
673 if (data
->state
!= FAILURE
&& data
->state
!= RESULT_FAILURE
) {
674 eap_sim_state(data
, data
->use_result_ind
?
675 RESULT_SUCCESS
: SUCCESS
);
678 data
->num_id_req
= 0;
679 data
->num_notification
= 0;
680 /* RFC 4186 specifies that counter is initialized to one after
681 * fullauth, but initializing it to zero makes it easier to implement
682 * reauth verification. */
684 return eap_sim_response_challenge(data
, id
);
688 static int eap_sim_process_notification_reauth(struct eap_sim_data
*data
,
689 struct eap_sim_attrs
*attr
)
691 struct eap_sim_attrs eattr
;
694 if (attr
->encr_data
== NULL
|| attr
->iv
== NULL
) {
695 wpa_printf(MSG_WARNING
, "EAP-SIM: Notification message after "
696 "reauth did not include encrypted data");
700 decrypted
= eap_sim_parse_encr(data
->k_encr
, attr
->encr_data
,
701 attr
->encr_data_len
, attr
->iv
, &eattr
,
703 if (decrypted
== NULL
) {
704 wpa_printf(MSG_WARNING
, "EAP-SIM: Failed to parse encrypted "
705 "data from notification message");
709 if (eattr
.counter
< 0 || (size_t) eattr
.counter
!= data
->counter
) {
710 wpa_printf(MSG_WARNING
, "EAP-SIM: Counter in notification "
711 "message does not match with counter in reauth "
722 static int eap_sim_process_notification_auth(struct eap_sim_data
*data
,
723 const struct wpabuf
*reqData
,
724 struct eap_sim_attrs
*attr
)
726 if (attr
->mac
== NULL
) {
727 wpa_printf(MSG_INFO
, "EAP-SIM: no AT_MAC in after_auth "
728 "Notification message");
732 if (eap_sim_verify_mac(data
->k_aut
, reqData
, attr
->mac
, (u8
*) "", 0))
734 wpa_printf(MSG_WARNING
, "EAP-SIM: Notification message "
735 "used invalid AT_MAC");
740 eap_sim_process_notification_reauth(data
, attr
)) {
741 wpa_printf(MSG_WARNING
, "EAP-SIM: Invalid notification "
742 "message after reauth");
750 static struct wpabuf
* eap_sim_process_notification(
751 struct eap_sm
*sm
, struct eap_sim_data
*data
, u8 id
,
752 const struct wpabuf
*reqData
, struct eap_sim_attrs
*attr
)
754 wpa_printf(MSG_DEBUG
, "EAP-SIM: subtype Notification");
755 if (data
->num_notification
> 0) {
756 wpa_printf(MSG_INFO
, "EAP-SIM: too many notification "
757 "rounds (only one allowed)");
758 return eap_sim_client_error(data
, id
,
759 EAP_SIM_UNABLE_TO_PROCESS_PACKET
);
761 data
->num_notification
++;
762 if (attr
->notification
== -1) {
763 wpa_printf(MSG_INFO
, "EAP-SIM: no AT_NOTIFICATION in "
764 "Notification message");
765 return eap_sim_client_error(data
, id
,
766 EAP_SIM_UNABLE_TO_PROCESS_PACKET
);
769 if ((attr
->notification
& 0x4000) == 0 &&
770 eap_sim_process_notification_auth(data
, reqData
, attr
)) {
771 return eap_sim_client_error(data
, id
,
772 EAP_SIM_UNABLE_TO_PROCESS_PACKET
);
775 eap_sim_report_notification(sm
->msg_ctx
, attr
->notification
, 0);
776 if (attr
->notification
>= 0 && attr
->notification
< 32768) {
777 eap_sim_state(data
, FAILURE
);
778 } else if (attr
->notification
== EAP_SIM_SUCCESS
&&
779 data
->state
== RESULT_SUCCESS
)
780 eap_sim_state(data
, SUCCESS
);
781 return eap_sim_response_notification(data
, id
, attr
->notification
);
785 static struct wpabuf
* eap_sim_process_reauthentication(
786 struct eap_sm
*sm
, struct eap_sim_data
*data
, u8 id
,
787 const struct wpabuf
*reqData
, struct eap_sim_attrs
*attr
)
789 struct eap_sim_attrs eattr
;
792 wpa_printf(MSG_DEBUG
, "EAP-SIM: subtype Reauthentication");
794 if (data
->reauth_id
== NULL
) {
795 wpa_printf(MSG_WARNING
, "EAP-SIM: Server is trying "
796 "reauthentication, but no reauth_id available");
797 return eap_sim_client_error(data
, id
,
798 EAP_SIM_UNABLE_TO_PROCESS_PACKET
);
802 if (eap_sim_verify_mac(data
->k_aut
, reqData
, attr
->mac
, (u8
*) "", 0))
804 wpa_printf(MSG_WARNING
, "EAP-SIM: Reauthentication "
805 "did not have valid AT_MAC");
806 return eap_sim_client_error(data
, id
,
807 EAP_SIM_UNABLE_TO_PROCESS_PACKET
);
810 if (attr
->encr_data
== NULL
|| attr
->iv
== NULL
) {
811 wpa_printf(MSG_WARNING
, "EAP-SIM: Reauthentication "
812 "message did not include encrypted data");
813 return eap_sim_client_error(data
, id
,
814 EAP_SIM_UNABLE_TO_PROCESS_PACKET
);
817 decrypted
= eap_sim_parse_encr(data
->k_encr
, attr
->encr_data
,
818 attr
->encr_data_len
, attr
->iv
, &eattr
,
820 if (decrypted
== NULL
) {
821 wpa_printf(MSG_WARNING
, "EAP-SIM: Failed to parse encrypted "
822 "data from reauthentication message");
823 return eap_sim_client_error(data
, id
,
824 EAP_SIM_UNABLE_TO_PROCESS_PACKET
);
827 if (eattr
.nonce_s
== NULL
|| eattr
.counter
< 0) {
828 wpa_printf(MSG_INFO
, "EAP-SIM: (encr) No%s%s in reauth packet",
829 !eattr
.nonce_s
? " AT_NONCE_S" : "",
830 eattr
.counter
< 0 ? " AT_COUNTER" : "");
832 return eap_sim_client_error(data
, id
,
833 EAP_SIM_UNABLE_TO_PROCESS_PACKET
);
836 if (eattr
.counter
< 0 || (size_t) eattr
.counter
<= data
->counter
) {
837 wpa_printf(MSG_INFO
, "EAP-SIM: (encr) Invalid counter "
838 "(%d <= %d)", eattr
.counter
, data
->counter
);
839 data
->counter_too_small
= eattr
.counter
;
840 /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
841 * reauth_id must not be used to start a new reauthentication.
842 * However, since it was used in the last EAP-Response-Identity
843 * packet, it has to saved for the following fullauth to be
844 * used in MK derivation. */
845 os_free(data
->last_eap_identity
);
846 data
->last_eap_identity
= data
->reauth_id
;
847 data
->last_eap_identity_len
= data
->reauth_id_len
;
848 data
->reauth_id
= NULL
;
849 data
->reauth_id_len
= 0;
851 return eap_sim_response_reauth(data
, id
, 1);
853 data
->counter
= eattr
.counter
;
855 os_memcpy(data
->nonce_s
, eattr
.nonce_s
, EAP_SIM_NONCE_S_LEN
);
856 wpa_hexdump(MSG_DEBUG
, "EAP-SIM: (encr) AT_NONCE_S",
857 data
->nonce_s
, EAP_SIM_NONCE_S_LEN
);
859 eap_sim_derive_keys_reauth(data
->counter
,
860 data
->reauth_id
, data
->reauth_id_len
,
861 data
->nonce_s
, data
->mk
, data
->msk
,
863 eap_sim_clear_identities(data
, CLEAR_REAUTH_ID
| CLEAR_EAP_ID
);
864 eap_sim_learn_ids(data
, &eattr
);
866 if (data
->result_ind
&& attr
->result_ind
)
867 data
->use_result_ind
= 1;
869 if (data
->state
!= FAILURE
&& data
->state
!= RESULT_FAILURE
) {
870 eap_sim_state(data
, data
->use_result_ind
?
871 RESULT_SUCCESS
: SUCCESS
);
874 data
->num_id_req
= 0;
875 data
->num_notification
= 0;
876 if (data
->counter
> EAP_SIM_MAX_FAST_REAUTHS
) {
877 wpa_printf(MSG_DEBUG
, "EAP-SIM: Maximum number of "
878 "fast reauths performed - force fullauth");
879 eap_sim_clear_identities(data
, CLEAR_REAUTH_ID
| CLEAR_EAP_ID
);
882 return eap_sim_response_reauth(data
, id
, 0);
886 static struct wpabuf
* eap_sim_process(struct eap_sm
*sm
, void *priv
,
887 struct eap_method_ret
*ret
,
888 const struct wpabuf
*reqData
)
890 struct eap_sim_data
*data
= priv
;
891 const struct eap_hdr
*req
;
895 struct eap_sim_attrs attr
;
898 wpa_hexdump_buf(MSG_DEBUG
, "EAP-SIM: EAP data", reqData
);
899 if (eap_get_config_identity(sm
, &len
) == NULL
) {
900 wpa_printf(MSG_INFO
, "EAP-SIM: Identity not configured");
901 eap_sm_request_identity(sm
);
906 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, EAP_TYPE_SIM
, reqData
, &len
);
907 if (pos
== NULL
|| len
< 1) {
911 req
= wpabuf_head(reqData
);
912 id
= req
->identifier
;
913 len
= be_to_host16(req
->length
);
916 ret
->methodState
= METHOD_MAY_CONT
;
917 ret
->decision
= DECISION_FAIL
;
918 ret
->allowNotifications
= TRUE
;
921 wpa_printf(MSG_DEBUG
, "EAP-SIM: Subtype=%d", subtype
);
922 pos
+= 2; /* Reserved */
924 if (eap_sim_parse_attr(pos
, wpabuf_head_u8(reqData
) + len
, &attr
, 0,
926 res
= eap_sim_client_error(data
, id
,
927 EAP_SIM_UNABLE_TO_PROCESS_PACKET
);
932 case EAP_SIM_SUBTYPE_START
:
933 res
= eap_sim_process_start(sm
, data
, id
, &attr
);
935 case EAP_SIM_SUBTYPE_CHALLENGE
:
936 res
= eap_sim_process_challenge(sm
, data
, id
, reqData
, &attr
);
938 case EAP_SIM_SUBTYPE_NOTIFICATION
:
939 res
= eap_sim_process_notification(sm
, data
, id
, reqData
,
942 case EAP_SIM_SUBTYPE_REAUTHENTICATION
:
943 res
= eap_sim_process_reauthentication(sm
, data
, id
, reqData
,
946 case EAP_SIM_SUBTYPE_CLIENT_ERROR
:
947 wpa_printf(MSG_DEBUG
, "EAP-SIM: subtype Client-Error");
948 res
= eap_sim_client_error(data
, id
,
949 EAP_SIM_UNABLE_TO_PROCESS_PACKET
);
952 wpa_printf(MSG_DEBUG
, "EAP-SIM: Unknown subtype=%d", subtype
);
953 res
= eap_sim_client_error(data
, id
,
954 EAP_SIM_UNABLE_TO_PROCESS_PACKET
);
959 if (data
->state
== FAILURE
) {
960 ret
->decision
= DECISION_FAIL
;
961 ret
->methodState
= METHOD_DONE
;
962 } else if (data
->state
== SUCCESS
) {
963 ret
->decision
= data
->use_result_ind
?
964 DECISION_UNCOND_SUCC
: DECISION_COND_SUCC
;
965 ret
->methodState
= data
->use_result_ind
?
966 METHOD_DONE
: METHOD_MAY_CONT
;
967 } else if (data
->state
== RESULT_FAILURE
)
968 ret
->methodState
= METHOD_CONT
;
969 else if (data
->state
== RESULT_SUCCESS
)
970 ret
->methodState
= METHOD_CONT
;
972 if (ret
->methodState
== METHOD_DONE
) {
973 ret
->allowNotifications
= FALSE
;
980 static Boolean
eap_sim_has_reauth_data(struct eap_sm
*sm
, void *priv
)
982 struct eap_sim_data
*data
= priv
;
983 return data
->pseudonym
|| data
->reauth_id
;
987 static void eap_sim_deinit_for_reauth(struct eap_sm
*sm
, void *priv
)
989 struct eap_sim_data
*data
= priv
;
990 eap_sim_clear_identities(data
, CLEAR_EAP_ID
);
991 data
->use_result_ind
= 0;
995 static void * eap_sim_init_for_reauth(struct eap_sm
*sm
, void *priv
)
997 struct eap_sim_data
*data
= priv
;
998 if (os_get_random(data
->nonce_mt
, EAP_SIM_NONCE_MT_LEN
)) {
999 wpa_printf(MSG_WARNING
, "EAP-SIM: Failed to get random data "
1004 data
->num_id_req
= 0;
1005 data
->num_notification
= 0;
1006 eap_sim_state(data
, CONTINUE
);
1011 static const u8
* eap_sim_get_identity(struct eap_sm
*sm
, void *priv
,
1014 struct eap_sim_data
*data
= priv
;
1016 if (data
->reauth_id
) {
1017 *len
= data
->reauth_id_len
;
1018 return data
->reauth_id
;
1021 if (data
->pseudonym
) {
1022 *len
= data
->pseudonym_len
;
1023 return data
->pseudonym
;
1030 static Boolean
eap_sim_isKeyAvailable(struct eap_sm
*sm
, void *priv
)
1032 struct eap_sim_data
*data
= priv
;
1033 return data
->state
== SUCCESS
;
1037 static u8
* eap_sim_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
1039 struct eap_sim_data
*data
= priv
;
1042 if (data
->state
!= SUCCESS
)
1045 key
= os_malloc(EAP_SIM_KEYING_DATA_LEN
);
1049 *len
= EAP_SIM_KEYING_DATA_LEN
;
1050 os_memcpy(key
, data
->msk
, EAP_SIM_KEYING_DATA_LEN
);
1056 static u8
* eap_sim_get_emsk(struct eap_sm
*sm
, void *priv
, size_t *len
)
1058 struct eap_sim_data
*data
= priv
;
1061 if (data
->state
!= SUCCESS
)
1064 key
= os_malloc(EAP_EMSK_LEN
);
1068 *len
= EAP_EMSK_LEN
;
1069 os_memcpy(key
, data
->emsk
, EAP_EMSK_LEN
);
1075 int eap_peer_sim_register(void)
1077 struct eap_method
*eap
;
1080 eap
= eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION
,
1081 EAP_VENDOR_IETF
, EAP_TYPE_SIM
, "SIM");
1085 eap
->init
= eap_sim_init
;
1086 eap
->deinit
= eap_sim_deinit
;
1087 eap
->process
= eap_sim_process
;
1088 eap
->isKeyAvailable
= eap_sim_isKeyAvailable
;
1089 eap
->getKey
= eap_sim_getKey
;
1090 eap
->has_reauth_data
= eap_sim_has_reauth_data
;
1091 eap
->deinit_for_reauth
= eap_sim_deinit_for_reauth
;
1092 eap
->init_for_reauth
= eap_sim_init_for_reauth
;
1093 eap
->get_identity
= eap_sim_get_identity
;
1094 eap
->get_emsk
= eap_sim_get_emsk
;
1096 ret
= eap_peer_method_register(eap
);
1098 eap_peer_method_free(eap
);