2 * hostapd / EAP-SIM (draft-haverinen-pppext-eap-sim-15.txt)
3 * Copyright (c) 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.
18 #include <netinet/in.h>
24 #include "eap_sim_common.h"
25 #include "eap_sim_db.h"
28 #define EAP_SIM_VERSION 1
30 /* EAP-SIM Subtypes */
31 #define EAP_SIM_SUBTYPE_START 10
32 #define EAP_SIM_SUBTYPE_CHALLENGE 11
33 #define EAP_SIM_SUBTYPE_NOTIFICATION 12
34 #define EAP_SIM_SUBTYPE_REAUTHENTICATION 13
35 #define EAP_SIM_SUBTYPE_CLIENT_ERROR 14
37 /* AT_CLIENT_ERROR_CODE error codes */
38 #define EAP_SIM_UNABLE_TO_PROCESS_PACKET 0
39 #define EAP_SIM_UNSUPPORTED_VERSION 1
40 #define EAP_SIM_INSUFFICIENT_NUM_OF_CHAL 2
41 #define EAP_SIM_RAND_NOT_FRESH 3
45 #define EAP_SIM_MAX_FAST_REAUTHS 1000
47 #define EAP_SIM_MAX_CHAL 3
50 u8 mk
[EAP_SIM_MK_LEN
];
51 u8 nonce_mt
[EAP_SIM_NONCE_MT_LEN
];
52 u8 k_aut
[EAP_SIM_K_AUT_LEN
];
53 u8 k_encr
[EAP_SIM_K_ENCR_LEN
];
54 u8 msk
[EAP_SIM_KEYING_DATA_LEN
];
55 u8 kc
[EAP_SIM_MAX_CHAL
][KC_LEN
];
56 u8 sres
[EAP_SIM_MAX_CHAL
][SRES_LEN
];
57 u8 rand
[EAP_SIM_MAX_CHAL
][GSM_RAND_LEN
];
59 enum { START
, CHALLENGE
, SUCCESS
, FAILURE
} state
;
63 static const char * eap_sim_state_txt(int state
)
80 static void eap_sim_state(struct eap_sim_data
*data
, int state
)
82 wpa_printf(MSG_DEBUG
, "EAP-SIM %s -> %s",
83 eap_sim_state_txt(data
->state
),
84 eap_sim_state_txt(state
));
89 static void * eap_sim_init(struct eap_sm
*sm
)
91 struct eap_sim_data
*data
;
93 if (sm
->eap_sim_db_priv
== NULL
) {
94 wpa_printf(MSG_WARNING
, "EAP-SIM: eap_sim_db not configured");
98 data
= malloc(sizeof(*data
));
101 memset(data
, 0, sizeof(*data
));
108 static void eap_sim_reset(struct eap_sm
*sm
, void *priv
)
110 struct eap_sim_data
*data
= priv
;
115 static u8
* eap_sim_build_start(struct eap_sm
*sm
, struct eap_sim_data
*data
,
116 int id
, size_t *reqDataLen
)
118 struct eap_sim_msg
*msg
;
121 msg
= eap_sim_msg_init(EAP_CODE_REQUEST
, id
, EAP_TYPE_SIM
,
122 EAP_SIM_SUBTYPE_START
);
123 if (eap_sim_db_identity_known(sm
->eap_sim_db_priv
, sm
->identity
,
125 eap_sim_msg_add(msg
, EAP_SIM_AT_PERMANENT_ID_REQ
, 0, NULL
, 0);
128 ver
[1] = EAP_SIM_VERSION
;
129 eap_sim_msg_add(msg
, EAP_SIM_AT_VERSION_LIST
, sizeof(ver
),
131 return eap_sim_msg_finish(msg
, reqDataLen
, NULL
, NULL
, 0);
135 static u8
* eap_sim_build_challenge(struct eap_sm
*sm
,
136 struct eap_sim_data
*data
,
137 int id
, size_t *reqDataLen
)
139 struct eap_sim_msg
*msg
;
141 msg
= eap_sim_msg_init(EAP_CODE_REQUEST
, id
, EAP_TYPE_SIM
,
142 EAP_SIM_SUBTYPE_CHALLENGE
);
143 eap_sim_msg_add(msg
, EAP_SIM_AT_RAND
, 0, (u8
*) data
->rand
,
144 data
->num_chal
* GSM_RAND_LEN
);
145 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
146 return eap_sim_msg_finish(msg
, reqDataLen
, data
->k_aut
, data
->nonce_mt
,
147 EAP_SIM_NONCE_MT_LEN
);
151 static u8
* eap_sim_buildReq(struct eap_sm
*sm
, void *priv
, int id
,
154 struct eap_sim_data
*data
= priv
;
156 switch (data
->state
) {
158 return eap_sim_build_start(sm
, data
, id
, reqDataLen
);
160 return eap_sim_build_challenge(sm
, data
, id
, reqDataLen
);
162 wpa_printf(MSG_DEBUG
, "EAP-SIM: Unknown state %d in "
163 "buildReq", data
->state
);
170 static Boolean
eap_sim_check(struct eap_sm
*sm
, void *priv
,
171 u8
*respData
, size_t respDataLen
)
173 struct eap_sim_data
*data
= priv
;
174 struct eap_hdr
*resp
;
178 resp
= (struct eap_hdr
*) respData
;
179 pos
= (u8
*) (resp
+ 1);
180 if (respDataLen
< sizeof(*resp
) + 4 || *pos
!= EAP_TYPE_SIM
||
181 (len
= ntohs(resp
->length
)) > respDataLen
) {
182 wpa_printf(MSG_INFO
, "EAP-SIM: Invalid frame");
187 if (subtype
== EAP_SIM_SUBTYPE_CLIENT_ERROR
)
190 switch (data
->state
) {
192 if (subtype
!= EAP_SIM_SUBTYPE_START
) {
193 wpa_printf(MSG_INFO
, "EAP-SIM: Unexpected response "
194 "subtype %d", subtype
);
199 if (subtype
!= EAP_SIM_SUBTYPE_CHALLENGE
) {
200 wpa_printf(MSG_INFO
, "EAP-SIM: Unexpected response "
201 "subtype %d", subtype
);
206 wpa_printf(MSG_INFO
, "EAP-SIM: Unexpected state (%d) for "
207 "processing a response", data
->state
);
215 static int eap_sim_supported_ver(struct eap_sim_data
*data
, int version
)
217 return version
== EAP_SIM_VERSION
;
221 static void eap_sim_derive_mk(struct eap_sim_data
*data
,
222 const u8
*identity
, size_t identity_len
,
223 const u8
*nonce_mt
, int selected_version
,
224 int num_chal
, const u8
*kc
)
226 u8 sel_ver
[2], ver_list
[2];
227 const unsigned char *addr
[5];
236 len
[0] = identity_len
;
237 len
[1] = num_chal
* KC_LEN
;
238 len
[2] = EAP_SIM_NONCE_MT_LEN
;
239 len
[3] = sizeof(ver_list
);
240 len
[4] = sizeof(sel_ver
);
243 ver_list
[1] = EAP_SIM_VERSION
;
244 sel_ver
[0] = selected_version
>> 8;
245 sel_ver
[1] = selected_version
& 0xff;
247 /* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
248 sha1_vector(5, addr
, len
, data
->mk
);
249 wpa_hexdump_key(MSG_DEBUG
, "EAP-SIM: MK", data
->mk
, EAP_SIM_MK_LEN
);
253 static void eap_sim_process_start(struct eap_sm
*sm
,
254 struct eap_sim_data
*data
,
255 u8
*respData
, size_t respDataLen
,
256 struct eap_sim_attrs
*attr
)
258 wpa_printf(MSG_DEBUG
, "EAP-SIM: Receive start response");
260 if (attr
->nonce_mt
== NULL
|| attr
->selected_version
< 0) {
261 wpa_printf(MSG_DEBUG
, "EAP-SIM: Start/Response missing "
262 "required attributes");
263 eap_sim_state(data
, FAILURE
);
267 if (!eap_sim_supported_ver(data
, attr
->selected_version
)) {
268 wpa_printf(MSG_DEBUG
, "EAP-SIM: Peer selected unsupported "
269 "version %d", attr
->selected_version
);
270 eap_sim_state(data
, FAILURE
);
274 if (attr
->identity
) {
276 sm
->identity
= malloc(attr
->identity_len
);
278 memcpy(sm
->identity
, attr
->identity
,
280 sm
->identity_len
= attr
->identity_len
;
284 if (sm
->identity
== NULL
|| sm
->identity_len
< 1 ||
285 sm
->identity
[0] != '1') {
286 wpa_printf(MSG_DEBUG
, "EAP-SIM: Could not get proper permanent"
288 eap_sim_state(data
, FAILURE
);
292 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-SIM: Identity",
293 sm
->identity
, sm
->identity_len
);
295 data
->num_chal
= eap_sim_db_get_gsm_triplets(
296 sm
->eap_sim_db_priv
, sm
->identity
, sm
->identity_len
,
298 (u8
*) data
->rand
, (u8
*) data
->kc
, (u8
*) data
->sres
);
299 if (data
->num_chal
< 2) {
300 wpa_printf(MSG_INFO
, "EAP-SIM: Failed to get GSM "
301 "authentication triplets for the peer");
302 eap_sim_state(data
, FAILURE
);
306 memcpy(data
->nonce_mt
, attr
->nonce_mt
, EAP_SIM_NONCE_MT_LEN
);
307 eap_sim_derive_mk(data
, sm
->identity
, sm
->identity_len
, attr
->nonce_mt
,
308 attr
->selected_version
, data
->num_chal
,
310 eap_sim_derive_keys(data
->mk
, data
->k_encr
, data
->k_aut
, data
->msk
);
312 eap_sim_state(data
, CHALLENGE
);
316 static void eap_sim_process_challenge(struct eap_sm
*sm
,
317 struct eap_sim_data
*data
,
318 u8
*respData
, size_t respDataLen
,
319 struct eap_sim_attrs
*attr
)
321 if (attr
->mac
== NULL
||
322 eap_sim_verify_mac(data
->k_aut
, respData
, respDataLen
, attr
->mac
,
323 (u8
*) data
->sres
, data
->num_chal
* SRES_LEN
)) {
324 wpa_printf(MSG_WARNING
, "EAP-SIM: Challenge message "
325 "did not include valid AT_MAC");
326 eap_sim_state(data
, FAILURE
);
330 wpa_printf(MSG_DEBUG
, "EAP-SIM: Challenge response includes the "
332 eap_sim_state(data
, SUCCESS
);
336 static void eap_sim_process_client_error(struct eap_sm
*sm
,
337 struct eap_sim_data
*data
,
338 u8
*respData
, size_t respDataLen
,
339 struct eap_sim_attrs
*attr
)
341 wpa_printf(MSG_DEBUG
, "EAP-SIM: Client reported error %d",
342 attr
->client_error_code
);
343 eap_sim_state(data
, FAILURE
);
347 static void eap_sim_process(struct eap_sm
*sm
, void *priv
,
348 u8
*respData
, size_t respDataLen
)
350 struct eap_sim_data
*data
= priv
;
351 struct eap_hdr
*resp
;
354 struct eap_sim_attrs attr
;
356 resp
= (struct eap_hdr
*) respData
;
357 pos
= (u8
*) (resp
+ 1);
359 len
= ntohs(resp
->length
);
362 if (eap_sim_parse_attr(pos
, respData
+ len
, &attr
, 0, 0)) {
363 wpa_printf(MSG_DEBUG
, "EAP-SIM: Failed to parse attributes");
364 eap_sim_state(data
, FAILURE
);
368 if (subtype
== EAP_SIM_SUBTYPE_CLIENT_ERROR
) {
369 eap_sim_process_client_error(sm
, data
, respData
, len
, &attr
);
373 switch (data
->state
) {
375 eap_sim_process_start(sm
, data
, respData
, len
, &attr
);
378 eap_sim_process_challenge(sm
, data
, respData
, len
, &attr
);
381 wpa_printf(MSG_DEBUG
, "EAP-SIM: Unknown state %d in "
382 "process", data
->state
);
388 static Boolean
eap_sim_isDone(struct eap_sm
*sm
, void *priv
)
390 struct eap_sim_data
*data
= priv
;
391 return data
->state
== SUCCESS
|| data
->state
== FAILURE
;
395 static u8
* eap_sim_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
397 struct eap_sim_data
*data
= priv
;
400 if (data
->state
!= SUCCESS
)
403 key
= malloc(EAP_SIM_KEYING_DATA_LEN
);
406 memcpy(key
, data
->msk
, EAP_SIM_KEYING_DATA_LEN
);
407 *len
= EAP_SIM_KEYING_DATA_LEN
;
412 static Boolean
eap_sim_isSuccess(struct eap_sm
*sm
, void *priv
)
414 struct eap_sim_data
*data
= priv
;
415 return data
->state
== SUCCESS
;
419 const struct eap_method eap_method_sim
=
421 .method
= EAP_TYPE_SIM
,
423 .init
= eap_sim_init
,
424 .reset
= eap_sim_reset
,
425 .buildReq
= eap_sim_buildReq
,
426 .check
= eap_sim_check
,
427 .process
= eap_sim_process
,
428 .isDone
= eap_sim_isDone
,
429 .getKey
= eap_sim_getKey
,
430 .isSuccess
= eap_sim_isSuccess
,