2 * hostapd / EAP-SIM (RFC 4186)
3 * Copyright (c) 2005-2012, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
12 #include "crypto/random.h"
13 #include "eap_server/eap_i.h"
14 #include "eap_common/eap_sim_common.h"
15 #include "eap_server/eap_sim_db.h"
19 u8 mk
[EAP_SIM_MK_LEN
];
20 u8 nonce_mt
[EAP_SIM_NONCE_MT_LEN
];
21 u8 nonce_s
[EAP_SIM_NONCE_S_LEN
];
22 u8 k_aut
[EAP_SIM_K_AUT_LEN
];
23 u8 k_encr
[EAP_SIM_K_ENCR_LEN
];
24 u8 msk
[EAP_SIM_KEYING_DATA_LEN
];
25 u8 emsk
[EAP_EMSK_LEN
];
26 u8 kc
[EAP_SIM_MAX_CHAL
][EAP_SIM_KC_LEN
];
27 u8 sres
[EAP_SIM_MAX_CHAL
][EAP_SIM_SRES_LEN
];
28 u8 rand
[EAP_SIM_MAX_CHAL
][GSM_RAND_LEN
];
31 START
, CHALLENGE
, REAUTH
, NOTIFICATION
, SUCCESS
, FAILURE
36 struct eap_sim_reauth
*reauth
;
40 char permanent
[20]; /* Permanent username */
44 static const char * eap_sim_state_txt(int state
)
58 return "NOTIFICATION";
65 static void eap_sim_state(struct eap_sim_data
*data
, int state
)
67 wpa_printf(MSG_DEBUG
, "EAP-SIM: %s -> %s",
68 eap_sim_state_txt(data
->state
),
69 eap_sim_state_txt(state
));
74 static void * eap_sim_init(struct eap_sm
*sm
)
76 struct eap_sim_data
*data
;
78 if (sm
->eap_sim_db_priv
== NULL
) {
79 wpa_printf(MSG_WARNING
, "EAP-SIM: eap_sim_db not configured");
83 data
= os_zalloc(sizeof(*data
));
92 static void eap_sim_reset(struct eap_sm
*sm
, void *priv
)
94 struct eap_sim_data
*data
= priv
;
95 os_free(data
->next_pseudonym
);
96 os_free(data
->next_reauth_id
);
97 bin_clear_free(data
, sizeof(*data
));
101 static struct wpabuf
* eap_sim_build_start(struct eap_sm
*sm
,
102 struct eap_sim_data
*data
, u8 id
)
104 struct eap_sim_msg
*msg
;
107 wpa_printf(MSG_DEBUG
, "EAP-SIM: Generating Start");
108 msg
= eap_sim_msg_init(EAP_CODE_REQUEST
, id
, EAP_TYPE_SIM
,
109 EAP_SIM_SUBTYPE_START
);
111 if (data
->start_round
== 1) {
113 * RFC 4186, Chap. 4.2.4 recommends that identity from EAP is
114 * ignored and the SIM/Start is used to request the identity.
116 wpa_printf(MSG_DEBUG
, " AT_ANY_ID_REQ");
117 eap_sim_msg_add(msg
, EAP_SIM_AT_ANY_ID_REQ
, 0, NULL
, 0);
118 } else if (data
->start_round
> 3) {
119 /* Cannot use more than three rounds of Start messages */
120 eap_sim_msg_free(msg
);
122 } else if (data
->start_round
== 0) {
124 * This is a special case that is used to recover from
125 * AT_COUNTER_TOO_SMALL during re-authentication. Since we
126 * already know the identity of the peer, there is no need to
127 * request any identity in this case.
129 } else if (sm
->identity
&& sm
->identity_len
> 0 &&
130 sm
->identity
[0] == EAP_SIM_REAUTH_ID_PREFIX
) {
131 /* Reauth id may have expired - try fullauth */
132 wpa_printf(MSG_DEBUG
, " AT_FULLAUTH_ID_REQ");
133 eap_sim_msg_add(msg
, EAP_SIM_AT_FULLAUTH_ID_REQ
, 0, NULL
, 0);
135 wpa_printf(MSG_DEBUG
, " AT_PERMANENT_ID_REQ");
136 eap_sim_msg_add(msg
, EAP_SIM_AT_PERMANENT_ID_REQ
, 0, NULL
, 0);
138 wpa_printf(MSG_DEBUG
, " AT_VERSION_LIST");
140 ver
[1] = EAP_SIM_VERSION
;
141 eap_sim_msg_add(msg
, EAP_SIM_AT_VERSION_LIST
, sizeof(ver
),
143 return eap_sim_msg_finish(msg
, EAP_TYPE_SIM
, NULL
, NULL
, 0);
147 static int eap_sim_build_encr(struct eap_sm
*sm
, struct eap_sim_data
*data
,
148 struct eap_sim_msg
*msg
, u16 counter
,
151 os_free(data
->next_pseudonym
);
152 if (nonce_s
== NULL
) {
153 data
->next_pseudonym
=
154 eap_sim_db_get_next_pseudonym(sm
->eap_sim_db_priv
,
157 /* Do not update pseudonym during re-authentication */
158 data
->next_pseudonym
= NULL
;
160 os_free(data
->next_reauth_id
);
161 if (data
->counter
<= EAP_SIM_MAX_FAST_REAUTHS
) {
162 data
->next_reauth_id
=
163 eap_sim_db_get_next_reauth_id(sm
->eap_sim_db_priv
,
166 wpa_printf(MSG_DEBUG
, "EAP-SIM: Max fast re-authentication "
167 "count exceeded - force full authentication");
168 data
->next_reauth_id
= NULL
;
171 if (data
->next_pseudonym
== NULL
&& data
->next_reauth_id
== NULL
&&
172 counter
== 0 && nonce_s
== NULL
)
175 wpa_printf(MSG_DEBUG
, " AT_IV");
176 wpa_printf(MSG_DEBUG
, " AT_ENCR_DATA");
177 eap_sim_msg_add_encr_start(msg
, EAP_SIM_AT_IV
, EAP_SIM_AT_ENCR_DATA
);
180 wpa_printf(MSG_DEBUG
, " *AT_COUNTER (%u)", counter
);
181 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER
, counter
, NULL
, 0);
185 wpa_printf(MSG_DEBUG
, " *AT_NONCE_S");
186 eap_sim_msg_add(msg
, EAP_SIM_AT_NONCE_S
, 0, nonce_s
,
187 EAP_SIM_NONCE_S_LEN
);
190 if (data
->next_pseudonym
) {
191 wpa_printf(MSG_DEBUG
, " *AT_NEXT_PSEUDONYM (%s)",
192 data
->next_pseudonym
);
193 eap_sim_msg_add(msg
, EAP_SIM_AT_NEXT_PSEUDONYM
,
194 os_strlen(data
->next_pseudonym
),
195 (u8
*) data
->next_pseudonym
,
196 os_strlen(data
->next_pseudonym
));
199 if (data
->next_reauth_id
) {
200 wpa_printf(MSG_DEBUG
, " *AT_NEXT_REAUTH_ID (%s)",
201 data
->next_reauth_id
);
202 eap_sim_msg_add(msg
, EAP_SIM_AT_NEXT_REAUTH_ID
,
203 os_strlen(data
->next_reauth_id
),
204 (u8
*) data
->next_reauth_id
,
205 os_strlen(data
->next_reauth_id
));
208 if (eap_sim_msg_add_encr_end(msg
, data
->k_encr
, EAP_SIM_AT_PADDING
)) {
209 wpa_printf(MSG_WARNING
, "EAP-SIM: Failed to encrypt "
218 static struct wpabuf
* eap_sim_build_challenge(struct eap_sm
*sm
,
219 struct eap_sim_data
*data
,
222 struct eap_sim_msg
*msg
;
224 wpa_printf(MSG_DEBUG
, "EAP-SIM: Generating Challenge");
225 msg
= eap_sim_msg_init(EAP_CODE_REQUEST
, id
, EAP_TYPE_SIM
,
226 EAP_SIM_SUBTYPE_CHALLENGE
);
227 wpa_printf(MSG_DEBUG
, " AT_RAND");
228 eap_sim_msg_add(msg
, EAP_SIM_AT_RAND
, 0, (u8
*) data
->rand
,
229 data
->num_chal
* GSM_RAND_LEN
);
231 if (eap_sim_build_encr(sm
, data
, msg
, 0, NULL
)) {
232 eap_sim_msg_free(msg
);
236 if (sm
->eap_sim_aka_result_ind
) {
237 wpa_printf(MSG_DEBUG
, " AT_RESULT_IND");
238 eap_sim_msg_add(msg
, EAP_SIM_AT_RESULT_IND
, 0, NULL
, 0);
241 wpa_printf(MSG_DEBUG
, " AT_MAC");
242 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
243 return eap_sim_msg_finish(msg
, EAP_TYPE_SIM
, data
->k_aut
,
244 data
->nonce_mt
, EAP_SIM_NONCE_MT_LEN
);
248 static struct wpabuf
* eap_sim_build_reauth(struct eap_sm
*sm
,
249 struct eap_sim_data
*data
, u8 id
)
251 struct eap_sim_msg
*msg
;
253 wpa_printf(MSG_DEBUG
, "EAP-SIM: Generating Re-authentication");
255 if (random_get_bytes(data
->nonce_s
, EAP_SIM_NONCE_S_LEN
))
257 wpa_hexdump_key(MSG_MSGDUMP
, "EAP-SIM: NONCE_S",
258 data
->nonce_s
, EAP_SIM_NONCE_S_LEN
);
260 eap_sim_derive_keys(data
->mk
, data
->k_encr
, data
->k_aut
, data
->msk
,
262 eap_sim_derive_keys_reauth(data
->counter
, sm
->identity
,
263 sm
->identity_len
, data
->nonce_s
, data
->mk
,
264 data
->msk
, data
->emsk
);
266 msg
= eap_sim_msg_init(EAP_CODE_REQUEST
, id
, EAP_TYPE_SIM
,
267 EAP_SIM_SUBTYPE_REAUTHENTICATION
);
269 if (eap_sim_build_encr(sm
, data
, msg
, data
->counter
, data
->nonce_s
)) {
270 eap_sim_msg_free(msg
);
274 if (sm
->eap_sim_aka_result_ind
) {
275 wpa_printf(MSG_DEBUG
, " AT_RESULT_IND");
276 eap_sim_msg_add(msg
, EAP_SIM_AT_RESULT_IND
, 0, NULL
, 0);
279 wpa_printf(MSG_DEBUG
, " AT_MAC");
280 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
281 return eap_sim_msg_finish(msg
, EAP_TYPE_SIM
, data
->k_aut
, NULL
, 0);
285 static struct wpabuf
* eap_sim_build_notification(struct eap_sm
*sm
,
286 struct eap_sim_data
*data
,
289 struct eap_sim_msg
*msg
;
291 wpa_printf(MSG_DEBUG
, "EAP-SIM: Generating Notification");
292 msg
= eap_sim_msg_init(EAP_CODE_REQUEST
, id
, EAP_TYPE_SIM
,
293 EAP_SIM_SUBTYPE_NOTIFICATION
);
294 wpa_printf(MSG_DEBUG
, " AT_NOTIFICATION (%d)", data
->notification
);
295 eap_sim_msg_add(msg
, EAP_SIM_AT_NOTIFICATION
, data
->notification
,
297 if (data
->use_result_ind
) {
299 wpa_printf(MSG_DEBUG
, " AT_IV");
300 wpa_printf(MSG_DEBUG
, " AT_ENCR_DATA");
301 eap_sim_msg_add_encr_start(msg
, EAP_SIM_AT_IV
,
302 EAP_SIM_AT_ENCR_DATA
);
303 wpa_printf(MSG_DEBUG
, " *AT_COUNTER (%u)",
305 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER
, data
->counter
,
308 if (eap_sim_msg_add_encr_end(msg
, data
->k_encr
,
309 EAP_SIM_AT_PADDING
)) {
310 wpa_printf(MSG_WARNING
, "EAP-SIM: Failed to "
311 "encrypt AT_ENCR_DATA");
312 eap_sim_msg_free(msg
);
317 wpa_printf(MSG_DEBUG
, " AT_MAC");
318 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
320 return eap_sim_msg_finish(msg
, EAP_TYPE_SIM
, data
->k_aut
, NULL
, 0);
324 static struct wpabuf
* eap_sim_buildReq(struct eap_sm
*sm
, void *priv
, u8 id
)
326 struct eap_sim_data
*data
= priv
;
328 switch (data
->state
) {
330 return eap_sim_build_start(sm
, data
, id
);
332 return eap_sim_build_challenge(sm
, data
, id
);
334 return eap_sim_build_reauth(sm
, data
, id
);
336 return eap_sim_build_notification(sm
, data
, id
);
338 wpa_printf(MSG_DEBUG
, "EAP-SIM: Unknown state %d in "
339 "buildReq", data
->state
);
346 static Boolean
eap_sim_check(struct eap_sm
*sm
, void *priv
,
347 struct wpabuf
*respData
)
352 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, EAP_TYPE_SIM
, respData
, &len
);
353 if (pos
== NULL
|| len
< 3) {
354 wpa_printf(MSG_INFO
, "EAP-SIM: Invalid frame");
362 static Boolean
eap_sim_unexpected_subtype(struct eap_sim_data
*data
,
365 if (subtype
== EAP_SIM_SUBTYPE_CLIENT_ERROR
)
368 switch (data
->state
) {
370 if (subtype
!= EAP_SIM_SUBTYPE_START
) {
371 wpa_printf(MSG_INFO
, "EAP-SIM: Unexpected response "
372 "subtype %d", subtype
);
377 if (subtype
!= EAP_SIM_SUBTYPE_CHALLENGE
) {
378 wpa_printf(MSG_INFO
, "EAP-SIM: Unexpected response "
379 "subtype %d", subtype
);
384 if (subtype
!= EAP_SIM_SUBTYPE_REAUTHENTICATION
) {
385 wpa_printf(MSG_INFO
, "EAP-SIM: Unexpected response "
386 "subtype %d", subtype
);
391 if (subtype
!= EAP_SIM_SUBTYPE_NOTIFICATION
) {
392 wpa_printf(MSG_INFO
, "EAP-SIM: Unexpected response "
393 "subtype %d", subtype
);
398 wpa_printf(MSG_INFO
, "EAP-SIM: Unexpected state (%d) for "
399 "processing a response", data
->state
);
407 static int eap_sim_supported_ver(struct eap_sim_data
*data
, int version
)
409 return version
== EAP_SIM_VERSION
;
413 static void eap_sim_process_start(struct eap_sm
*sm
,
414 struct eap_sim_data
*data
,
415 struct wpabuf
*respData
,
416 struct eap_sim_attrs
*attr
)
423 wpa_printf(MSG_DEBUG
, "EAP-SIM: Receive start response");
425 if (data
->start_round
== 0) {
427 * Special case for AT_COUNTER_TOO_SMALL recovery - no identity
428 * was requested since we already know it.
434 * We always request identity in SIM/Start, so the peer is required to
435 * have replied with one.
437 if (!attr
->identity
|| attr
->identity_len
== 0) {
438 wpa_printf(MSG_DEBUG
, "EAP-SIM: Peer did not provide any "
443 new_identity
= os_malloc(attr
->identity_len
);
444 if (new_identity
== NULL
)
446 os_free(sm
->identity
);
447 sm
->identity
= new_identity
;
448 os_memcpy(sm
->identity
, attr
->identity
, attr
->identity_len
);
449 sm
->identity_len
= attr
->identity_len
;
451 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-SIM: Identity",
452 sm
->identity
, sm
->identity_len
);
453 username
= sim_get_username(sm
->identity
, sm
->identity_len
);
454 if (username
== NULL
)
457 if (username
[0] == EAP_SIM_REAUTH_ID_PREFIX
) {
458 wpa_printf(MSG_DEBUG
, "EAP-SIM: Reauth username '%s'",
460 data
->reauth
= eap_sim_db_get_reauth_entry(
461 sm
->eap_sim_db_priv
, username
);
463 if (data
->reauth
== NULL
) {
464 wpa_printf(MSG_DEBUG
, "EAP-SIM: Unknown reauth "
465 "identity - request full auth identity");
466 /* Remain in START state for another round */
469 wpa_printf(MSG_DEBUG
, "EAP-SIM: Using fast re-authentication");
470 os_strlcpy(data
->permanent
, data
->reauth
->permanent
,
471 sizeof(data
->permanent
));
472 data
->counter
= data
->reauth
->counter
;
473 os_memcpy(data
->mk
, data
->reauth
->mk
, EAP_SIM_MK_LEN
);
474 eap_sim_state(data
, REAUTH
);
478 if (username
[0] == EAP_SIM_PSEUDONYM_PREFIX
) {
479 const char *permanent
;
480 wpa_printf(MSG_DEBUG
, "EAP-SIM: Pseudonym username '%s'",
482 permanent
= eap_sim_db_get_permanent(
483 sm
->eap_sim_db_priv
, username
);
485 if (permanent
== NULL
) {
486 wpa_printf(MSG_DEBUG
, "EAP-SIM: Unknown pseudonym "
487 "identity - request permanent identity");
488 /* Remain in START state for another round */
491 os_strlcpy(data
->permanent
, permanent
,
492 sizeof(data
->permanent
));
493 } else if (username
[0] == EAP_SIM_PERMANENT_PREFIX
) {
494 wpa_printf(MSG_DEBUG
, "EAP-SIM: Permanent username '%s'",
496 os_strlcpy(data
->permanent
, username
, sizeof(data
->permanent
));
499 wpa_printf(MSG_DEBUG
, "EAP-SIM: Unrecognized username '%s'",
506 /* Full authentication */
508 if (attr
->nonce_mt
== NULL
|| attr
->selected_version
< 0) {
509 wpa_printf(MSG_DEBUG
, "EAP-SIM: Start/Response missing "
510 "required attributes");
514 if (!eap_sim_supported_ver(data
, attr
->selected_version
)) {
515 wpa_printf(MSG_DEBUG
, "EAP-SIM: Peer selected unsupported "
516 "version %d", attr
->selected_version
);
520 data
->counter
= 0; /* reset re-auth counter since this is full auth */
523 data
->num_chal
= eap_sim_db_get_gsm_triplets(
524 sm
->eap_sim_db_priv
, data
->permanent
, EAP_SIM_MAX_CHAL
,
525 (u8
*) data
->rand
, (u8
*) data
->kc
, (u8
*) data
->sres
, sm
);
526 if (data
->num_chal
== EAP_SIM_DB_PENDING
) {
527 wpa_printf(MSG_DEBUG
, "EAP-SIM: GSM authentication triplets "
528 "not yet available - pending request");
529 sm
->method_pending
= METHOD_PENDING_WAIT
;
532 if (data
->num_chal
< 2) {
533 wpa_printf(MSG_INFO
, "EAP-SIM: Failed to get GSM "
534 "authentication triplets for the peer");
538 identity_len
= sm
->identity_len
;
539 while (identity_len
> 0 && sm
->identity
[identity_len
- 1] == '\0') {
540 wpa_printf(MSG_DEBUG
, "EAP-SIM: Workaround - drop last null "
541 "character from identity");
544 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-SIM: Identity for MK derivation",
545 sm
->identity
, identity_len
);
547 os_memcpy(data
->nonce_mt
, attr
->nonce_mt
, EAP_SIM_NONCE_MT_LEN
);
548 WPA_PUT_BE16(ver_list
, EAP_SIM_VERSION
);
549 eap_sim_derive_mk(sm
->identity
, identity_len
, attr
->nonce_mt
,
550 attr
->selected_version
, ver_list
, sizeof(ver_list
),
551 data
->num_chal
, (const u8
*) data
->kc
, data
->mk
);
552 eap_sim_derive_keys(data
->mk
, data
->k_encr
, data
->k_aut
, data
->msk
,
555 eap_sim_state(data
, CHALLENGE
);
559 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
560 eap_sim_state(data
, NOTIFICATION
);
564 static void eap_sim_process_challenge(struct eap_sm
*sm
,
565 struct eap_sim_data
*data
,
566 struct wpabuf
*respData
,
567 struct eap_sim_attrs
*attr
)
569 if (attr
->mac
== NULL
||
570 eap_sim_verify_mac(data
->k_aut
, respData
, attr
->mac
,
572 data
->num_chal
* EAP_SIM_SRES_LEN
)) {
573 wpa_printf(MSG_WARNING
, "EAP-SIM: Challenge message "
574 "did not include valid AT_MAC");
575 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
576 eap_sim_state(data
, NOTIFICATION
);
580 wpa_printf(MSG_DEBUG
, "EAP-SIM: Challenge response includes the "
582 if (sm
->eap_sim_aka_result_ind
&& attr
->result_ind
) {
583 data
->use_result_ind
= 1;
584 data
->notification
= EAP_SIM_SUCCESS
;
585 eap_sim_state(data
, NOTIFICATION
);
587 eap_sim_state(data
, SUCCESS
);
589 if (data
->next_pseudonym
) {
590 eap_sim_db_add_pseudonym(sm
->eap_sim_db_priv
, data
->permanent
,
591 data
->next_pseudonym
);
592 data
->next_pseudonym
= NULL
;
594 if (data
->next_reauth_id
) {
595 eap_sim_db_add_reauth(sm
->eap_sim_db_priv
, data
->permanent
,
596 data
->next_reauth_id
, data
->counter
+ 1,
598 data
->next_reauth_id
= NULL
;
603 static void eap_sim_process_reauth(struct eap_sm
*sm
,
604 struct eap_sim_data
*data
,
605 struct wpabuf
*respData
,
606 struct eap_sim_attrs
*attr
)
608 struct eap_sim_attrs eattr
;
609 u8
*decrypted
= NULL
;
611 if (attr
->mac
== NULL
||
612 eap_sim_verify_mac(data
->k_aut
, respData
, attr
->mac
, data
->nonce_s
,
613 EAP_SIM_NONCE_S_LEN
)) {
614 wpa_printf(MSG_WARNING
, "EAP-SIM: Re-authentication message "
615 "did not include valid AT_MAC");
619 if (attr
->encr_data
== NULL
|| attr
->iv
== NULL
) {
620 wpa_printf(MSG_WARNING
, "EAP-SIM: Reauthentication "
621 "message did not include encrypted data");
625 decrypted
= eap_sim_parse_encr(data
->k_encr
, attr
->encr_data
,
626 attr
->encr_data_len
, attr
->iv
, &eattr
,
628 if (decrypted
== NULL
) {
629 wpa_printf(MSG_WARNING
, "EAP-SIM: Failed to parse encrypted "
630 "data from reauthentication message");
634 if (eattr
.counter
!= data
->counter
) {
635 wpa_printf(MSG_WARNING
, "EAP-SIM: Re-authentication message "
636 "used incorrect counter %u, expected %u",
637 eattr
.counter
, data
->counter
);
643 wpa_printf(MSG_DEBUG
, "EAP-SIM: Re-authentication response includes "
644 "the correct AT_MAC");
646 if (eattr
.counter_too_small
) {
647 wpa_printf(MSG_DEBUG
, "EAP-AKA: Re-authentication response "
648 "included AT_COUNTER_TOO_SMALL - starting full "
650 data
->start_round
= -1;
651 eap_sim_state(data
, START
);
655 if (sm
->eap_sim_aka_result_ind
&& attr
->result_ind
) {
656 data
->use_result_ind
= 1;
657 data
->notification
= EAP_SIM_SUCCESS
;
658 eap_sim_state(data
, NOTIFICATION
);
660 eap_sim_state(data
, SUCCESS
);
662 if (data
->next_reauth_id
) {
663 eap_sim_db_add_reauth(sm
->eap_sim_db_priv
, data
->permanent
,
664 data
->next_reauth_id
,
665 data
->counter
+ 1, data
->mk
);
666 data
->next_reauth_id
= NULL
;
668 eap_sim_db_remove_reauth(sm
->eap_sim_db_priv
, data
->reauth
);
675 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
676 eap_sim_state(data
, NOTIFICATION
);
677 eap_sim_db_remove_reauth(sm
->eap_sim_db_priv
, data
->reauth
);
683 static void eap_sim_process_client_error(struct eap_sm
*sm
,
684 struct eap_sim_data
*data
,
685 struct wpabuf
*respData
,
686 struct eap_sim_attrs
*attr
)
688 wpa_printf(MSG_DEBUG
, "EAP-SIM: Client reported error %d",
689 attr
->client_error_code
);
690 if (data
->notification
== EAP_SIM_SUCCESS
&& data
->use_result_ind
)
691 eap_sim_state(data
, SUCCESS
);
693 eap_sim_state(data
, FAILURE
);
697 static void eap_sim_process_notification(struct eap_sm
*sm
,
698 struct eap_sim_data
*data
,
699 struct wpabuf
*respData
,
700 struct eap_sim_attrs
*attr
)
702 wpa_printf(MSG_DEBUG
, "EAP-SIM: Client replied to notification");
703 if (data
->notification
== EAP_SIM_SUCCESS
&& data
->use_result_ind
)
704 eap_sim_state(data
, SUCCESS
);
706 eap_sim_state(data
, FAILURE
);
710 static void eap_sim_process(struct eap_sm
*sm
, void *priv
,
711 struct wpabuf
*respData
)
713 struct eap_sim_data
*data
= priv
;
717 struct eap_sim_attrs attr
;
719 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, EAP_TYPE_SIM
, respData
, &len
);
720 if (pos
== NULL
|| len
< 3)
727 if (eap_sim_unexpected_subtype(data
, subtype
)) {
728 wpa_printf(MSG_DEBUG
, "EAP-SIM: Unrecognized or unexpected "
729 "EAP-SIM Subtype in EAP Response");
730 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
731 eap_sim_state(data
, NOTIFICATION
);
735 if (eap_sim_parse_attr(pos
, end
, &attr
, 0, 0)) {
736 wpa_printf(MSG_DEBUG
, "EAP-SIM: Failed to parse attributes");
737 if (subtype
!= EAP_SIM_SUBTYPE_CLIENT_ERROR
&&
738 (data
->state
== START
|| data
->state
== CHALLENGE
||
739 data
->state
== REAUTH
)) {
741 EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
742 eap_sim_state(data
, NOTIFICATION
);
745 eap_sim_state(data
, FAILURE
);
749 if (subtype
== EAP_SIM_SUBTYPE_CLIENT_ERROR
) {
750 eap_sim_process_client_error(sm
, data
, respData
, &attr
);
754 switch (data
->state
) {
756 eap_sim_process_start(sm
, data
, respData
, &attr
);
759 eap_sim_process_challenge(sm
, data
, respData
, &attr
);
762 eap_sim_process_reauth(sm
, data
, respData
, &attr
);
765 eap_sim_process_notification(sm
, data
, respData
, &attr
);
768 wpa_printf(MSG_DEBUG
, "EAP-SIM: Unknown state %d in "
769 "process", data
->state
);
775 static Boolean
eap_sim_isDone(struct eap_sm
*sm
, void *priv
)
777 struct eap_sim_data
*data
= priv
;
778 return data
->state
== SUCCESS
|| data
->state
== FAILURE
;
782 static u8
* eap_sim_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
784 struct eap_sim_data
*data
= priv
;
787 if (data
->state
!= SUCCESS
)
790 key
= os_malloc(EAP_SIM_KEYING_DATA_LEN
);
793 os_memcpy(key
, data
->msk
, EAP_SIM_KEYING_DATA_LEN
);
794 *len
= EAP_SIM_KEYING_DATA_LEN
;
799 static u8
* eap_sim_get_emsk(struct eap_sm
*sm
, void *priv
, size_t *len
)
801 struct eap_sim_data
*data
= priv
;
804 if (data
->state
!= SUCCESS
)
807 key
= os_malloc(EAP_EMSK_LEN
);
810 os_memcpy(key
, data
->emsk
, EAP_EMSK_LEN
);
816 static Boolean
eap_sim_isSuccess(struct eap_sm
*sm
, void *priv
)
818 struct eap_sim_data
*data
= priv
;
819 return data
->state
== SUCCESS
;
823 static u8
* eap_sim_get_session_id(struct eap_sm
*sm
, void *priv
, size_t *len
)
825 struct eap_sim_data
*data
= priv
;
828 if (data
->state
!= SUCCESS
)
831 *len
= 1 + data
->num_chal
* GSM_RAND_LEN
+ EAP_SIM_NONCE_MT_LEN
;
832 id
= os_malloc(*len
);
836 id
[0] = EAP_TYPE_SIM
;
837 os_memcpy(id
+ 1, data
->rand
, data
->num_chal
* GSM_RAND_LEN
);
838 os_memcpy(id
+ 1 + data
->num_chal
* GSM_RAND_LEN
, data
->nonce_mt
,
839 EAP_SIM_NONCE_MT_LEN
);
840 wpa_hexdump(MSG_DEBUG
, "EAP-SIM: Derived Session-Id", id
, *len
);
846 int eap_server_sim_register(void)
848 struct eap_method
*eap
;
850 eap
= eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION
,
851 EAP_VENDOR_IETF
, EAP_TYPE_SIM
, "SIM");
855 eap
->init
= eap_sim_init
;
856 eap
->reset
= eap_sim_reset
;
857 eap
->buildReq
= eap_sim_buildReq
;
858 eap
->check
= eap_sim_check
;
859 eap
->process
= eap_sim_process
;
860 eap
->isDone
= eap_sim_isDone
;
861 eap
->getKey
= eap_sim_getKey
;
862 eap
->isSuccess
= eap_sim_isSuccess
;
863 eap
->get_emsk
= eap_sim_get_emsk
;
864 eap
->getSessionId
= eap_sim_get_session_id
;
866 return eap_server_method_register(eap
);