2 * hostapd / EAP-SIM (RFC 4186)
3 * Copyright (c) 2005-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.
21 #include "eap_sim_common.h"
22 #include "eap_sim_db.h"
26 u8 mk
[EAP_SIM_MK_LEN
];
27 u8 nonce_mt
[EAP_SIM_NONCE_MT_LEN
];
28 u8 nonce_s
[EAP_SIM_NONCE_S_LEN
];
29 u8 k_aut
[EAP_SIM_K_AUT_LEN
];
30 u8 k_encr
[EAP_SIM_K_ENCR_LEN
];
31 u8 msk
[EAP_SIM_KEYING_DATA_LEN
];
32 u8 emsk
[EAP_EMSK_LEN
];
33 u8 kc
[EAP_SIM_MAX_CHAL
][EAP_SIM_KC_LEN
];
34 u8 sres
[EAP_SIM_MAX_CHAL
][EAP_SIM_SRES_LEN
];
35 u8 rand
[EAP_SIM_MAX_CHAL
][GSM_RAND_LEN
];
37 enum { START
, CHALLENGE
, REAUTH
, SUCCESS
, FAILURE
} state
;
41 struct eap_sim_reauth
*reauth
;
45 static const char * eap_sim_state_txt(int state
)
64 static void eap_sim_state(struct eap_sim_data
*data
, int state
)
66 wpa_printf(MSG_DEBUG
, "EAP-SIM: %s -> %s",
67 eap_sim_state_txt(data
->state
),
68 eap_sim_state_txt(state
));
73 static void * eap_sim_init(struct eap_sm
*sm
)
75 struct eap_sim_data
*data
;
77 if (sm
->eap_sim_db_priv
== NULL
) {
78 wpa_printf(MSG_WARNING
, "EAP-SIM: eap_sim_db not configured");
82 data
= wpa_zalloc(sizeof(*data
));
91 static void eap_sim_reset(struct eap_sm
*sm
, void *priv
)
93 struct eap_sim_data
*data
= priv
;
94 free(data
->next_pseudonym
);
95 free(data
->next_reauth_id
);
100 static u8
* eap_sim_build_start(struct eap_sm
*sm
, struct eap_sim_data
*data
,
101 int id
, size_t *reqDataLen
)
103 struct eap_sim_msg
*msg
;
106 wpa_printf(MSG_DEBUG
, "EAP-SIM: Generating Start");
107 msg
= eap_sim_msg_init(EAP_CODE_REQUEST
, id
, EAP_TYPE_SIM
,
108 EAP_SIM_SUBTYPE_START
);
109 if (eap_sim_db_identity_known(sm
->eap_sim_db_priv
, sm
->identity
,
111 wpa_printf(MSG_DEBUG
, " AT_PERMANENT_ID_REQ");
112 eap_sim_msg_add(msg
, EAP_SIM_AT_PERMANENT_ID_REQ
, 0, NULL
, 0);
114 wpa_printf(MSG_DEBUG
, " AT_VERSION_LIST");
116 ver
[1] = EAP_SIM_VERSION
;
117 eap_sim_msg_add(msg
, EAP_SIM_AT_VERSION_LIST
, sizeof(ver
),
119 return eap_sim_msg_finish(msg
, reqDataLen
, NULL
, NULL
, 0);
123 static int eap_sim_build_encr(struct eap_sm
*sm
, struct eap_sim_data
*data
,
124 struct eap_sim_msg
*msg
, u16 counter
,
127 free(data
->next_pseudonym
);
128 data
->next_pseudonym
=
129 eap_sim_db_get_next_pseudonym(sm
->eap_sim_db_priv
, 0);
130 free(data
->next_reauth_id
);
131 if (data
->counter
<= EAP_SIM_MAX_FAST_REAUTHS
) {
132 data
->next_reauth_id
=
133 eap_sim_db_get_next_reauth_id(sm
->eap_sim_db_priv
, 0);
135 wpa_printf(MSG_DEBUG
, "EAP-SIM: Max fast re-authentication "
136 "count exceeded - force full authentication");
137 data
->next_reauth_id
= NULL
;
140 if (data
->next_pseudonym
== NULL
&& data
->next_reauth_id
== NULL
&&
141 counter
== 0 && nonce_s
== NULL
)
144 wpa_printf(MSG_DEBUG
, " AT_IV");
145 wpa_printf(MSG_DEBUG
, " AT_ENCR_DATA");
146 eap_sim_msg_add_encr_start(msg
, EAP_SIM_AT_IV
, EAP_SIM_AT_ENCR_DATA
);
149 wpa_printf(MSG_DEBUG
, " *AT_COUNTER (%u)", counter
);
150 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER
, counter
, NULL
, 0);
154 wpa_printf(MSG_DEBUG
, " *AT_NONCE_S");
155 eap_sim_msg_add(msg
, EAP_SIM_AT_NONCE_S
, 0, nonce_s
,
156 EAP_SIM_NONCE_S_LEN
);
159 if (data
->next_pseudonym
) {
160 wpa_printf(MSG_DEBUG
, " *AT_NEXT_PSEUDONYM (%s)",
161 data
->next_pseudonym
);
162 eap_sim_msg_add(msg
, EAP_SIM_AT_NEXT_PSEUDONYM
,
163 strlen(data
->next_pseudonym
),
164 (u8
*) data
->next_pseudonym
,
165 strlen(data
->next_pseudonym
));
168 if (data
->next_reauth_id
) {
169 wpa_printf(MSG_DEBUG
, " *AT_NEXT_REAUTH_ID (%s)",
170 data
->next_reauth_id
);
171 eap_sim_msg_add(msg
, EAP_SIM_AT_NEXT_REAUTH_ID
,
172 strlen(data
->next_reauth_id
),
173 (u8
*) data
->next_reauth_id
,
174 strlen(data
->next_reauth_id
));
177 if (eap_sim_msg_add_encr_end(msg
, data
->k_encr
, EAP_SIM_AT_PADDING
)) {
178 wpa_printf(MSG_WARNING
, "EAP-SIM: Failed to encrypt "
187 static u8
* eap_sim_build_challenge(struct eap_sm
*sm
,
188 struct eap_sim_data
*data
,
189 int id
, size_t *reqDataLen
)
191 struct eap_sim_msg
*msg
;
193 wpa_printf(MSG_DEBUG
, "EAP-SIM: Generating Challenge");
194 msg
= eap_sim_msg_init(EAP_CODE_REQUEST
, id
, EAP_TYPE_SIM
,
195 EAP_SIM_SUBTYPE_CHALLENGE
);
196 wpa_printf(MSG_DEBUG
, " AT_RAND");
197 eap_sim_msg_add(msg
, EAP_SIM_AT_RAND
, 0, (u8
*) data
->rand
,
198 data
->num_chal
* GSM_RAND_LEN
);
200 if (eap_sim_build_encr(sm
, data
, msg
, 0, NULL
)) {
201 eap_sim_msg_free(msg
);
205 wpa_printf(MSG_DEBUG
, " AT_MAC");
206 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
207 return eap_sim_msg_finish(msg
, reqDataLen
, data
->k_aut
, data
->nonce_mt
,
208 EAP_SIM_NONCE_MT_LEN
);
212 static u8
* eap_sim_build_reauth(struct eap_sm
*sm
,
213 struct eap_sim_data
*data
,
214 int id
, size_t *reqDataLen
)
216 struct eap_sim_msg
*msg
;
218 wpa_printf(MSG_DEBUG
, "EAP-SIM: Generating Re-authentication");
220 if (hostapd_get_rand(data
->nonce_s
, EAP_SIM_NONCE_S_LEN
))
222 wpa_hexdump_key(MSG_MSGDUMP
, "EAP-SIM: NONCE_S",
223 data
->nonce_s
, EAP_SIM_NONCE_S_LEN
);
225 eap_sim_derive_keys(data
->mk
, data
->k_encr
, data
->k_aut
, data
->msk
,
227 eap_sim_derive_keys_reauth(data
->counter
, sm
->identity
,
228 sm
->identity_len
, data
->nonce_s
, data
->mk
,
229 data
->msk
, data
->emsk
);
231 msg
= eap_sim_msg_init(EAP_CODE_REQUEST
, id
, EAP_TYPE_SIM
,
232 EAP_SIM_SUBTYPE_REAUTHENTICATION
);
234 if (eap_sim_build_encr(sm
, data
, msg
, data
->counter
, data
->nonce_s
)) {
235 eap_sim_msg_free(msg
);
239 wpa_printf(MSG_DEBUG
, " AT_MAC");
240 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
241 return eap_sim_msg_finish(msg
, reqDataLen
, data
->k_aut
, NULL
, 0);
245 static u8
* eap_sim_buildReq(struct eap_sm
*sm
, void *priv
, int id
,
248 struct eap_sim_data
*data
= priv
;
250 switch (data
->state
) {
252 return eap_sim_build_start(sm
, data
, id
, reqDataLen
);
254 return eap_sim_build_challenge(sm
, data
, id
, reqDataLen
);
256 return eap_sim_build_reauth(sm
, data
, id
, reqDataLen
);
258 wpa_printf(MSG_DEBUG
, "EAP-SIM: Unknown state %d in "
259 "buildReq", data
->state
);
266 static Boolean
eap_sim_check(struct eap_sm
*sm
, void *priv
,
267 u8
*respData
, size_t respDataLen
)
269 struct eap_sim_data
*data
= priv
;
270 struct eap_hdr
*resp
;
273 resp
= (struct eap_hdr
*) respData
;
274 pos
= (u8
*) (resp
+ 1);
275 if (respDataLen
< sizeof(*resp
) + 4 || *pos
!= EAP_TYPE_SIM
||
276 (ntohs(resp
->length
)) > respDataLen
) {
277 wpa_printf(MSG_INFO
, "EAP-SIM: Invalid frame");
282 if (subtype
== EAP_SIM_SUBTYPE_CLIENT_ERROR
)
285 switch (data
->state
) {
287 if (subtype
!= EAP_SIM_SUBTYPE_START
) {
288 wpa_printf(MSG_INFO
, "EAP-SIM: Unexpected response "
289 "subtype %d", subtype
);
294 if (subtype
!= EAP_SIM_SUBTYPE_CHALLENGE
) {
295 wpa_printf(MSG_INFO
, "EAP-SIM: Unexpected response "
296 "subtype %d", subtype
);
301 if (subtype
!= EAP_SIM_SUBTYPE_REAUTHENTICATION
) {
302 wpa_printf(MSG_INFO
, "EAP-SIM: Unexpected response "
303 "subtype %d", subtype
);
308 wpa_printf(MSG_INFO
, "EAP-SIM: Unexpected state (%d) for "
309 "processing a response", data
->state
);
317 static int eap_sim_supported_ver(struct eap_sim_data
*data
, int version
)
319 return version
== EAP_SIM_VERSION
;
323 static void eap_sim_process_start(struct eap_sm
*sm
,
324 struct eap_sim_data
*data
,
325 u8
*respData
, size_t respDataLen
,
326 struct eap_sim_attrs
*attr
)
332 wpa_printf(MSG_DEBUG
, "EAP-SIM: Receive start response");
334 if (attr
->nonce_mt
== NULL
|| attr
->selected_version
< 0) {
335 wpa_printf(MSG_DEBUG
, "EAP-SIM: Start/Response missing "
336 "required attributes");
337 eap_sim_state(data
, FAILURE
);
341 if (!eap_sim_supported_ver(data
, attr
->selected_version
)) {
342 wpa_printf(MSG_DEBUG
, "EAP-SIM: Peer selected unsupported "
343 "version %d", attr
->selected_version
);
344 eap_sim_state(data
, FAILURE
);
348 if (attr
->identity
) {
350 sm
->identity
= malloc(attr
->identity_len
);
352 memcpy(sm
->identity
, attr
->identity
,
354 sm
->identity_len
= attr
->identity_len
;
361 if (sm
->identity
&& sm
->identity_len
> 0 &&
362 sm
->identity
[0] == EAP_SIM_PERMANENT_PREFIX
) {
363 identity
= sm
->identity
;
364 identity_len
= sm
->identity_len
;
366 identity
= eap_sim_db_get_permanent(sm
->eap_sim_db_priv
,
370 if (identity
== NULL
) {
371 data
->reauth
= eap_sim_db_get_reauth_entry(
372 sm
->eap_sim_db_priv
, sm
->identity
,
375 wpa_printf(MSG_DEBUG
, "EAP-SIM: Using fast "
376 "re-authentication");
377 identity
= data
->reauth
->identity
;
378 identity_len
= data
->reauth
->identity_len
;
379 data
->counter
= data
->reauth
->counter
;
380 memcpy(data
->mk
, data
->reauth
->mk
,
386 if (identity
== NULL
) {
387 wpa_printf(MSG_DEBUG
, "EAP-SIM: Could not get proper permanent"
389 eap_sim_state(data
, FAILURE
);
393 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-SIM: Identity",
394 identity
, identity_len
);
397 eap_sim_state(data
, REAUTH
);
401 data
->counter
= 0; /* reset re-auth counter since this is full auth */
404 data
->num_chal
= eap_sim_db_get_gsm_triplets(
405 sm
->eap_sim_db_priv
, identity
, identity_len
,
407 (u8
*) data
->rand
, (u8
*) data
->kc
, (u8
*) data
->sres
, sm
);
408 if (data
->num_chal
== EAP_SIM_DB_PENDING
) {
409 wpa_printf(MSG_DEBUG
, "EAP-SIM: GSM authentication triplets "
410 "not yet available - pending request");
411 sm
->method_pending
= METHOD_PENDING_WAIT
;
414 if (data
->num_chal
< 2) {
415 wpa_printf(MSG_INFO
, "EAP-SIM: Failed to get GSM "
416 "authentication triplets for the peer");
417 eap_sim_state(data
, FAILURE
);
421 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-SIM: Identity for MK derivation",
422 sm
->identity
, sm
->identity_len
);
424 memcpy(data
->nonce_mt
, attr
->nonce_mt
, EAP_SIM_NONCE_MT_LEN
);
425 WPA_PUT_BE16(ver_list
, EAP_SIM_VERSION
);
426 eap_sim_derive_mk(sm
->identity
, sm
->identity_len
, attr
->nonce_mt
,
427 attr
->selected_version
, ver_list
, sizeof(ver_list
),
428 data
->num_chal
, (const u8
*) data
->kc
, data
->mk
);
429 eap_sim_derive_keys(data
->mk
, data
->k_encr
, data
->k_aut
, data
->msk
,
432 eap_sim_state(data
, CHALLENGE
);
436 static void eap_sim_process_challenge(struct eap_sm
*sm
,
437 struct eap_sim_data
*data
,
438 u8
*respData
, size_t respDataLen
,
439 struct eap_sim_attrs
*attr
)
444 if (attr
->mac
== NULL
||
445 eap_sim_verify_mac(data
->k_aut
, respData
, respDataLen
, attr
->mac
,
447 data
->num_chal
* EAP_SIM_SRES_LEN
)) {
448 wpa_printf(MSG_WARNING
, "EAP-SIM: Challenge message "
449 "did not include valid AT_MAC");
450 eap_sim_state(data
, FAILURE
);
454 wpa_printf(MSG_DEBUG
, "EAP-SIM: Challenge response includes the "
456 eap_sim_state(data
, SUCCESS
);
458 identity
= eap_sim_db_get_permanent(sm
->eap_sim_db_priv
, sm
->identity
,
459 sm
->identity_len
, &identity_len
);
460 if (identity
== NULL
) {
461 identity
= sm
->identity
;
462 identity_len
= sm
->identity_len
;
465 if (data
->next_pseudonym
) {
466 eap_sim_db_add_pseudonym(sm
->eap_sim_db_priv
, identity
,
468 data
->next_pseudonym
);
469 data
->next_pseudonym
= NULL
;
471 if (data
->next_reauth_id
) {
472 eap_sim_db_add_reauth(sm
->eap_sim_db_priv
, identity
,
474 data
->next_reauth_id
, data
->counter
+ 1,
476 data
->next_reauth_id
= NULL
;
481 static void eap_sim_process_reauth(struct eap_sm
*sm
,
482 struct eap_sim_data
*data
,
483 u8
*respData
, size_t respDataLen
,
484 struct eap_sim_attrs
*attr
)
486 struct eap_sim_attrs eattr
;
487 u8
*decrypted
= NULL
;
488 const u8
*identity
, *id2
;
489 size_t identity_len
, id2_len
;
491 if (attr
->mac
== NULL
||
492 eap_sim_verify_mac(data
->k_aut
, respData
, respDataLen
, attr
->mac
,
493 data
->nonce_s
, EAP_SIM_NONCE_S_LEN
)) {
494 wpa_printf(MSG_WARNING
, "EAP-SIM: Re-authentication message "
495 "did not include valid AT_MAC");
499 if (attr
->encr_data
== NULL
|| attr
->iv
== NULL
) {
500 wpa_printf(MSG_WARNING
, "EAP-SIM: Reauthentication "
501 "message did not include encrypted data");
505 decrypted
= eap_sim_parse_encr(data
->k_encr
, attr
->encr_data
,
506 attr
->encr_data_len
, attr
->iv
, &eattr
,
508 if (decrypted
== NULL
) {
509 wpa_printf(MSG_WARNING
, "EAP-SIM: Failed to parse encrypted "
510 "data from reauthentication message");
514 if (eattr
.counter
!= data
->counter
) {
515 wpa_printf(MSG_WARNING
, "EAP-SIM: Re-authentication message "
516 "used incorrect counter %u, expected %u",
517 eattr
.counter
, data
->counter
);
523 wpa_printf(MSG_DEBUG
, "EAP-SIM: Re-authentication response includes "
524 "the correct AT_MAC");
525 eap_sim_state(data
, SUCCESS
);
528 identity
= data
->reauth
->identity
;
529 identity_len
= data
->reauth
->identity_len
;
531 identity
= sm
->identity
;
532 identity_len
= sm
->identity_len
;
535 id2
= eap_sim_db_get_permanent(sm
->eap_sim_db_priv
, identity
,
536 identity_len
, &id2_len
);
539 identity_len
= id2_len
;
542 if (data
->next_pseudonym
) {
543 eap_sim_db_add_pseudonym(sm
->eap_sim_db_priv
, identity
,
544 identity_len
, data
->next_pseudonym
);
545 data
->next_pseudonym
= NULL
;
547 if (data
->next_reauth_id
) {
548 eap_sim_db_add_reauth(sm
->eap_sim_db_priv
, identity
,
549 identity_len
, data
->next_reauth_id
,
550 data
->counter
+ 1, data
->mk
);
551 data
->next_reauth_id
= NULL
;
553 eap_sim_db_remove_reauth(sm
->eap_sim_db_priv
, data
->reauth
);
560 eap_sim_state(data
, FAILURE
);
561 eap_sim_db_remove_reauth(sm
->eap_sim_db_priv
, data
->reauth
);
567 static void eap_sim_process_client_error(struct eap_sm
*sm
,
568 struct eap_sim_data
*data
,
569 u8
*respData
, size_t respDataLen
,
570 struct eap_sim_attrs
*attr
)
572 wpa_printf(MSG_DEBUG
, "EAP-SIM: Client reported error %d",
573 attr
->client_error_code
);
574 eap_sim_state(data
, FAILURE
);
578 static void eap_sim_process(struct eap_sm
*sm
, void *priv
,
579 u8
*respData
, size_t respDataLen
)
581 struct eap_sim_data
*data
= priv
;
582 struct eap_hdr
*resp
;
585 struct eap_sim_attrs attr
;
587 resp
= (struct eap_hdr
*) respData
;
588 pos
= (u8
*) (resp
+ 1);
590 len
= ntohs(resp
->length
);
593 if (eap_sim_parse_attr(pos
, respData
+ len
, &attr
, 0, 0)) {
594 wpa_printf(MSG_DEBUG
, "EAP-SIM: Failed to parse attributes");
595 eap_sim_state(data
, FAILURE
);
599 if (subtype
== EAP_SIM_SUBTYPE_CLIENT_ERROR
) {
600 eap_sim_process_client_error(sm
, data
, respData
, len
, &attr
);
604 switch (data
->state
) {
606 eap_sim_process_start(sm
, data
, respData
, len
, &attr
);
609 eap_sim_process_challenge(sm
, data
, respData
, len
, &attr
);
612 eap_sim_process_reauth(sm
, data
, respData
, len
, &attr
);
615 wpa_printf(MSG_DEBUG
, "EAP-SIM: Unknown state %d in "
616 "process", data
->state
);
622 static Boolean
eap_sim_isDone(struct eap_sm
*sm
, void *priv
)
624 struct eap_sim_data
*data
= priv
;
625 return data
->state
== SUCCESS
|| data
->state
== FAILURE
;
629 static u8
* eap_sim_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
631 struct eap_sim_data
*data
= priv
;
634 if (data
->state
!= SUCCESS
)
637 key
= malloc(EAP_SIM_KEYING_DATA_LEN
);
640 memcpy(key
, data
->msk
, EAP_SIM_KEYING_DATA_LEN
);
641 *len
= EAP_SIM_KEYING_DATA_LEN
;
646 static u8
* eap_sim_get_emsk(struct eap_sm
*sm
, void *priv
, size_t *len
)
648 struct eap_sim_data
*data
= priv
;
651 if (data
->state
!= SUCCESS
)
654 key
= malloc(EAP_EMSK_LEN
);
657 memcpy(key
, data
->emsk
, EAP_EMSK_LEN
);
663 static Boolean
eap_sim_isSuccess(struct eap_sm
*sm
, void *priv
)
665 struct eap_sim_data
*data
= priv
;
666 return data
->state
== SUCCESS
;
670 int eap_server_sim_register(void)
672 struct eap_method
*eap
;
675 eap
= eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION
,
676 EAP_VENDOR_IETF
, EAP_TYPE_SIM
, "SIM");
680 eap
->init
= eap_sim_init
;
681 eap
->reset
= eap_sim_reset
;
682 eap
->buildReq
= eap_sim_buildReq
;
683 eap
->check
= eap_sim_check
;
684 eap
->process
= eap_sim_process
;
685 eap
->isDone
= eap_sim_isDone
;
686 eap
->getKey
= eap_sim_getKey
;
687 eap
->isSuccess
= eap_sim_isSuccess
;
688 eap
->get_emsk
= eap_sim_get_emsk
;
690 ret
= eap_server_method_register(eap
);
692 eap_server_method_free(eap
);