1 /*
2  * hostapd / EAP-SIM (RFC 4186)
3  * Copyright (c) 2005-2012, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "includes.h"
10 
11 #include "common.h"
12 #include "utils/base64.h"
13 #include "crypto/crypto.h"
14 #include "crypto/random.h"
15 #include "eap_server/eap_i.h"
16 #include "eap_common/eap_sim_common.h"
17 #include "eap_server/eap_sim_db.h"
18 
19 
20 struct eap_sim_data {
21           u8 mk[EAP_SIM_MK_LEN];
22           u8 nonce_mt[EAP_SIM_NONCE_MT_LEN];
23           u8 nonce_s[EAP_SIM_NONCE_S_LEN];
24           u8 k_aut[EAP_SIM_K_AUT_LEN];
25           u8 k_encr[EAP_SIM_K_ENCR_LEN];
26           u8 msk[EAP_SIM_KEYING_DATA_LEN];
27           u8 emsk[EAP_EMSK_LEN];
28           u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
29           u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
30           u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
31           u8 reauth_mac[EAP_SIM_MAC_LEN];
32           int num_chal;
33           enum {
34                     START, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE
35           } state;
36           char *next_pseudonym;
37           char *next_reauth_id;
38           u16 counter;
39           struct eap_sim_reauth *reauth;
40           u16 notification;
41           int use_result_ind;
42           int start_round;
43           char permanent[20]; /* Permanent username */
44 };
45 
46 
eap_sim_state_txt(int state)47 static const char * eap_sim_state_txt(int state)
48 {
49           switch (state) {
50           case START:
51                     return "START";
52           case CHALLENGE:
53                     return "CHALLENGE";
54           case REAUTH:
55                     return "REAUTH";
56           case SUCCESS:
57                     return "SUCCESS";
58           case FAILURE:
59                     return "FAILURE";
60           case NOTIFICATION:
61                     return "NOTIFICATION";
62           default:
63                     return "Unknown?!";
64           }
65 }
66 
67 
eap_sim_state(struct eap_sim_data * data,int state)68 static void eap_sim_state(struct eap_sim_data *data, int state)
69 {
70           wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s",
71                        eap_sim_state_txt(data->state),
72                        eap_sim_state_txt(state));
73           data->state = state;
74 }
75 
76 
eap_sim_init(struct eap_sm * sm)77 static void * eap_sim_init(struct eap_sm *sm)
78 {
79           struct eap_sim_data *data;
80 
81           if (!sm->cfg->eap_sim_db_priv) {
82                     wpa_printf(MSG_WARNING, "EAP-SIM: eap_sim_db not configured");
83                     return NULL;
84           }
85 
86           data = os_zalloc(sizeof(*data));
87           if (data == NULL)
88                     return NULL;
89           data->state = START;
90 
91           return data;
92 }
93 
94 
eap_sim_reset(struct eap_sm * sm,void * priv)95 static void eap_sim_reset(struct eap_sm *sm, void *priv)
96 {
97           struct eap_sim_data *data = priv;
98           os_free(data->next_pseudonym);
99           os_free(data->next_reauth_id);
100           bin_clear_free(data, sizeof(*data));
101 }
102 
103 
eap_sim_build_start(struct eap_sm * sm,struct eap_sim_data * data,u8 id)104 static struct wpabuf * eap_sim_build_start(struct eap_sm *sm,
105                                                      struct eap_sim_data *data, u8 id)
106 {
107           struct eap_sim_msg *msg;
108           u8 ver[2];
109           bool id_req = true;
110 
111           wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Start");
112           msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
113                                      EAP_SIM_SUBTYPE_START);
114           data->start_round++;
115 
116           if (data->start_round == 1 && (sm->cfg->eap_sim_id & 0x04)) {
117                     char *username;
118 
119                     username = sim_get_username(sm->identity, sm->identity_len);
120                     if (username && username[0] == EAP_SIM_REAUTH_ID_PREFIX &&
121                         eap_sim_db_get_reauth_entry(sm->cfg->eap_sim_db_priv,
122                                                             username))
123                               id_req = false;
124 
125                     os_free(username);
126           }
127 
128           if (!id_req) {
129                     wpa_printf(MSG_DEBUG, "   No identity request");
130           } else if (data->start_round == 1) {
131                     /*
132                      * RFC 4186, Chap. 4.2.4 recommends that identity from EAP is
133                      * ignored and the SIM/Start is used to request the identity.
134                      */
135                     wpa_printf(MSG_DEBUG, "   AT_ANY_ID_REQ");
136                     eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
137           } else if (data->start_round > 3) {
138                     /* Cannot use more than three rounds of Start messages */
139                     eap_sim_msg_free(msg);
140                     return NULL;
141           } else if (data->start_round == 0) {
142                     /*
143                      * This is a special case that is used to recover from
144                      * AT_COUNTER_TOO_SMALL during re-authentication. Since we
145                      * already know the identity of the peer, there is no need to
146                      * request any identity in this case.
147                      */
148           } else if (sm->identity && sm->identity_len > 0 &&
149                        sm->identity[0] == EAP_SIM_REAUTH_ID_PREFIX) {
150                     /* Reauth id may have expired - try fullauth */
151                     wpa_printf(MSG_DEBUG, "   AT_FULLAUTH_ID_REQ");
152                     eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0, NULL, 0);
153           } else {
154                     wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
155                     eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
156           }
157           wpa_printf(MSG_DEBUG, "   AT_VERSION_LIST");
158           ver[0] = 0;
159           ver[1] = EAP_SIM_VERSION;
160           eap_sim_msg_add(msg, EAP_SIM_AT_VERSION_LIST, sizeof(ver),
161                               ver, sizeof(ver));
162           return eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0);
163 }
164 
165 
eap_sim_build_encr(struct eap_sm * sm,struct eap_sim_data * data,struct eap_sim_msg * msg,u16 counter,const u8 * nonce_s)166 static int eap_sim_build_encr(struct eap_sm *sm, struct eap_sim_data *data,
167                                     struct eap_sim_msg *msg, u16 counter,
168                                     const u8 *nonce_s)
169 {
170           os_free(data->next_pseudonym);
171           if (!(sm->cfg->eap_sim_id & 0x01)) {
172                     /* Use of pseudonyms disabled in configuration */
173                     data->next_pseudonym = NULL;
174           } else if (!nonce_s) {
175                     data->next_pseudonym =
176                               eap_sim_db_get_next_pseudonym(sm->cfg->eap_sim_db_priv,
177                                                                   EAP_SIM_DB_SIM);
178           } else {
179                     /* Do not update pseudonym during re-authentication */
180                     data->next_pseudonym = NULL;
181           }
182           os_free(data->next_reauth_id);
183           if (!(sm->cfg->eap_sim_id & 0x02)) {
184                     /* Use of fast reauth disabled in configuration */
185                     data->next_reauth_id = NULL;
186           } else if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) {
187                     data->next_reauth_id =
188                               eap_sim_db_get_next_reauth_id(sm->cfg->eap_sim_db_priv,
189                                                                   EAP_SIM_DB_SIM);
190           } else {
191                     wpa_printf(MSG_DEBUG, "EAP-SIM: Max fast re-authentication "
192                                  "count exceeded - force full authentication");
193                     data->next_reauth_id = NULL;
194           }
195 
196           if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
197               counter == 0 && nonce_s == NULL)
198                     return 0;
199 
200           wpa_printf(MSG_DEBUG, "   AT_IV");
201           wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
202           eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
203 
204           if (counter > 0) {
205                     wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)", counter);
206                     eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
207           }
208 
209           if (nonce_s) {
210                     wpa_printf(MSG_DEBUG, "   *AT_NONCE_S");
211                     eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
212                                         EAP_SIM_NONCE_S_LEN);
213           }
214 
215           if (data->next_pseudonym) {
216                     wpa_printf(MSG_DEBUG, "   *AT_NEXT_PSEUDONYM (%s)",
217                                  data->next_pseudonym);
218                     eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
219                                         os_strlen(data->next_pseudonym),
220                                         (u8 *) data->next_pseudonym,
221                                         os_strlen(data->next_pseudonym));
222           }
223 
224           if (data->next_reauth_id) {
225                     wpa_printf(MSG_DEBUG, "   *AT_NEXT_REAUTH_ID (%s)",
226                                  data->next_reauth_id);
227                     eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
228                                         os_strlen(data->next_reauth_id),
229                                         (u8 *) data->next_reauth_id,
230                                         os_strlen(data->next_reauth_id));
231           }
232 
233           if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
234                     wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
235                                  "AT_ENCR_DATA");
236                     return -1;
237           }
238 
239           return 0;
240 }
241 
242 
eap_sim_build_challenge(struct eap_sm * sm,struct eap_sim_data * data,u8 id)243 static struct wpabuf * eap_sim_build_challenge(struct eap_sm *sm,
244                                                          struct eap_sim_data *data,
245                                                          u8 id)
246 {
247           struct eap_sim_msg *msg;
248 
249           wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Challenge");
250           msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
251                                      EAP_SIM_SUBTYPE_CHALLENGE);
252           wpa_printf(MSG_DEBUG, "   AT_RAND");
253           eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, (u8 *) data->rand,
254                               data->num_chal * GSM_RAND_LEN);
255 
256           if (eap_sim_build_encr(sm, data, msg, 0, NULL)) {
257                     eap_sim_msg_free(msg);
258                     return NULL;
259           }
260 
261           if (sm->cfg->eap_sim_aka_result_ind) {
262                     wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
263                     eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
264           }
265 
266           wpa_printf(MSG_DEBUG, "   AT_MAC");
267           eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
268           return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut,
269                                           data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
270 }
271 
272 
eap_sim_build_reauth(struct eap_sm * sm,struct eap_sim_data * data,u8 id)273 static struct wpabuf * eap_sim_build_reauth(struct eap_sm *sm,
274                                                       struct eap_sim_data *data, u8 id)
275 {
276           struct eap_sim_msg *msg;
277           struct wpabuf *buf;
278 
279           wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Re-authentication");
280 
281           if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN))
282                     return NULL;
283           wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: NONCE_S",
284                               data->nonce_s, EAP_SIM_NONCE_S_LEN);
285 
286           eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
287                                   data->emsk);
288           eap_sim_derive_keys_reauth(data->counter, sm->identity,
289                                            sm->identity_len, data->nonce_s, data->mk,
290                                            data->msk, data->emsk);
291 
292           msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
293                                      EAP_SIM_SUBTYPE_REAUTHENTICATION);
294 
295           if (eap_sim_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
296                     eap_sim_msg_free(msg);
297                     return NULL;
298           }
299 
300           if (sm->cfg->eap_sim_aka_result_ind) {
301                     wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
302                     eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
303           }
304 
305           wpa_printf(MSG_DEBUG, "   AT_MAC");
306           eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
307           buf = eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, NULL, 0);
308 
309           /* Remember this MAC before sending it to the peer. This MAC is used for
310            * Session-Id calculation after receiving response from the peer and
311            * after all other checks pass. */
312           os_memcpy(data->reauth_mac,
313                       wpabuf_head_u8(buf) + wpabuf_len(buf) - EAP_SIM_MAC_LEN,
314                       EAP_SIM_MAC_LEN);
315 
316           return buf;
317 }
318 
319 
eap_sim_build_notification(struct eap_sm * sm,struct eap_sim_data * data,u8 id)320 static struct wpabuf * eap_sim_build_notification(struct eap_sm *sm,
321                                                               struct eap_sim_data *data,
322                                                               u8 id)
323 {
324           struct eap_sim_msg *msg;
325 
326           wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Notification");
327           msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
328                                      EAP_SIM_SUBTYPE_NOTIFICATION);
329           wpa_printf(MSG_DEBUG, "   AT_NOTIFICATION (%d)", data->notification);
330           eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
331                               NULL, 0);
332           if (data->use_result_ind) {
333                     if (data->reauth) {
334                               wpa_printf(MSG_DEBUG, "   AT_IV");
335                               wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
336                               eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
337                                                                EAP_SIM_AT_ENCR_DATA);
338                               wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)",
339                                            data->counter);
340                               eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
341                                                   NULL, 0);
342 
343                               if (eap_sim_msg_add_encr_end(msg, data->k_encr,
344                                                                  EAP_SIM_AT_PADDING)) {
345                                         wpa_printf(MSG_WARNING, "EAP-SIM: Failed to "
346                                                      "encrypt AT_ENCR_DATA");
347                                         eap_sim_msg_free(msg);
348                                         return NULL;
349                               }
350                     }
351 
352                     wpa_printf(MSG_DEBUG, "   AT_MAC");
353                     eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
354           }
355           return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, NULL, 0);
356 }
357 
358 
eap_sim_buildReq(struct eap_sm * sm,void * priv,u8 id)359 static struct wpabuf * eap_sim_buildReq(struct eap_sm *sm, void *priv, u8 id)
360 {
361           struct eap_sim_data *data = priv;
362 
363           switch (data->state) {
364           case START:
365                     return eap_sim_build_start(sm, data, id);
366           case CHALLENGE:
367                     return eap_sim_build_challenge(sm, data, id);
368           case REAUTH:
369                     return eap_sim_build_reauth(sm, data, id);
370           case NOTIFICATION:
371                     return eap_sim_build_notification(sm, data, id);
372           default:
373                     wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
374                                  "buildReq", data->state);
375                     break;
376           }
377           return NULL;
378 }
379 
380 
eap_sim_check(struct eap_sm * sm,void * priv,struct wpabuf * respData)381 static bool eap_sim_check(struct eap_sm *sm, void *priv,
382                                 struct wpabuf *respData)
383 {
384           const u8 *pos;
385           size_t len;
386 
387           pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len);
388           if (pos == NULL || len < 3) {
389                     wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame");
390                     return true;
391           }
392 
393           return false;
394 }
395 
396 
eap_sim_unexpected_subtype(struct eap_sim_data * data,u8 subtype)397 static bool eap_sim_unexpected_subtype(struct eap_sim_data *data,
398                                                u8 subtype)
399 {
400           if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR)
401                     return false;
402 
403           switch (data->state) {
404           case START:
405                     if (subtype != EAP_SIM_SUBTYPE_START) {
406                               wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
407                                            "subtype %d", subtype);
408                               return true;
409                     }
410                     break;
411           case CHALLENGE:
412                     if (subtype != EAP_SIM_SUBTYPE_CHALLENGE) {
413                               wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
414                                            "subtype %d", subtype);
415                               return true;
416                     }
417                     break;
418           case REAUTH:
419                     if (subtype != EAP_SIM_SUBTYPE_REAUTHENTICATION) {
420                               wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
421                                            "subtype %d", subtype);
422                               return true;
423                     }
424                     break;
425           case NOTIFICATION:
426                     if (subtype != EAP_SIM_SUBTYPE_NOTIFICATION) {
427                               wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
428                                            "subtype %d", subtype);
429                               return true;
430                     }
431                     break;
432           default:
433                     wpa_printf(MSG_INFO, "EAP-SIM: Unexpected state (%d) for "
434                                  "processing a response", data->state);
435                     return true;
436           }
437 
438           return false;
439 }
440 
441 
eap_sim_supported_ver(struct eap_sim_data * data,int version)442 static int eap_sim_supported_ver(struct eap_sim_data *data, int version)
443 {
444           return version == EAP_SIM_VERSION;
445 }
446 
447 
eap_sim_process_start(struct eap_sm * sm,struct eap_sim_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)448 static void eap_sim_process_start(struct eap_sm *sm,
449                                           struct eap_sim_data *data,
450                                           struct wpabuf *respData,
451                                           struct eap_sim_attrs *attr)
452 {
453           const u8 *identity;
454           size_t identity_len;
455           u8 ver_list[2];
456           u8 *new_identity;
457           char *username;
458 
459           wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response");
460 
461           if (data->start_round == 0) {
462                     /*
463                      * Special case for AT_COUNTER_TOO_SMALL recovery - no identity
464                      * was requested since we already know it.
465                      */
466                     goto skip_id_update;
467           }
468 
469           if ((sm->cfg->eap_sim_id & 0x04) &&
470               (!attr->identity || attr->identity_len == 0))
471                     goto skip_id_attr;
472 
473           /*
474            * Unless explicitly configured otherwise, we always request identity
475            * in SIM/Start, so the peer is required to have replied with one.
476            */
477           if (!attr->identity || attr->identity_len == 0) {
478                     wpa_printf(MSG_DEBUG, "EAP-SIM: Peer did not provide any "
479                                  "identity");
480                     goto failed;
481           }
482 
483           new_identity = os_malloc(attr->identity_len);
484           if (new_identity == NULL)
485                     goto failed;
486           os_free(sm->identity);
487           sm->identity = new_identity;
488           os_memcpy(sm->identity, attr->identity, attr->identity_len);
489           sm->identity_len = attr->identity_len;
490 
491 skip_id_attr:
492           if (sm->sim_aka_permanent[0]) {
493                     identity = (const u8 *) sm->sim_aka_permanent;
494                     identity_len = os_strlen(sm->sim_aka_permanent);
495           } else {
496                     identity = sm->identity;
497                     identity_len = sm->identity_len;
498           }
499           wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
500                                 identity, identity_len);
501           username = sim_get_username(identity, identity_len);
502           if (username == NULL)
503                     goto failed;
504 
505           if (username[0] == EAP_SIM_REAUTH_ID_PREFIX) {
506                     wpa_printf(MSG_DEBUG, "EAP-SIM: Reauth username '%s'",
507                                  username);
508                     data->reauth = eap_sim_db_get_reauth_entry(
509                               sm->cfg->eap_sim_db_priv, username);
510                     os_free(username);
511                     if (data->reauth == NULL) {
512                               wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown reauth "
513                                            "identity - request full auth identity");
514                               /* Remain in START state for another round */
515                               return;
516                     }
517 
518                     if (data->reauth->counter >
519                         sm->cfg->eap_sim_aka_fast_reauth_limit &&
520                         (sm->cfg->eap_sim_id & 0x04)) {
521                               wpa_printf(MSG_DEBUG,
522                                            "EAP-SIM: Too many fast re-authentication attemps - fall back to full authentication");
523                               wpa_printf(MSG_DEBUG,
524                                            "EAP-SIM: Permanent identity recognized - skip new Identity query");
525                               os_strlcpy(data->permanent,
526                                            data->reauth->permanent,
527                                            sizeof(data->permanent));
528                               os_strlcpy(sm->sim_aka_permanent,
529                                            data->reauth->permanent,
530                                            sizeof(sm->sim_aka_permanent));
531                               eap_sim_db_remove_reauth(
532                                         sm->cfg->eap_sim_db_priv,
533                                         data->reauth);
534                               data->reauth = NULL;
535                               goto skip_id_update;
536                     }
537 
538                     wpa_printf(MSG_DEBUG,
539                                  "EAP-SIM: Using fast re-authentication (counter=%d)",
540                                  data->reauth->counter);
541                     os_strlcpy(data->permanent, data->reauth->permanent,
542                                  sizeof(data->permanent));
543                     data->counter = data->reauth->counter;
544                     os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN);
545                     eap_sim_state(data, REAUTH);
546                     return;
547           }
548 
549           if (username[0] == EAP_SIM_PSEUDONYM_PREFIX) {
550                     const char *permanent;
551                     wpa_printf(MSG_DEBUG, "EAP-SIM: Pseudonym username '%s'",
552                                  username);
553                     permanent = eap_sim_db_get_permanent(
554                               sm->cfg->eap_sim_db_priv, username);
555                     os_free(username);
556                     if (permanent == NULL) {
557                               wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown pseudonym "
558                                            "identity - request permanent identity");
559                               /* Remain in START state for another round */
560                               return;
561                     }
562                     os_strlcpy(data->permanent, permanent,
563                                  sizeof(data->permanent));
564           } else if (username[0] == EAP_SIM_PERMANENT_PREFIX) {
565                     wpa_printf(MSG_DEBUG, "EAP-SIM: Permanent username '%s'",
566                                  username);
567                     os_strlcpy(data->permanent, username, sizeof(data->permanent));
568                     os_free(username);
569 #ifdef CRYPTO_RSA_OAEP_SHA256
570           } else if (sm->identity_len > 1 && sm->identity[0] == '\0') {
571                     char *enc_id, *pos, *end;
572                     size_t enc_id_len;
573                     u8 *decoded_id;
574                     size_t decoded_id_len;
575                     struct wpabuf *enc, *dec;
576                     u8 *new_id;
577 
578                     os_free(username);
579                     if (!sm->cfg->imsi_privacy_key) {
580                               wpa_printf(MSG_DEBUG,
581                                            "EAP-SIM: Received encrypted identity, but no IMSI privacy key configured to decrypt it");
582                               goto failed;
583                     }
584 
585                     enc_id = (char *) &sm->identity[1];
586                     end = (char *) &sm->identity[sm->identity_len];
587                     for (pos = enc_id; pos < end; pos++) {
588                               if (*pos == ',')
589                                         break;
590                     }
591                     enc_id_len = pos - enc_id;
592 
593                     wpa_hexdump_ascii(MSG_DEBUG,
594                                           "EAP-SIM: Encrypted permanent identity",
595                                           enc_id, enc_id_len);
596                     decoded_id = base64_decode(enc_id, enc_id_len, &decoded_id_len);
597                     if (!decoded_id) {
598                               wpa_printf(MSG_DEBUG,
599                                            "EAP-SIM: Could not base64 decode encrypted identity");
600                               goto failed;
601                     }
602                     wpa_hexdump(MSG_DEBUG,
603                                   "EAP-SIM: Decoded encrypted permanent identity",
604                                   decoded_id, decoded_id_len);
605                     enc = wpabuf_alloc_copy(decoded_id, decoded_id_len);
606                     os_free(decoded_id);
607                     if (!enc)
608                               goto failed;
609                     dec = crypto_rsa_oaep_sha256_decrypt(sm->cfg->imsi_privacy_key,
610                                                                  enc);
611                     wpabuf_free(enc);
612                     if (!dec) {
613                               wpa_printf(MSG_DEBUG,
614                                            "EAP-SIM: Failed to decrypt encrypted identity");
615                               goto failed;
616                     }
617                     wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Decrypted permanent identity",
618                                           wpabuf_head(dec), wpabuf_len(dec));
619                     username = sim_get_username(wpabuf_head(dec), wpabuf_len(dec));
620                     if (!username) {
621                               wpabuf_free(dec);
622                               goto failed;
623                     }
624                     new_id = os_memdup(wpabuf_head(dec), wpabuf_len(dec));
625                     if (!new_id) {
626                               wpabuf_free(dec);
627                               goto failed;
628                     }
629                     os_free(sm->identity);
630                     sm->identity = new_id;
631                     sm->identity_len = wpabuf_len(dec);
632                     wpabuf_free(dec);
633                     os_strlcpy(data->permanent, username, sizeof(data->permanent));
634                     os_free(username);
635 #endif /* CRYPTO_RSA_OAEP_SHA256 */
636           } else {
637                     wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized username '%s'",
638                                  username);
639                     os_free(username);
640                     goto failed;
641           }
642 
643 skip_id_update:
644           /* Full authentication */
645 
646           if (attr->nonce_mt == NULL || attr->selected_version < 0) {
647                     wpa_printf(MSG_DEBUG, "EAP-SIM: Start/Response missing "
648                                  "required attributes");
649                     goto failed;
650           }
651 
652           if (!eap_sim_supported_ver(data, attr->selected_version)) {
653                     wpa_printf(MSG_DEBUG, "EAP-SIM: Peer selected unsupported "
654                                  "version %d", attr->selected_version);
655                     goto failed;
656           }
657 
658           data->counter = 0; /* reset re-auth counter since this is full auth */
659           data->reauth = NULL;
660 
661           data->num_chal = eap_sim_db_get_gsm_triplets(
662                     sm->cfg->eap_sim_db_priv, data->permanent, EAP_SIM_MAX_CHAL,
663                     (u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm);
664           if (data->num_chal == EAP_SIM_DB_PENDING) {
665                     wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets "
666                                  "not yet available - pending request");
667                     sm->method_pending = METHOD_PENDING_WAIT;
668                     return;
669           }
670           if (data->num_chal < 2) {
671                     wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM "
672                                  "authentication triplets for the peer");
673                     goto failed;
674           }
675 
676           if (data->permanent[0] == EAP_SIM_PERMANENT_PREFIX)
677                     os_strlcpy(sm->imsi, &data->permanent[1], sizeof(sm->imsi));
678 
679           identity_len = sm->identity_len;
680           while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
681                     wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop last null "
682                                  "character from identity");
683                     identity_len--;
684           }
685           wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity for MK derivation",
686                                 sm->identity, identity_len);
687 
688           os_memcpy(data->nonce_mt, attr->nonce_mt, EAP_SIM_NONCE_MT_LEN);
689           WPA_PUT_BE16(ver_list, EAP_SIM_VERSION);
690           eap_sim_derive_mk(sm->identity, identity_len, attr->nonce_mt,
691                                 attr->selected_version, ver_list, sizeof(ver_list),
692                                 data->num_chal, (const u8 *) data->kc, data->mk);
693           eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
694                                   data->emsk);
695 
696           eap_sim_state(data, CHALLENGE);
697           return;
698 
699 failed:
700           data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
701           eap_sim_state(data, NOTIFICATION);
702 }
703 
704 
eap_sim_process_challenge(struct eap_sm * sm,struct eap_sim_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)705 static void eap_sim_process_challenge(struct eap_sm *sm,
706                                               struct eap_sim_data *data,
707                                               struct wpabuf *respData,
708                                               struct eap_sim_attrs *attr)
709 {
710           if (attr->mac == NULL ||
711               eap_sim_verify_mac(data->k_aut, respData, attr->mac,
712                                      (u8 *) data->sres,
713                                      data->num_chal * EAP_SIM_SRES_LEN)) {
714                     wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
715                                  "did not include valid AT_MAC");
716                     data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
717                     eap_sim_state(data, NOTIFICATION);
718                     return;
719           }
720 
721           wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the "
722                        "correct AT_MAC");
723           if (sm->cfg->eap_sim_aka_result_ind && attr->result_ind) {
724                     data->use_result_ind = 1;
725                     data->notification = EAP_SIM_SUCCESS;
726                     eap_sim_state(data, NOTIFICATION);
727           } else
728                     eap_sim_state(data, SUCCESS);
729 
730           if (data->next_pseudonym) {
731                     eap_sim_db_add_pseudonym(sm->cfg->eap_sim_db_priv,
732                                                    data->permanent,
733                                                    data->next_pseudonym);
734                     data->next_pseudonym = NULL;
735           }
736           if (data->next_reauth_id) {
737                     eap_sim_db_add_reauth(sm->cfg->eap_sim_db_priv, data->permanent,
738                                               data->next_reauth_id, data->counter + 1,
739                                               data->mk);
740                     data->next_reauth_id = NULL;
741           }
742 }
743 
744 
eap_sim_process_reauth(struct eap_sm * sm,struct eap_sim_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)745 static void eap_sim_process_reauth(struct eap_sm *sm,
746                                            struct eap_sim_data *data,
747                                            struct wpabuf *respData,
748                                            struct eap_sim_attrs *attr)
749 {
750           struct eap_sim_attrs eattr;
751           u8 *decrypted = NULL;
752 
753           if (attr->mac == NULL ||
754               eap_sim_verify_mac(data->k_aut, respData, attr->mac, data->nonce_s,
755                                      EAP_SIM_NONCE_S_LEN)) {
756                     wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
757                                  "did not include valid AT_MAC");
758                     goto fail;
759           }
760 
761           if (attr->encr_data == NULL || attr->iv == NULL) {
762                     wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
763                                  "message did not include encrypted data");
764                     goto fail;
765           }
766 
767           decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
768                                                attr->encr_data_len, attr->iv, &eattr,
769                                                0);
770           if (decrypted == NULL) {
771                     wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
772                                  "data from reauthentication message");
773                     goto fail;
774           }
775 
776           if (eattr.counter != data->counter) {
777                     wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
778                                  "used incorrect counter %u, expected %u",
779                                  eattr.counter, data->counter);
780                     goto fail;
781           }
782           os_free(decrypted);
783           decrypted = NULL;
784 
785           wpa_printf(MSG_DEBUG, "EAP-SIM: Re-authentication response includes "
786                        "the correct AT_MAC");
787 
788           if (eattr.counter_too_small) {
789                     wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
790                                  "included AT_COUNTER_TOO_SMALL - starting full "
791                                  "authentication");
792                     data->start_round = -1;
793                     eap_sim_state(data, START);
794                     return;
795           }
796 
797           if (sm->cfg->eap_sim_aka_result_ind && attr->result_ind) {
798                     data->use_result_ind = 1;
799                     data->notification = EAP_SIM_SUCCESS;
800                     eap_sim_state(data, NOTIFICATION);
801           } else
802                     eap_sim_state(data, SUCCESS);
803 
804           if (data->next_reauth_id) {
805                     eap_sim_db_add_reauth(sm->cfg->eap_sim_db_priv, data->permanent,
806                                               data->next_reauth_id,
807                                               data->counter + 1, data->mk);
808                     data->next_reauth_id = NULL;
809           } else {
810                     eap_sim_db_remove_reauth(sm->cfg->eap_sim_db_priv,
811                                                    data->reauth);
812                     data->reauth = NULL;
813           }
814 
815           return;
816 
817 fail:
818           data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
819           eap_sim_state(data, NOTIFICATION);
820           eap_sim_db_remove_reauth(sm->cfg->eap_sim_db_priv, data->reauth);
821           data->reauth = NULL;
822           os_free(decrypted);
823 }
824 
825 
eap_sim_process_client_error(struct eap_sm * sm,struct eap_sim_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)826 static void eap_sim_process_client_error(struct eap_sm *sm,
827                                                    struct eap_sim_data *data,
828                                                    struct wpabuf *respData,
829                                                    struct eap_sim_attrs *attr)
830 {
831           wpa_printf(MSG_DEBUG, "EAP-SIM: Client reported error %d",
832                        attr->client_error_code);
833           if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
834                     eap_sim_state(data, SUCCESS);
835           else
836                     eap_sim_state(data, FAILURE);
837 }
838 
839 
eap_sim_process_notification(struct eap_sm * sm,struct eap_sim_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)840 static void eap_sim_process_notification(struct eap_sm *sm,
841                                                    struct eap_sim_data *data,
842                                                    struct wpabuf *respData,
843                                                    struct eap_sim_attrs *attr)
844 {
845           wpa_printf(MSG_DEBUG, "EAP-SIM: Client replied to notification");
846           if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
847                     eap_sim_state(data, SUCCESS);
848           else
849                     eap_sim_state(data, FAILURE);
850 }
851 
852 
eap_sim_process(struct eap_sm * sm,void * priv,struct wpabuf * respData)853 static void eap_sim_process(struct eap_sm *sm, void *priv,
854                                   struct wpabuf *respData)
855 {
856           struct eap_sim_data *data = priv;
857           const u8 *pos, *end;
858           u8 subtype;
859           size_t len;
860           struct eap_sim_attrs attr;
861 
862           pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len);
863           if (pos == NULL || len < 3)
864                     return;
865 
866           end = pos + len;
867           subtype = *pos;
868           pos += 3;
869 
870           if (eap_sim_unexpected_subtype(data, subtype)) {
871                     wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized or unexpected "
872                                  "EAP-SIM Subtype in EAP Response");
873                     data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
874                     eap_sim_state(data, NOTIFICATION);
875                     return;
876           }
877 
878           if (eap_sim_parse_attr(pos, end, &attr, 0, 0)) {
879                     wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to parse attributes");
880                     if (subtype != EAP_SIM_SUBTYPE_CLIENT_ERROR &&
881                         (data->state == START || data->state == CHALLENGE ||
882                          data->state == REAUTH)) {
883                               data->notification =
884                                         EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
885                               eap_sim_state(data, NOTIFICATION);
886                               return;
887                     }
888                     eap_sim_state(data, FAILURE);
889                     return;
890           }
891 
892           if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) {
893                     eap_sim_process_client_error(sm, data, respData, &attr);
894                     return;
895           }
896 
897           switch (data->state) {
898           case START:
899                     eap_sim_process_start(sm, data, respData, &attr);
900                     break;
901           case CHALLENGE:
902                     eap_sim_process_challenge(sm, data, respData, &attr);
903                     break;
904           case REAUTH:
905                     eap_sim_process_reauth(sm, data, respData, &attr);
906                     break;
907           case NOTIFICATION:
908                     eap_sim_process_notification(sm, data, respData, &attr);
909                     break;
910           default:
911                     wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
912                                  "process", data->state);
913                     break;
914           }
915 }
916 
917 
eap_sim_isDone(struct eap_sm * sm,void * priv)918 static bool eap_sim_isDone(struct eap_sm *sm, void *priv)
919 {
920           struct eap_sim_data *data = priv;
921           return data->state == SUCCESS || data->state == FAILURE;
922 }
923 
924 
eap_sim_getKey(struct eap_sm * sm,void * priv,size_t * len)925 static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
926 {
927           struct eap_sim_data *data = priv;
928           u8 *key;
929 
930           if (data->state != SUCCESS)
931                     return NULL;
932 
933           key = os_memdup(data->msk, EAP_SIM_KEYING_DATA_LEN);
934           if (key == NULL)
935                     return NULL;
936           *len = EAP_SIM_KEYING_DATA_LEN;
937           return key;
938 }
939 
940 
eap_sim_get_emsk(struct eap_sm * sm,void * priv,size_t * len)941 static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
942 {
943           struct eap_sim_data *data = priv;
944           u8 *key;
945 
946           if (data->state != SUCCESS)
947                     return NULL;
948 
949           key = os_memdup(data->emsk, EAP_EMSK_LEN);
950           if (key == NULL)
951                     return NULL;
952           *len = EAP_EMSK_LEN;
953           return key;
954 }
955 
956 
eap_sim_isSuccess(struct eap_sm * sm,void * priv)957 static bool eap_sim_isSuccess(struct eap_sm *sm, void *priv)
958 {
959           struct eap_sim_data *data = priv;
960           return data->state == SUCCESS;
961 }
962 
963 
eap_sim_get_session_id(struct eap_sm * sm,void * priv,size_t * len)964 static u8 * eap_sim_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
965 {
966           struct eap_sim_data *data = priv;
967           u8 *id;
968 
969           if (data->state != SUCCESS)
970                     return NULL;
971 
972           if (!data->reauth)
973                     *len = 1 + data->num_chal * GSM_RAND_LEN + EAP_SIM_NONCE_MT_LEN;
974           else
975                     *len = 1 + EAP_SIM_NONCE_S_LEN + EAP_SIM_MAC_LEN;
976           id = os_malloc(*len);
977           if (id == NULL)
978                     return NULL;
979 
980           id[0] = EAP_TYPE_SIM;
981           if (!data->reauth) {
982                     os_memcpy(id + 1, data->rand, data->num_chal * GSM_RAND_LEN);
983                     os_memcpy(id + 1 + data->num_chal * GSM_RAND_LEN,
984                                 data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
985           } else {
986                     os_memcpy(id + 1, data->nonce_s, EAP_SIM_NONCE_S_LEN);
987                     os_memcpy(id + 1 + EAP_SIM_NONCE_S_LEN, data->reauth_mac,
988                                 EAP_SIM_MAC_LEN);
989 
990           }
991           wpa_hexdump(MSG_DEBUG, "EAP-SIM: Derived Session-Id", id, *len);
992 
993           return id;
994 }
995 
996 
eap_server_sim_register(void)997 int eap_server_sim_register(void)
998 {
999           struct eap_method *eap;
1000 
1001           eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
1002                                               EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
1003           if (eap == NULL)
1004                     return -1;
1005 
1006           eap->init = eap_sim_init;
1007           eap->reset = eap_sim_reset;
1008           eap->buildReq = eap_sim_buildReq;
1009           eap->check = eap_sim_check;
1010           eap->process = eap_sim_process;
1011           eap->isDone = eap_sim_isDone;
1012           eap->getKey = eap_sim_getKey;
1013           eap->isSuccess = eap_sim_isSuccess;
1014           eap->get_emsk = eap_sim_get_emsk;
1015           eap->getSessionId = eap_sim_get_session_id;
1016 
1017           return eap_server_method_register(eap);
1018 }
1019