eap_fast.c

Go to the documentation of this file.
00001 
00016 #include "includes.h"
00017 
00018 #include "common.h"
00019 #include "eap_i.h"
00020 #include "eap_tls_common.h"
00021 #include "config_ssid.h"
00022 #include "tls.h"
00023 #include "eap_tlv.h"
00024 #include "sha1.h"
00025 #include "config.h"
00026 
00027 /* TODO:
00028  * - encrypt PAC-Key in the PAC file
00029  * - test session resumption and enable it if it interoperates
00030  * - password change (pending mschapv2 packet; replay decrypted packet)
00031  */
00032 
00033 #define EAP_FAST_VERSION 1
00034 #define EAP_FAST_KEY_LEN 64
00035 #define EAP_FAST_PAC_KEY_LEN 32
00036 #define EAP_FAST_SIMCK_LEN 40
00037 #define EAP_FAST_SKS_LEN 40
00038 
00039 #define TLS_EXT_PAC_OPAQUE 35
00040 
00041 static const char *pac_file_hdr =
00042         "wpa_supplicant EAP-FAST PAC file - version 1";
00043 
00044 
00045 static void eap_fast_deinit(struct eap_sm *sm, void *priv);
00046 
00047 
00048 #define PAC_TYPE_PAC_KEY 1
00049 #define PAC_TYPE_PAC_OPAQUE 2
00050 #define PAC_TYPE_CRED_LIFETIME 3
00051 #define PAC_TYPE_A_ID 4
00052 #define PAC_TYPE_I_ID 5
00053 #define PAC_TYPE_SERVER_PROTECTED_DATA 6
00054 #define PAC_TYPE_A_ID_INFO 7
00055 #define PAC_TYPE_PAC_ACKNOWLEDGEMENT 8
00056 #define PAC_TYPE_PAC_INFO 9
00057 
00058 struct pac_tlv_hdr {
00059         u16 type;
00060         u16 len;
00061 };
00062 
00063 
00064 /* draft-cam-winget-eap-fast-provisioning-01.txt:
00065  * 3.4 Key Derivations Used in the EAP-FAST Provisioning Exchange */
00066 struct eap_fast_key_block_provisioning {
00067         /* Extra key material after TLS key_block */
00068         u8 session_key_seed[EAP_FAST_SKS_LEN];
00069         u8 server_challenge[16];
00070         u8 client_challenge[16];
00071 };
00072 
00073 
00074 struct eap_fast_pac {
00075         struct eap_fast_pac *next;
00076 
00077         u8 pac_key[EAP_FAST_PAC_KEY_LEN];
00078         u8 *pac_opaque;
00079         size_t pac_opaque_len;
00080         u8 *pac_info;
00081         size_t pac_info_len;
00082         u8 *a_id;
00083         size_t a_id_len;
00084         u8 *i_id;
00085         size_t i_id_len;
00086         u8 *a_id_info;
00087         size_t a_id_info_len;
00088 };
00089 
00090 
00091 struct eap_fast_data {
00092         struct eap_ssl_data ssl;
00093 
00094         int fast_version;
00095 
00096         const struct eap_method *phase2_method;
00097         void *phase2_priv;
00098         int phase2_success;
00099 
00100         struct eap_method_type phase2_type;
00101         struct eap_method_type *phase2_types;
00102         size_t num_phase2_types;
00103         int resuming; /* starting a resumed session */
00104         struct eap_fast_key_block_provisioning *key_block_p;
00105         int provisioning_allowed; /* is PAC provisioning allowed */
00106         int provisioning; /* doing PAC provisioning (not the normal auth) */
00107 
00108         u8 key_data[EAP_FAST_KEY_LEN];
00109         u8 emsk[EAP_EMSK_LEN];
00110         int success;
00111 
00112         struct eap_fast_pac *pac;
00113         struct eap_fast_pac *current_pac;
00114 
00115         int tls_master_secret_set;
00116 
00117         u8 simck[EAP_FAST_SIMCK_LEN];
00118         int simck_idx;
00119 };
00120 
00121 
00122 static void eap_fast_free_pac(struct eap_fast_pac *pac)
00123 {
00124         os_free(pac->pac_opaque);
00125         os_free(pac->pac_info);
00126         os_free(pac->a_id);
00127         os_free(pac->i_id);
00128         os_free(pac->a_id_info);
00129         os_free(pac);
00130 }
00131 
00132 
00133 static struct eap_fast_pac * eap_fast_get_pac(struct eap_fast_data *data,
00134                                               const u8 *a_id, size_t a_id_len)
00135 {
00136         struct eap_fast_pac *pac = data->pac;
00137 
00138         while (pac) {
00139                 if (pac->a_id_len == a_id_len &&
00140                     os_memcmp(pac->a_id, a_id, a_id_len) == 0) {
00141                         return pac;
00142                 }
00143                 pac = pac->next;
00144         }
00145         return NULL;
00146 }
00147 
00148 
00149 static int eap_fast_add_pac(struct eap_fast_data *data,
00150                             struct eap_fast_pac *entry)
00151 {
00152         struct eap_fast_pac *pac, *prev;
00153 
00154         if (entry == NULL || entry->a_id == NULL)
00155                 return -1;
00156 
00157         /* Remove a possible old entry for the matching A-ID. */
00158         pac = data->pac;
00159         prev = NULL;
00160         while (pac) {
00161                 if (pac->a_id_len == entry->a_id_len &&
00162                     os_memcmp(pac->a_id, entry->a_id, pac->a_id_len) == 0) {
00163                         if (prev == NULL) {
00164                                 data->pac = pac->next;
00165                         } else {
00166                                 prev->next = pac->next;
00167                         }
00168                         if (data->current_pac == pac)
00169                                 data->current_pac = NULL;
00170                         eap_fast_free_pac(pac);
00171                         break;
00172                 }
00173                 prev = pac;
00174                 pac = pac->next;
00175         }
00176 
00177         /* Allocate a new entry and add it to the list of PACs. */
00178         pac = os_zalloc(sizeof(*pac));
00179         if (pac == NULL)
00180                 return -1;
00181 
00182         os_memcpy(pac->pac_key, entry->pac_key, EAP_FAST_PAC_KEY_LEN);
00183         if (entry->pac_opaque) {
00184                 pac->pac_opaque = os_malloc(entry->pac_opaque_len);
00185                 if (pac->pac_opaque == NULL) {
00186                         eap_fast_free_pac(pac);
00187                         return -1;
00188                 }
00189                 os_memcpy(pac->pac_opaque, entry->pac_opaque,
00190                           entry->pac_opaque_len);
00191                 pac->pac_opaque_len = entry->pac_opaque_len;
00192         }
00193         if (entry->pac_info) {
00194                 pac->pac_info = os_malloc(entry->pac_info_len);
00195                 if (pac->pac_info == NULL) {
00196                         eap_fast_free_pac(pac);
00197                         return -1;
00198                 }
00199                 os_memcpy(pac->pac_info, entry->pac_info,
00200                           entry->pac_info_len);
00201                 pac->pac_info_len = entry->pac_info_len;
00202         }
00203         if (entry->a_id) {
00204                 pac->a_id = os_malloc(entry->a_id_len);
00205                 if (pac->a_id == NULL) {
00206                         eap_fast_free_pac(pac);
00207                         return -1;
00208                 }
00209                 os_memcpy(pac->a_id, entry->a_id,
00210                           entry->a_id_len);
00211                 pac->a_id_len = entry->a_id_len;
00212         }
00213         if (entry->i_id) {
00214                 pac->i_id = os_malloc(entry->i_id_len);
00215                 if (pac->i_id == NULL) {
00216                         eap_fast_free_pac(pac);
00217                         return -1;
00218                 }
00219                 os_memcpy(pac->i_id, entry->i_id,
00220                           entry->i_id_len);
00221                 pac->i_id_len = entry->i_id_len;
00222         }
00223         if (entry->a_id_info) {
00224                 pac->a_id_info = os_malloc(entry->a_id_info_len);
00225                 if (pac->a_id_info == NULL) {
00226                         eap_fast_free_pac(pac);
00227                         return -1;
00228                 }
00229                 os_memcpy(pac->a_id_info, entry->a_id_info,
00230                           entry->a_id_info_len);
00231                 pac->a_id_info_len = entry->a_id_info_len;
00232         }
00233         pac->next = data->pac;
00234         data->pac = pac;
00235         return 0;
00236 }
00237 
00238 
00239 struct eap_fast_read_ctx {
00240         FILE *f;
00241         const char *pos;
00242         const char *end;
00243 };
00244 
00245 static int eap_fast_read_line(struct eap_fast_read_ctx *rc, char *buf,
00246                               size_t buf_len)
00247 {
00248         char *pos;
00249 
00250         if (rc->f) {
00251                 if (fgets(buf, buf_len, rc->f) == NULL)
00252                         return -1;
00253         } else {
00254                 const char *l_end;
00255                 size_t len;
00256                 if (rc->pos >= rc->end)
00257                         return -1;
00258                 l_end = rc->pos;
00259                 while (l_end < rc->end && *l_end != '\n')
00260                         l_end++;
00261                 len = l_end - rc->pos;
00262                 if (len >= buf_len)
00263                         len = buf_len - 1;
00264                 os_memcpy(buf, rc->pos, len);
00265                 buf[len] = '\0';
00266                 rc->pos = l_end + 1;
00267         }
00268 
00269         buf[buf_len - 1] = '\0';
00270         pos = buf;
00271         while (*pos != '\0') {
00272                 if (*pos == '\n' || *pos == '\r') {
00273                         *pos = '\0';
00274                         break;
00275                 }
00276                 pos++;
00277         }
00278 
00279         return 0;
00280 }
00281 
00282 
00283 static u8 * eap_fast_parse_hex(const char *value, size_t *len)
00284 {
00285         int hlen;
00286         u8 *buf;
00287 
00288         if (value == NULL)
00289                 return NULL;
00290         hlen = os_strlen(value);
00291         if (hlen & 1)
00292                 return NULL;
00293         *len = hlen / 2;
00294         buf = os_malloc(*len);
00295         if (buf == NULL)
00296                 return NULL;
00297         if (hexstr2bin(value, buf, *len)) {
00298                 os_free(buf);
00299                 return NULL;
00300         }
00301         return buf;
00302 }
00303 
00304 
00305 static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
00306                              const char *pac_file)
00307 {
00308         struct eap_fast_read_ctx rc;
00309         struct eap_fast_pac *pac = NULL;
00310         int count = 0;
00311         char *buf, *pos;
00312         const int buf_len = 2048;
00313         int ret = 0, line = 0;
00314 
00315         if (pac_file == NULL)
00316                 return -1;
00317 
00318         os_memset(&rc, 0, sizeof(rc));
00319 
00320         if (os_strncmp(pac_file, "blob://", 7) == 0) {
00321                 const struct wpa_config_blob *blob;
00322                 blob = eap_get_config_blob(sm, pac_file + 7);
00323                 if (blob == NULL) {
00324                         wpa_printf(MSG_INFO, "EAP-FAST: No PAC blob '%s' - "
00325                                    "assume no PAC entries have been "
00326                                    "provisioned", pac_file + 7);
00327                         return 0;
00328                 }
00329                 rc.pos = (char *) blob->data;
00330                 rc.end = (char *) blob->data + blob->len;
00331         } else {
00332                 rc.f = fopen(pac_file, "r");
00333                 if (rc.f == NULL) {
00334                         wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - "
00335                                    "assume no PAC entries have been "
00336                                    "provisioned", pac_file);
00337                         return 0;
00338                 }
00339         }
00340 
00341         buf = os_malloc(buf_len);
00342         if (buf == NULL) {
00343                 return -1;
00344         }
00345 
00346         line++;
00347         if (eap_fast_read_line(&rc, buf, buf_len) < 0 ||
00348             os_strcmp(pac_file_hdr, buf) != 0) {
00349                 wpa_printf(MSG_INFO, "EAP-FAST: Unrecognized header line in "
00350                            "PAC file '%s'", pac_file);
00351                 os_free(buf);
00352                 if (rc.f)
00353                         fclose(rc.f);
00354                 return -1;
00355         }
00356 
00357         while (eap_fast_read_line(&rc, buf, buf_len) == 0) {
00358                 line++;
00359                 pos = os_strchr(buf, '=');
00360                 if (pos) {
00361                         *pos++ = '\0';
00362                 }
00363 
00364                 if (os_strcmp(buf, "START") == 0) {
00365                         if (pac) {
00366                                 wpa_printf(MSG_INFO, "EAP-FAST: START line "
00367                                            "without END in '%s:%d'",
00368                                            pac_file, line);
00369                                 ret = -1;
00370                                 break;
00371                         }
00372                         pac = os_zalloc(sizeof(*pac));
00373                         if (pac == NULL) {
00374                                 wpa_printf(MSG_INFO, "EAP-FAST: No memory for "
00375                                            "PAC entry");
00376                                 ret = -1;
00377                                 break;
00378                         }
00379                 } else if (os_strcmp(buf, "END") == 0) {
00380                         if (pac == NULL) {
00381                                 wpa_printf(MSG_INFO, "EAP-FAST: END line "
00382                                            "without START in '%s:%d'",
00383                                            pac_file, line);
00384                                 ret = -1;
00385                                 break;
00386                         }
00387                         pac->next = data->pac;
00388                         data->pac = pac;
00389                         pac = NULL;
00390                         count++;
00391                 } else if (pac && os_strcmp(buf, "PAC-Key") == 0) {
00392                         u8 *key;
00393                         size_t key_len;
00394                         key = eap_fast_parse_hex(pos, &key_len);
00395                         if (key == NULL || key_len != EAP_FAST_PAC_KEY_LEN) {
00396                                 wpa_printf(MSG_INFO, "EAP-FAST: Invalid "
00397                                            "PAC-Key '%s:%d'", pac_file, line);
00398                                 ret = -1;
00399                                 os_free(key);
00400                                 break;
00401                         }
00402 
00403                         os_memcpy(pac->pac_key, key, EAP_FAST_PAC_KEY_LEN);
00404                         os_free(key);
00405                 } else if (pac && os_strcmp(buf, "PAC-Opaque") == 0) {
00406                         os_free(pac->pac_opaque);
00407                         pac->pac_opaque =
00408                                 eap_fast_parse_hex(pos, &pac->pac_opaque_len);
00409                         if (pac->pac_opaque == NULL) {
00410                                 wpa_printf(MSG_INFO, "EAP-FAST: Invalid "
00411                                            "PAC-Opaque '%s:%d'",
00412                                            pac_file, line);
00413                                 ret = -1;
00414                                 break;
00415                         }
00416                 } else if (pac && os_strcmp(buf, "A-ID") == 0) {
00417                         os_free(pac->a_id);
00418                         pac->a_id = eap_fast_parse_hex(pos, &pac->a_id_len);
00419                         if (pac->a_id == NULL) {
00420                                 wpa_printf(MSG_INFO, "EAP-FAST: Invalid "
00421                                            "A-ID '%s:%d'", pac_file, line);
00422                                 ret = -1;
00423                                 break;
00424                         }
00425                 } else if (pac && os_strcmp(buf, "I-ID") == 0) {
00426                         os_free(pac->i_id);
00427                         pac->i_id = eap_fast_parse_hex(pos, &pac->i_id_len);
00428                         if (pac->i_id == NULL) {
00429                                 wpa_printf(MSG_INFO, "EAP-FAST: Invalid "
00430                                            "I-ID '%s:%d'", pac_file, line);
00431                                 ret = -1;
00432                                 break;
00433                         }
00434                 } else if (pac && os_strcmp(buf, "A-ID-Info") == 0) {
00435                         os_free(pac->a_id_info);
00436                         pac->a_id_info =
00437                                 eap_fast_parse_hex(pos, &pac->a_id_info_len);
00438                         if (pac->a_id_info == NULL) {
00439                                 wpa_printf(MSG_INFO, "EAP-FAST: Invalid "
00440                                            "A-ID-Info '%s:%d'",
00441                                            pac_file, line);
00442                                 ret = -1;
00443                                 break;
00444                         }
00445                 }
00446         }
00447 
00448         if (pac) {
00449                 wpa_printf(MSG_INFO, "EAP-FAST: PAC block not terminated with "
00450                            "END in '%s'", pac_file);
00451                 eap_fast_free_pac(pac);
00452                 ret = -1;
00453         }
00454 
00455         os_free(buf);
00456         if (rc.f)
00457                 fclose(rc.f);
00458 
00459         if (ret == 0) {
00460                 wpa_printf(MSG_DEBUG, "EAP-FAST: read %d PAC entries from "
00461                            "'%s'", count, pac_file);
00462         }
00463 
00464         return ret;
00465 }
00466 
00467 
00468 static void eap_fast_write(char **buf, char **pos, size_t *buf_len,
00469                            const char *field, const u8 *data,
00470                            size_t len, int txt)
00471 {
00472         size_t i, need;
00473         int ret;
00474 
00475         if (data == NULL || *buf == NULL)
00476                 return;
00477 
00478         need = os_strlen(field) + len * 2 + 30;
00479         if (txt)
00480                 need += os_strlen(field) + len + 20;
00481 
00482         if (*pos - *buf + need > *buf_len) {
00483                 char *nbuf = os_realloc(*buf, *buf_len + need);
00484                 if (nbuf == NULL) {
00485                         os_free(*buf);
00486                         *buf = NULL;
00487                         return;
00488                 }
00489                 *buf = nbuf;
00490                 *buf_len += need;
00491         }
00492 
00493         ret = os_snprintf(*pos, *buf + *buf_len - *pos, "%s=", field);
00494         if (ret < 0 || ret >= *buf + *buf_len - *pos)
00495                 return;
00496         *pos += ret;
00497         *pos += wpa_snprintf_hex(*pos, *buf + *buf_len - *pos, data, len);
00498         ret = os_snprintf(*pos, *buf + *buf_len - *pos, "\n");
00499         if (ret < 0 || ret >= *buf + *buf_len - *pos)
00500                 return;
00501         *pos += ret;
00502 
00503         if (txt) {
00504                 ret = os_snprintf(*pos, *buf + *buf_len - *pos,
00505                                   "%s-txt=", field);
00506                 if (ret < 0 || ret >= *buf + *buf_len - *pos)
00507                         return;
00508                 *pos += ret;
00509                 for (i = 0; i < len; i++) {
00510                         ret = os_snprintf(*pos, *buf + *buf_len - *pos,
00511                                           "%c", data[i]);
00512                         if (ret < 0 || ret >= *buf + *buf_len - *pos)
00513                                 return;
00514                         *pos += ret;
00515                 }
00516                 ret = os_snprintf(*pos, *buf + *buf_len - *pos, "\n");
00517                 if (ret < 0 || ret >= *buf + *buf_len - *pos)
00518                         return;
00519                 *pos += ret;
00520         }
00521 }
00522 
00523 
00524 static int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_data *data,
00525                              const char *pac_file)
00526 {
00527         FILE *f;
00528         struct eap_fast_pac *pac;
00529         int count = 0, ret;
00530         char *buf, *pos;
00531         size_t buf_len;
00532 
00533         if (pac_file == NULL)
00534                 return -1;
00535 
00536         buf_len = 1024;
00537         pos = buf = os_malloc(buf_len);
00538         if (buf == NULL)
00539                 return -1;
00540 
00541         ret = os_snprintf(pos, buf + buf_len - pos, "%s\n", pac_file_hdr);
00542         if (ret < 0 || ret >= buf + buf_len - pos) {
00543                 os_free(buf);
00544                 return -1;
00545         }
00546         pos += ret;
00547 
00548         pac = data->pac;
00549         while (pac) {
00550                 ret = os_snprintf(pos, buf + buf_len - pos, "START\n");
00551                 if (ret < 0 || ret >= buf + buf_len - pos) {
00552                         os_free(buf);
00553                         return -1;
00554                 }
00555                 pos += ret;
00556                 eap_fast_write(&buf, &pos, &buf_len, "PAC-Key", pac->pac_key,
00557                                EAP_FAST_PAC_KEY_LEN, 0);
00558                 eap_fast_write(&buf, &pos, &buf_len, "PAC-Opaque",
00559                                pac->pac_opaque, pac->pac_opaque_len, 0);
00560                 eap_fast_write(&buf, &pos, &buf_len, "PAC-Info", pac->pac_info,
00561                                pac->pac_info_len, 0);
00562                 eap_fast_write(&buf, &pos, &buf_len, "A-ID", pac->a_id,
00563                                pac->a_id_len, 0);
00564                 eap_fast_write(&buf, &pos, &buf_len, "I-ID", pac->i_id,
00565                                pac->i_id_len, 1);
00566                 eap_fast_write(&buf, &pos, &buf_len, "A-ID-Info",
00567                                pac->a_id_info, pac->a_id_info_len, 1);
00568                 if (buf == NULL) {
00569                         wpa_printf(MSG_DEBUG, "EAP-FAST: No memory for PAC "
00570                                    "data");
00571                         return -1;
00572                 }
00573                 ret = os_snprintf(pos, buf + buf_len - pos, "END\n");
00574                 if (ret < 0 || ret >= buf + buf_len - pos) {
00575                         os_free(buf);
00576                         return -1;
00577                 }
00578                 pos += ret;
00579                 count++;
00580                 pac = pac->next;
00581         }
00582 
00583         if (os_strncmp(pac_file, "blob://", 7) == 0) {
00584                 struct wpa_config_blob *blob;
00585                 blob = os_zalloc(sizeof(*blob));
00586                 if (blob == NULL) {
00587                         os_free(buf);
00588                         return -1;
00589                 }
00590                 blob->data = (u8 *) buf;
00591                 blob->len = pos - buf;
00592                 buf = NULL;
00593                 blob->name = os_strdup(pac_file + 7);
00594                 if (blob->name == NULL) {
00595                         os_free(blob->data);
00596                         os_free(blob);
00597                         return -1;
00598                 }
00599                 eap_set_config_blob(sm, blob);
00600         } else {
00601                 f = fopen(pac_file, "w");
00602                 if (f == NULL) {
00603                         wpa_printf(MSG_INFO, "EAP-FAST: Failed to open PAC "
00604                                    "file '%s' for writing", pac_file);
00605                         os_free(buf);
00606                         return -1;
00607                 }
00608                 fprintf(f, "%s", buf);
00609                 os_free(buf);
00610                 fclose(f);
00611         }
00612 
00613         wpa_printf(MSG_DEBUG, "EAP-FAST: wrote %d PAC entries into '%s'",
00614                    count, pac_file);
00615 
00616         return 0;
00617 }
00618 
00619 
00620 static void * eap_fast_init(struct eap_sm *sm)
00621 {
00622         struct eap_fast_data *data;
00623         struct wpa_ssid *config = eap_get_config(sm);
00624 
00625         data = os_zalloc(sizeof(*data));
00626         if (data == NULL)
00627                 return NULL;
00628         data->fast_version = EAP_FAST_VERSION;
00629 
00630         if (config && config->phase1) {
00631                 if (os_strstr(config->phase1, "fast_provisioning=1")) {
00632                         data->provisioning_allowed = 1;
00633                         wpa_printf(MSG_DEBUG, "EAP-FAST: Automatic PAC "
00634                                    "provisioning is allowed");
00635                 }
00636         }
00637 
00638         if (config && config->phase2) {
00639                 char *start, *pos, *buf;
00640                 struct eap_method_type *methods = NULL, *_methods;
00641                 u8 method;
00642                 size_t num_methods = 0;
00643                 start = buf = os_strdup(config->phase2);
00644                 if (buf == NULL) {
00645                         eap_fast_deinit(sm, data);
00646                         return NULL;
00647                 }
00648                 while (start && *start != '\0') {
00649                         int vendor;
00650                         pos = os_strstr(start, "auth=");
00651                         if (pos == NULL)
00652                                 break;
00653                         if (start != pos && *(pos - 1) != ' ') {
00654                                 start = pos + 5;
00655                                 continue;
00656                         }
00657 
00658                         start = pos + 5;
00659                         pos = os_strchr(start, ' ');
00660                         if (pos)
00661                                 *pos++ = '\0';
00662                         method = eap_get_phase2_type(start, &vendor);
00663                         if (vendor == EAP_VENDOR_IETF &&
00664                             method == EAP_TYPE_NONE) {
00665                                 wpa_printf(MSG_ERROR, "EAP-FAST: Unsupported "
00666                                            "Phase2 method '%s'", start);
00667                         } else {
00668                                 num_methods++;
00669                                 _methods = os_realloc(
00670                                         methods,
00671                                         num_methods * sizeof(*methods));
00672                                 if (_methods == NULL) {
00673                                         os_free(methods);
00674                                         os_free(buf);
00675                                         eap_fast_deinit(sm, data);
00676                                         return NULL;
00677                                 }
00678                                 methods = _methods;
00679                                 methods[num_methods - 1].vendor = vendor;
00680                                 methods[num_methods - 1].method = method;
00681                         }
00682 
00683                         start = pos;
00684                 }
00685                 os_free(buf);
00686                 data->phase2_types = methods;
00687                 data->num_phase2_types = num_methods;
00688         }
00689         if (data->phase2_types == NULL) {
00690                 data->phase2_types =
00691                         eap_get_phase2_types(config, &data->num_phase2_types);
00692         }
00693         if (data->phase2_types == NULL) {
00694                 wpa_printf(MSG_ERROR, "EAP-FAST: No Phase2 method available");
00695                 eap_fast_deinit(sm, data);
00696                 return NULL;
00697         }
00698         wpa_hexdump(MSG_DEBUG, "EAP-FAST: Phase2 EAP types",
00699                     (u8 *) data->phase2_types,
00700                     data->num_phase2_types * sizeof(struct eap_method_type));
00701         data->phase2_type.vendor = EAP_VENDOR_IETF;
00702         data->phase2_type.method = EAP_TYPE_NONE;
00703 
00704         if (eap_tls_ssl_init(sm, &data->ssl, config)) {
00705                 wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL.");
00706                 eap_fast_deinit(sm, data);
00707                 return NULL;
00708         }
00709 
00710         /* The local RADIUS server in a Cisco AP does not seem to like empty
00711          * fragments before data, so disable that workaround for CBC.
00712          * TODO: consider making this configurable */
00713         tls_connection_enable_workaround(sm->ssl_ctx, data->ssl.conn);
00714 
00715         if (eap_fast_load_pac(sm, data, config->pac_file) < 0) {
00716                 eap_fast_deinit(sm, data);
00717                 return NULL;
00718         }
00719 
00720         if (data->pac == NULL && !data->provisioning_allowed) {
00721                 wpa_printf(MSG_INFO, "EAP-FAST: No PAC configured and "
00722                            "provisioning disabled");
00723                 eap_fast_deinit(sm, data);
00724                 return NULL;
00725         }
00726 
00727         return data;
00728 }
00729 
00730 
00731 static void eap_fast_deinit(struct eap_sm *sm, void *priv)
00732 {
00733         struct eap_fast_data *data = priv;
00734         struct eap_fast_pac *pac, *prev;
00735 
00736         if (data == NULL)
00737                 return;
00738         if (data->phase2_priv && data->phase2_method)
00739                 data->phase2_method->deinit(sm, data->phase2_priv);
00740         os_free(data->phase2_types);
00741         os_free(data->key_block_p);
00742         eap_tls_ssl_deinit(sm, &data->ssl);
00743 
00744         pac = data->pac;
00745         prev = NULL;
00746         while (pac) {
00747                 prev = pac;
00748                 pac = pac->next;
00749                 eap_fast_free_pac(prev);
00750         }
00751         os_free(data);
00752 }
00753 
00754 
00755 static int eap_fast_encrypt(struct eap_sm *sm, struct eap_fast_data *data,
00756                             int id, const u8 *plain, size_t plain_len,
00757                             u8 **out_data, size_t *out_len)
00758 {
00759         int res;
00760         u8 *pos;
00761         struct eap_hdr *resp;
00762 
00763         /* TODO: add support for fragmentation, if needed. This will need to
00764          * add TLS Message Length field, if the frame is fragmented. */
00765         resp = os_malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
00766         if (resp == NULL)
00767                 return 0;
00768 
00769         resp->code = EAP_CODE_RESPONSE;
00770         resp->identifier = id;
00771 
00772         pos = (u8 *) (resp + 1);
00773         *pos++ = EAP_TYPE_FAST;
00774         *pos++ = data->fast_version;
00775 
00776         res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
00777                                      plain, plain_len,
00778                                      pos, data->ssl.tls_out_limit);
00779         if (res < 0) {
00780                 wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt Phase 2 "
00781                            "data");
00782                 os_free(resp);
00783                 return 0;
00784         }
00785 
00786         *out_len = sizeof(struct eap_hdr) + 2 + res;
00787         resp->length = host_to_be16(*out_len);
00788         *out_data = (u8 *) resp;
00789         return 0;
00790 }
00791 
00792 
00793 static int eap_fast_phase2_nak(struct eap_fast_data *data,
00794                                struct eap_hdr *hdr,
00795                                u8 **resp, size_t *resp_len)
00796 {
00797         struct eap_hdr *resp_hdr;
00798         u8 *pos = (u8 *) (hdr + 1);
00799         size_t i;
00800 
00801         /* TODO: add support for expanded Nak */
00802         wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: Nak type=%d", *pos);
00803         wpa_hexdump(MSG_DEBUG, "EAP-FAST: Allowed Phase2 EAP types",
00804                     (u8 *) data->phase2_types,
00805                     data->num_phase2_types * sizeof(struct eap_method_type));
00806         *resp_len = sizeof(struct eap_hdr) + 1;
00807         *resp = os_malloc(*resp_len + data->num_phase2_types);
00808         if (*resp == NULL)
00809                 return -1;
00810 
00811         resp_hdr = (struct eap_hdr *) (*resp);
00812         resp_hdr->code = EAP_CODE_RESPONSE;
00813         resp_hdr->identifier = hdr->identifier;
00814         pos = (u8 *) (resp_hdr + 1);
00815         *pos++ = EAP_TYPE_NAK;
00816         for (i = 0; i < data->num_phase2_types; i++) {
00817                 if (data->phase2_types[i].vendor == EAP_VENDOR_IETF &&
00818                     data->phase2_types[i].method < 256) {
00819                         (*resp_len)++;
00820                         *pos++ = data->phase2_types[i].method;
00821                 }
00822         }
00823         resp_hdr->length = host_to_be16(*resp_len);
00824 
00825         return 0;
00826 }
00827 
00828 
00829 static int eap_fast_derive_msk(struct eap_fast_data *data)
00830 {
00831         /* Derive EAP Master Session Keys (section 5.4) */
00832         sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
00833                    "Session Key Generating Function", (u8 *) "", 0,
00834                    data->key_data, EAP_FAST_KEY_LEN);
00835         wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)",
00836                         data->key_data, EAP_FAST_KEY_LEN);
00837 
00838         sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
00839                    "Extended Session Key Generating Function",
00840                    (u8 *) "", 0, data->emsk, EAP_EMSK_LEN);
00841         wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)",
00842                         data->emsk, EAP_EMSK_LEN);
00843 
00844         data->success = 1;
00845 
00846         return 0;
00847 }
00848 
00849 
00850 static int eap_fast_set_tls_master_secret(struct eap_sm *sm,
00851                                           struct eap_fast_data *data,
00852                                           const u8 *tls, size_t tls_len)
00853 {
00854         struct tls_keys keys;
00855         u8 master_secret[48], *seed;
00856         const u8 *server_random;
00857         size_t seed_len, server_random_len;
00858 
00859         if (data->tls_master_secret_set || !data->current_pac ||
00860             tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
00861             keys.client_random == NULL) {
00862                 return 0;
00863         }
00864 
00865         wpa_hexdump(MSG_DEBUG, "EAP-FAST: client_random",
00866                     keys.client_random, keys.client_random_len);
00867 
00868         /* TLS master secret is needed before TLS library has processed this
00869          * message which includes both ServerHello and an encrypted handshake
00870          * message, so we need to parse server_random from this message before
00871          * passing it to TLS library.
00872          *
00873          * Example TLS packet header:
00874          * (16 03 01 00 2a 02 00 00 26 03 01 <32 bytes server_random>)
00875          * Content Type: Handshake: 0x16
00876          * Version: TLS 1.0 (0x0301)
00877          * Lenghth: 42 (0x002a)
00878          * Handshake Type: Server Hello: 0x02
00879          * Length: 38 (0x000026)
00880          * Version TLS 1.0 (0x0301)
00881          * Random: 32 bytes
00882          */
00883         if (tls_len < 43 || tls[0] != 0x16 ||
00884             tls[1] != 0x03 || tls[2] != 0x01 ||
00885             tls[5] != 0x02 || tls[9] != 0x03 || tls[10] != 0x01) {
00886                 wpa_hexdump(MSG_DEBUG, "EAP-FAST: unrecognized TLS "
00887                             "ServerHello", tls, tls_len);
00888                 return -1;
00889         }
00890         server_random = tls + 11;
00891         server_random_len = 32;
00892         wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random",
00893                     server_random, server_random_len);
00894 
00895         seed_len = keys.client_random_len + server_random_len;
00896         seed = os_malloc(seed_len);
00897         if (seed == NULL)
00898                 return -1;
00899         os_memcpy(seed, server_random, server_random_len);
00900         os_memcpy(seed + server_random_len,
00901                   keys.client_random, keys.client_random_len);
00902 
00903         wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: T-PRF seed", seed, seed_len);
00904         wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: PAC-Key",
00905                         data->current_pac->pac_key, EAP_FAST_PAC_KEY_LEN);
00906         /* master_secret = T-PRF(PAC-Key, "PAC to master secret label hash", 
00907          * server_random + client_random, 48) */
00908         sha1_t_prf(data->current_pac->pac_key, EAP_FAST_PAC_KEY_LEN,
00909                    "PAC to master secret label hash",
00910                    seed, seed_len, master_secret, sizeof(master_secret));
00911         os_free(seed);
00912         wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: TLS pre-master-secret",
00913                         master_secret, sizeof(master_secret));
00914 
00915         data->tls_master_secret_set = 1;
00916 
00917         return tls_connection_set_master_key(sm->ssl_ctx, data->ssl.conn,
00918                                              master_secret,
00919                                              sizeof(master_secret));
00920 }
00921 
00922 
00923 static u8 * eap_fast_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
00924                                 char *label, size_t len)
00925 {
00926         struct tls_keys keys;
00927         u8 *rnd = NULL, *out;
00928         int block_size;
00929 
00930         block_size = tls_connection_get_keyblock_size(sm->ssl_ctx, data->conn);
00931         if (block_size < 0)
00932                 return NULL;
00933 
00934         out = os_malloc(block_size + len);
00935         if (out == NULL)
00936                 return NULL;
00937 
00938         if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 1, out,
00939                                block_size + len) == 0) {
00940                 os_memmove(out, out + block_size, len);
00941                 return out;
00942         }
00943 
00944         if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
00945                 goto fail;
00946 
00947         rnd = os_malloc(keys.client_random_len + keys.server_random_len);
00948         if (rnd == NULL)
00949                 goto fail;
00950 
00951         os_memcpy(rnd, keys.server_random, keys.server_random_len);
00952         os_memcpy(rnd + keys.server_random_len, keys.client_random,
00953                   keys.client_random_len);
00954 
00955         wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key "
00956                         "expansion", keys.master_key, keys.master_key_len);
00957         if (tls_prf(keys.master_key, keys.master_key_len,
00958                     label, rnd, keys.client_random_len +
00959                     keys.server_random_len, out, block_size + len))
00960                 goto fail;
00961         os_free(rnd);
00962         os_memmove(out, out + block_size, len);
00963         return out;
00964 
00965 fail:
00966         os_free(rnd);
00967         os_free(out);
00968         return NULL;
00969 }
00970 
00971 
00972 static void eap_fast_derive_key_auth(struct eap_sm *sm,
00973                                      struct eap_fast_data *data)
00974 {
00975         u8 *sks;
00976 
00977         /* draft-cam-winget-eap-fast-05.txt:
00978          * 5.1 EAP-FAST Authentication Phase 1: Key Derivations
00979          * Extra key material after TLS key_block: session_ket_seed[40]
00980          */
00981 
00982         sks = eap_fast_derive_key(sm, &data->ssl, "key expansion",
00983                                   EAP_FAST_SKS_LEN);
00984         if (sks == NULL) {
00985                 wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
00986                            "session_key_seed");
00987                 return;
00988         }
00989 
00990         /*
00991          * draft-cam-winget-eap-fast-05.txt, 5.2:
00992          * S-IMCK[0] = session_key_seed
00993          */
00994         wpa_hexdump_key(MSG_DEBUG,
00995                         "EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
00996                         sks, EAP_FAST_SKS_LEN);
00997         data->simck_idx = 0;
00998         os_memcpy(data->simck, sks, EAP_FAST_SIMCK_LEN);
00999         os_free(sks);
01000 }
01001 
01002 
01003 static void eap_fast_derive_key_provisioning(struct eap_sm *sm,
01004                                              struct eap_fast_data *data)
01005 {
01006         os_free(data->key_block_p);
01007         data->key_block_p = (struct eap_fast_key_block_provisioning *)
01008                 eap_fast_derive_key(sm, &data->ssl, "key expansion",
01009                                     sizeof(*data->key_block_p));
01010         if (data->key_block_p == NULL) {
01011                 wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
01012                 return;
01013         }
01014         /*
01015          * draft-cam-winget-eap-fast-05.txt, 5.2:
01016          * S-IMCK[0] = session_key_seed
01017          */
01018         wpa_hexdump_key(MSG_DEBUG,
01019                         "EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
01020                         data->key_block_p->session_key_seed,
01021                         sizeof(data->key_block_p->session_key_seed));
01022         data->simck_idx = 0;
01023         os_memcpy(data->simck, data->key_block_p->session_key_seed,
01024                   EAP_FAST_SIMCK_LEN);
01025         wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: server_challenge",
01026                         data->key_block_p->server_challenge,
01027                         sizeof(data->key_block_p->server_challenge));
01028         wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: client_challenge",
01029                         data->key_block_p->client_challenge,
01030                         sizeof(data->key_block_p->client_challenge));
01031 }
01032 
01033 
01034 static void eap_fast_derive_keys(struct eap_sm *sm, struct eap_fast_data *data)
01035 {
01036         if (data->current_pac) {
01037                 eap_fast_derive_key_auth(sm, data);
01038         } else {
01039                 eap_fast_derive_key_provisioning(sm, data);
01040         }
01041 }
01042 
01043 
01044 static int eap_fast_phase2_request(struct eap_sm *sm,
01045                                    struct eap_fast_data *data,
01046                                    struct eap_method_ret *ret,
01047                                    struct eap_hdr *hdr,
01048                                    u8 **resp, size_t *resp_len)
01049 {
01050         size_t len = be_to_host16(hdr->length);
01051         u8 *pos;
01052         struct eap_method_ret iret;
01053 
01054         if (len <= sizeof(struct eap_hdr)) {
01055                 wpa_printf(MSG_INFO, "EAP-FAST: too short "
01056                            "Phase 2 request (len=%lu)", (unsigned long) len);
01057                 return -1;
01058         }
01059         pos = (u8 *) (hdr + 1);
01060         wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: type=%d", *pos);
01061         switch (*pos) {
01062         case EAP_TYPE_IDENTITY:
01063                 *resp = eap_sm_buildIdentity(sm, hdr->identifier, resp_len, 1);
01064                 break;
01065         default:
01066                 if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
01067                     data->phase2_type.method == EAP_TYPE_NONE) {
01068                         size_t i;
01069                         for (i = 0; i < data->num_phase2_types; i++) {
01070                                 if (data->phase2_types[i].vendor !=
01071                                     EAP_VENDOR_IETF ||
01072                                     data->phase2_types[i].method != *pos)
01073                                         continue;
01074 
01075                                 data->phase2_type.vendor =
01076                                         data->phase2_types[i].vendor;
01077                                 data->phase2_type.method =
01078                                         data->phase2_types[i].method;
01079                                 wpa_printf(MSG_DEBUG, "EAP-FAST: Selected "
01080                                            "Phase 2 EAP vendor %d method %d",
01081                                            data->phase2_type.vendor,
01082                                            data->phase2_type.method);
01083                                 break;
01084                         }
01085                 }
01086                 if (*pos != data->phase2_type.method ||
01087                     *pos == EAP_TYPE_NONE) {
01088                         if (eap_fast_phase2_nak(data, hdr, resp, resp_len))
01089                                 return -1;
01090                         return 0;
01091                 }
01092 
01093                 if (data->phase2_priv == NULL) {
01094                         data->phase2_method = eap_sm_get_eap_methods(
01095                                 data->phase2_type.vendor,
01096                                 data->phase2_type.method);
01097                         if (data->phase2_method) {
01098                                 if (data->key_block_p) {
01099                                         sm->auth_challenge =
01100                                                 data->key_block_p->
01101                                                 server_challenge;
01102                                         sm->peer_challenge =
01103                                                 data->key_block_p->
01104                                                 client_challenge;
01105                                 }
01106                                 sm->init_phase2 = 1;
01107                                 sm->mschapv2_full_key = 1;
01108                                 data->phase2_priv =
01109                                         data->phase2_method->init(sm);
01110                                 sm->init_phase2 = 0;
01111                                 sm->mschapv2_full_key = 0;
01112                                 sm->auth_challenge = NULL;
01113                                 sm->peer_challenge = NULL;
01114                         }
01115                 }
01116                 if (data->phase2_priv == NULL || data->phase2_method == NULL) {
01117                         wpa_printf(MSG_INFO, "EAP-FAST: failed to initialize "
01118                                    "Phase 2 EAP method %d", *pos);
01119                         ret->methodState = METHOD_DONE;
01120                         ret->decision = DECISION_FAIL;
01121                         return -1;
01122                 }
01123                 os_memset(&iret, 0, sizeof(iret));
01124                 *resp = data->phase2_method->process(sm, data->phase2_priv,
01125                                                      &iret, (u8 *) hdr, len,
01126                                                      resp_len);
01127                 if (*resp == NULL ||
01128                     (iret.methodState == METHOD_DONE &&
01129                      iret.decision == DECISION_FAIL)) {
01130                         ret->methodState = METHOD_DONE;
01131                         ret->decision = DECISION_FAIL;
01132                 } else if ((iret.methodState == METHOD_DONE ||
01133                             iret.methodState == METHOD_MAY_CONT) &&
01134                            (iret.decision == DECISION_UNCOND_SUCC ||
01135                             iret.decision == DECISION_COND_SUCC)) {
01136                         data->phase2_success = 1;
01137                 }
01138                 if (*resp == NULL)
01139                         return -1;
01140                 break;
01141         }
01142         return 0;
01143 }
01144 
01145 
01146 static u8 * eap_fast_tlv_nak(int vendor_id, int tlv_type, size_t *len)
01147 {
01148         struct eap_tlv_nak_tlv *nak;
01149         *len = sizeof(*nak);
01150         nak = os_malloc(*len);
01151         if (nak == NULL)
01152                 return NULL;
01153         nak->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | EAP_TLV_NAK_TLV);
01154         nak->length = host_to_be16(6);
01155         nak->vendor_id = host_to_be32(vendor_id);
01156         nak->nak_type = host_to_be16(tlv_type);
01157         return (u8 *) nak;
01158 }
01159 
01160 
01161 static u8 * eap_fast_tlv_result(int status, int intermediate, size_t *len)
01162 {
01163         struct eap_tlv_intermediate_result_tlv *result;
01164         *len = sizeof(*result);
01165         result = os_malloc(*len);
01166         if (result == NULL)
01167                 return NULL;
01168         result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
01169                                         (intermediate ?
01170                                          EAP_TLV_INTERMEDIATE_RESULT_TLV :
01171                                          EAP_TLV_RESULT_TLV));
01172         result->length = host_to_be16(2);
01173         result->status = host_to_be16(status);
01174         return (u8 *) result;
01175 }
01176 
01177 
01178 static u8 * eap_fast_tlv_pac_ack(size_t *len)
01179 {
01180         struct eap_tlv_result_tlv *res;
01181         struct eap_tlv_pac_ack_tlv *ack;
01182 
01183         *len = sizeof(*res) + sizeof(*ack);
01184         res = os_zalloc(*len);
01185         if (res == NULL)
01186                 return NULL;
01187 
01188         res->tlv_type = host_to_be16(EAP_TLV_RESULT_TLV |
01189                                      EAP_TLV_TYPE_MANDATORY);
01190         res->length = host_to_be16(sizeof(*res) - sizeof(struct eap_tlv_hdr));
01191         res->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
01192 
01193         ack = (struct eap_tlv_pac_ack_tlv *) (res + 1);
01194         ack->tlv_type = host_to_be16(EAP_TLV_PAC_TLV |
01195                                      EAP_TLV_TYPE_MANDATORY);
01196         ack->length = host_to_be16(sizeof(*ack) - sizeof(struct eap_tlv_hdr));
01197         ack->pac_type = host_to_be16(PAC_TYPE_PAC_ACKNOWLEDGEMENT);
01198         ack->pac_len = host_to_be16(2);
01199         ack->result = host_to_be16(EAP_TLV_RESULT_SUCCESS);
01200 
01201         return (u8 *) res;
01202 }
01203 
01204 
01205 static u8 * eap_fast_tlv_eap_payload(u8 *buf, size_t *len)
01206 {
01207         struct eap_tlv_hdr *tlv;
01208 
01209         /* Encapsulate EAP packet in EAP Payload TLV */
01210         tlv = os_malloc(sizeof(*tlv) + *len);
01211         if (tlv == NULL) {
01212                 wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to "
01213                            "allocate memory for TLV "
01214                            "encapsulation");
01215                 os_free(buf);
01216                 return NULL;
01217         }
01218         tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
01219                                      EAP_TLV_EAP_PAYLOAD_TLV);
01220         tlv->length = host_to_be16(*len);
01221         os_memcpy(tlv + 1, buf, *len);
01222         os_free(buf);
01223         *len += sizeof(*tlv);
01224         return (u8 *) tlv;
01225 }
01226 
01227 
01228 static u8 * eap_fast_process_crypto_binding(
01229         struct eap_sm *sm, struct eap_fast_data *data,
01230         struct eap_method_ret *ret,
01231         struct eap_tlv_crypto_binding__tlv *_bind, size_t bind_len,
01232         size_t *resp_len, int final)
01233 {
01234         u8 *resp;
01235         struct eap_tlv_intermediate_result_tlv *rresult;
01236         struct eap_tlv_crypto_binding__tlv *rbind;
01237         u8 isk[32], imck[60], *cmk, cmac[20], *key;
01238         size_t key_len;
01239         int res;
01240 
01241         wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV: Version %d "
01242                    "Received Version %d SubType %d",
01243                    _bind->version, _bind->received_version, _bind->subtype);
01244         wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
01245                     _bind->nonce, sizeof(_bind->nonce));
01246         wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
01247                     _bind->compound_mac, sizeof(_bind->compound_mac));
01248 
01249         if (_bind->version != EAP_FAST_VERSION ||
01250             _bind->received_version != EAP_FAST_VERSION ||
01251             _bind->subtype != EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST) {
01252                 wpa_printf(MSG_INFO, "EAP-FAST: Invalid version/subtype in "
01253                            "Crypto-Binding TLV: Version %d "
01254                            "Received Version %d SubType %d",
01255                            _bind->version, _bind->received_version,
01256                            _bind->subtype);
01257                 resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1,
01258                                            resp_len);
01259                 return resp;
01260         }
01261 
01262         wpa_printf(MSG_DEBUG, "EAP-FAST: Determining CMK[%d] for Compound MIC "
01263                    "calculation", data->simck_idx + 1);
01264 
01265         /*
01266          * draft-cam-winget-eap-fast-05.txt, 5.2:
01267          * IMCK[j] = T-PRF(S-IMCK[j-1], "Inner Methods Compound Keys",
01268          *                 MSK[j], 60)
01269          * S-IMCK[j] = first 40 octets of IMCK[j]
01270          * CMK[j] = last 20 octets of IMCK[j]
01271          */
01272 
01273         os_memset(isk, 0, sizeof(isk));
01274         if (data->phase2_method == NULL || data->phase2_priv == NULL) {
01275                 wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not "
01276                            "available");
01277                 return NULL;
01278         }
01279         if (data->phase2_method->isKeyAvailable && data->phase2_method->getKey)
01280         {
01281                 if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv)
01282                     ||
01283                     (key = data->phase2_method->getKey(sm, data->phase2_priv,
01284                                                        &key_len)) == NULL) {
01285                         wpa_printf(MSG_DEBUG, "EAP-FAST: Could not get key "
01286                                    "material from Phase 2");
01287                         return NULL;
01288                 }
01289                 if (key_len > sizeof(isk))
01290                         key_len = sizeof(isk);
01291                 os_memcpy(isk, key, key_len);
01292                 os_free(key);
01293         }
01294         wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: ISK[j]", isk, sizeof(isk));
01295         sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
01296                    "Inner Methods Compound Keys",
01297                    isk, sizeof(isk), imck, sizeof(imck));
01298         data->simck_idx++;
01299         os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN);
01300         wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]",
01301                         data->simck, EAP_FAST_SIMCK_LEN);
01302         cmk = imck + EAP_FAST_SIMCK_LEN;
01303         wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]", cmk, 20);
01304 
01305         os_memcpy(cmac, _bind->compound_mac, sizeof(cmac));
01306         os_memset(_bind->compound_mac, 0, sizeof(cmac));
01307         wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for Compound "
01308                     "MAC calculation", (u8 *) _bind, bind_len);
01309         hmac_sha1(cmk, 20, (u8 *) _bind, bind_len, _bind->compound_mac);
01310         res = os_memcmp(cmac, _bind->compound_mac, sizeof(cmac));
01311         wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Received Compound MAC",
01312                     cmac, sizeof(cmac));
01313         wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Calculated Compound MAC",
01314                     _bind->compound_mac, sizeof(cmac));
01315         if (res != 0) {
01316                 wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not match");
01317                 resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1,
01318                                            resp_len);
01319                 os_memcpy(_bind->compound_mac, cmac, sizeof(cmac));
01320                 return resp;
01321         }
01322 
01323         *resp_len = sizeof(*rresult) + sizeof(*rbind);
01324         resp = os_zalloc(*resp_len);
01325         if (resp == NULL)
01326                 return NULL;
01327 
01328         /* Both intermediate and final Result TLVs are identical, so ok to use
01329          * the same structure definition for them. */
01330         rresult = (struct eap_tlv_intermediate_result_tlv *) resp;
01331         rresult->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
01332                                          (final ? EAP_TLV_RESULT_TLV :
01333                                           EAP_TLV_INTERMEDIATE_RESULT_TLV));
01334         rresult->length = host_to_be16(2);
01335         rresult->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
01336 
01337         if (!data->provisioning && data->phase2_success &&
01338             eap_fast_derive_msk(data) < 0) {
01339                 wpa_printf(MSG_INFO, "EAP-FAST: Failed to generate MSK");
01340                 ret->methodState = METHOD_DONE;
01341                 ret->decision = DECISION_FAIL;
01342                 rresult->status = host_to_be16(EAP_TLV_RESULT_FAILURE);
01343                 data->phase2_success = 0;
01344         }
01345 
01346         rbind = (struct eap_tlv_crypto_binding__tlv *) (rresult + 1);
01347         rbind->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
01348                                        EAP_TLV_CRYPTO_BINDING_TLV_);
01349         rbind->length = host_to_be16(sizeof(*rbind) -
01350                                      sizeof(struct eap_tlv_hdr));
01351         rbind->version = EAP_FAST_VERSION;
01352         rbind->received_version = _bind->version;
01353         rbind->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE;
01354         os_memcpy(rbind->nonce, _bind->nonce, sizeof(_bind->nonce));
01355         inc_byte_array(rbind->nonce, sizeof(rbind->nonce));
01356         hmac_sha1(cmk, 20, (u8 *) rbind, sizeof(*rbind), rbind->compound_mac);
01357 
01358         wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: Version %d "
01359                    "Received Version %d SubType %d",
01360                    rbind->version, rbind->received_version, rbind->subtype);
01361         wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
01362                     rbind->nonce, sizeof(rbind->nonce));
01363         wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
01364                     rbind->compound_mac, sizeof(rbind->compound_mac));
01365 
01366         if (final && data->phase2_success) {
01367                 wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication completed "
01368                            "successfully.");
01369                 ret->methodState = METHOD_DONE;
01370                 ret->decision = DECISION_UNCOND_SUCC;
01371         }
01372 
01373         return resp;
01374 }
01375 
01376 
01377 static u8 * eap_fast_process_pac(struct eap_sm *sm, struct eap_fast_data *data,
01378                                  struct eap_method_ret *ret,
01379                                  u8 *pac, size_t pac_len, size_t *resp_len)
01380 {
01381         struct wpa_ssid *config = eap_get_config(sm);
01382         struct pac_tlv_hdr *hdr;
01383         u8 *pos;
01384         size_t left, len;
01385         int type, pac_key_found = 0;
01386         struct eap_fast_pac entry;
01387 
01388         os_memset(&entry, 0, sizeof(entry));
01389         pos = pac;
01390         left = pac_len;
01391         while (left > sizeof(*hdr)) {
01392                 hdr = (struct pac_tlv_hdr *) pos;
01393                 type = be_to_host16(hdr->type);
01394                 len = be_to_host16(hdr->len);
01395                 pos += sizeof(*hdr);
01396                 left -= sizeof(*hdr);
01397                 if (len > left) {
01398                         wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV overrun "
01399                                    "(type=%d len=%lu left=%lu)",
01400                                    type, (unsigned long) len,
01401                                    (unsigned long) left);
01402                         return eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
01403                                                    resp_len);
01404                 }
01405                 switch (type) {
01406                 case PAC_TYPE_PAC_KEY:
01407                         wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: PAC-Key",
01408                                         pos, len);
01409                         if (len != EAP_FAST_PAC_KEY_LEN) {
01410                                 wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid "
01411                                            "PAC-Key length %lu",
01412                                            (unsigned long) len);
01413                                 break;
01414                         }
01415                         pac_key_found = 1;
01416                         os_memcpy(entry.pac_key, pos, len);
01417                         break;
01418                 case PAC_TYPE_PAC_OPAQUE:
01419                         wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Opaque",
01420                                         pos, len);
01421                         entry.pac_opaque = pos;
01422                         entry.pac_opaque_len = len;
01423                         break;
01424                 case PAC_TYPE_PAC_INFO:
01425                         wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Info",
01426                                     pos, len);
01427                         entry.pac_info = pos;
01428                         entry.pac_info_len = len;
01429                         break;
01430                 default:
01431                         wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored unknown PAC "
01432                                    "type %d", type);
01433                         break;
01434                 }
01435 
01436                 pos += len;
01437                 left -= len;
01438         }
01439 
01440         if (!pac_key_found || !entry.pac_opaque || !entry.pac_info) {
01441                 wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV does not include "
01442                            "all the required fields");
01443                 return eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
01444                                            resp_len);
01445         }
01446 
01447         pos = entry.pac_info;
01448         left = entry.pac_info_len;
01449         while (left > sizeof(*hdr)) {
01450                 hdr = (struct pac_tlv_hdr *) pos;
01451                 type = be_to_host16(hdr->type);
01452                 len = be_to_host16(hdr->len);
01453                 pos += sizeof(*hdr);
01454                 left -= sizeof(*hdr);
01455                 if (len > left) {
01456                         wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info overrun "
01457                                    "(type=%d len=%lu left=%lu)",
01458                                    type, (unsigned long) len,
01459                                    (unsigned long) left);
01460                         return eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
01461                                                    resp_len);
01462                 }
01463                 switch (type) {
01464                 case PAC_TYPE_A_ID:
01465                         wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - "
01466                                           "A-ID", pos, len);
01467                         entry.a_id = pos;
01468                         entry.a_id_len = len;
01469                         break;
01470                 case PAC_TYPE_I_ID:
01471                         wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - "
01472                                           "I-ID", pos, len);
01473                         entry.i_id = pos;
01474                         entry.i_id_len = len;
01475                         break;
01476                 case PAC_TYPE_A_ID_INFO:
01477                         wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - "
01478                                           "A-ID-Info", pos, len);
01479                         entry.a_id_info = pos;
01480                         entry.a_id_info_len = len;
01481                         break;
01482                 default:
01483                         wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored unknown "
01484                                    "PAC-Info type %d", type);
01485                         break;
01486                 }
01487 
01488                 pos += len;
01489                 left -= len;
01490         }
01491 
01492         if (entry.a_id == NULL || entry.a_id_info == NULL) {
01493                 wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info does not include "
01494                            "all the required fields");
01495                 return eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
01496                                            resp_len);
01497         }
01498 
01499         eap_fast_add_pac(data, &entry);
01500         eap_fast_save_pac(sm, data, config->pac_file);
01501 
01502         if (data->provisioning) {
01503                 /* EAP-FAST provisioning does not provide keying material and
01504                  * must end with an EAP-Failure. Authentication will be done
01505                  * separately after this. */
01506                 data->success = 0;
01507                 ret->decision = DECISION_FAIL;
01508                 wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV "
01509                            "- Provisioning completed successfully");
01510         } else {
01511                 /* This is PAC refreshing, i.e., normal authentication that is
01512                  * expected to be completed with an EAP-Success. */
01513                 wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV "
01514                            "- PAC refreshing completed successfully");
01515                 ret->decision = DECISION_UNCOND_SUCC;
01516         }
01517         ret->methodState = METHOD_DONE;
01518         return eap_fast_tlv_pac_ack(resp_len);
01519 }
01520 
01521 
01522 static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
01523                             struct eap_method_ret *ret,
01524                             const struct eap_hdr *req,
01525                             const u8 *in_data, size_t in_len,
01526                             u8 **out_data, size_t *out_len)
01527 {
01528         u8 *in_decrypted, *pos, *end;
01529         int len_decrypted, len;
01530         struct eap_hdr *hdr;
01531         u8 *resp = NULL;
01532         size_t buf_len, resp_len;
01533         int mandatory, tlv_type;
01534         u8 *eap_payload_tlv = NULL, *pac = NULL;
01535         size_t eap_payload_tlv_len = 0, pac_len = 0;
01536         int iresult = 0, result = 0;
01537         struct eap_tlv_crypto_binding__tlv *crypto_binding = NULL;
01538         size_t crypto_binding_len = 0;
01539         const u8 *msg;
01540         size_t msg_len;
01541         int need_more_input, stop;
01542 
01543         wpa_printf(MSG_DEBUG, "EAP-FAST: received %lu bytes encrypted data for"
01544                    " Phase 2", (unsigned long) in_len);
01545 
01546         msg = eap_tls_data_reassemble(sm, &data->ssl, in_data, in_len,
01547                                       &msg_len, &need_more_input);
01548         if (msg == NULL)
01549                 return need_more_input ? 1 : -1;
01550 
01551         buf_len = in_len;
01552         if (data->ssl.tls_in_total > buf_len)
01553                 buf_len = data->ssl.tls_in_total;
01554         in_decrypted = os_malloc(buf_len);
01555         if (in_decrypted == NULL) {
01556                 os_free(data->ssl.tls_in);
01557                 data->ssl.tls_in = NULL;
01558                 data->ssl.tls_in_len = 0;
01559                 wpa_printf(MSG_WARNING, "EAP-FAST: failed to allocate memory "
01560                            "for decryption");
01561                 return -1;
01562         }
01563 
01564         len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
01565                                                msg, msg_len,
01566                                                in_decrypted, buf_len);
01567         os_free(data->ssl.tls_in);
01568         data->ssl.tls_in = NULL;
01569         data->ssl.tls_in_len = 0;
01570         if (len_decrypted < 0) {
01571                 wpa_printf(MSG_INFO, "EAP-FAST: Failed to decrypt Phase 2 "
01572                            "data");
01573                 os_free(in_decrypted);
01574                 return -1;
01575         }
01576 
01577         wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Decrypted Phase 2 TLV(s)",
01578                     in_decrypted, len_decrypted);
01579 
01580         if (len_decrypted < 4) {
01581                 os_free(in_decrypted);
01582                 wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 "
01583                            "TLV frame (len=%d)", len_decrypted);
01584                 return -1;
01585         }
01586 
01587         pos = in_decrypted;
01588         end = in_decrypted + len_decrypted;
01589         stop = 0;
01590         while (pos + 4 < end && !stop) {
01591                 mandatory = pos[0] & 0x80;
01592                 tlv_type = WPA_GET_BE16(pos) & 0x3fff;
01593                 pos += 2;
01594                 len = WPA_GET_BE16(pos);
01595                 pos += 2;
01596                 if (pos + len > end) {
01597                         os_free(in_decrypted);
01598                         wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
01599                         return 0;
01600                 }
01601                 wpa_printf(MSG_DEBUG, "EAP-FAST: received Phase 2: "
01602                            "TLV type %d length %d%s",
01603                            tlv_type, len, mandatory ? " (mandatory)" : "");
01604 
01605                 switch (tlv_type) {
01606                 case EAP_TLV_EAP_PAYLOAD_TLV:
01607                         wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: EAP Payload TLV",
01608                                     pos, len);
01609                         eap_payload_tlv = pos;
01610                         eap_payload_tlv_len = len;
01611                         break;
01612                 case EAP_TLV_RESULT_TLV:
01613                         wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Result TLV",
01614                                     pos, len);
01615                         if (len < 2) {
01616                                 wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
01617                                            "Result TLV");
01618                                 result = EAP_TLV_RESULT_FAILURE;
01619                                 break;
01620                         }
01621                         result = WPA_GET_BE16(pos);
01622                         if (result != EAP_TLV_RESULT_SUCCESS &&
01623                             result != EAP_TLV_RESULT_FAILURE) {
01624                                 wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown "
01625                                            "Result %d", result);
01626                                 result = EAP_TLV_RESULT_FAILURE;
01627                         }
01628                         wpa_printf(MSG_DEBUG, "EAP-FAST: Result: %s",
01629                                    result == EAP_TLV_RESULT_SUCCESS ?
01630                                    "Success" : "Failure");
01631                         break;
01632                 case EAP_TLV_INTERMEDIATE_RESULT_TLV:
01633                         wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Intermediate "
01634                                     "Result TLV", pos, len);
01635                         if (len < 2) {
01636                                 wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
01637                                            "Intermediate Result TLV");
01638                                 iresult = EAP_TLV_RESULT_FAILURE;
01639                                 break;
01640                         }
01641                         iresult = WPA_GET_BE16(pos);
01642                         if (iresult != EAP_TLV_RESULT_SUCCESS &&
01643                             iresult != EAP_TLV_RESULT_FAILURE) {
01644                                 wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown "
01645                                            "Intermediate Result %d", iresult);
01646                                 iresult = EAP_TLV_RESULT_FAILURE;
01647                         }
01648                         wpa_printf(MSG_DEBUG,
01649                                    "EAP-FAST: Intermediate Result: %s",
01650                                    iresult == EAP_TLV_RESULT_SUCCESS ?
01651                                    "Success" : "Failure");
01652                         break;
01653                 case EAP_TLV_CRYPTO_BINDING_TLV_:
01654                         wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding "
01655                                     "TLV", pos, len);
01656                         crypto_binding_len = sizeof(struct eap_tlv_hdr) + len;
01657                         if (crypto_binding_len < sizeof(*crypto_binding)) {
01658                                 wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
01659                                            "Crypto-Binding TLV");
01660                                 iresult = EAP_TLV_RESULT_FAILURE;
01661                                 pos = end;
01662                                 break;
01663                         }
01664                         crypto_binding =
01665                                 (struct eap_tlv_crypto_binding__tlv *)
01666                                 (pos - sizeof(struct eap_tlv_hdr));
01667                         break;
01668                 case EAP_TLV_PAC_TLV:
01669                         wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: PAC TLV",
01670                                     pos, len);
01671                         pac = pos;
01672                         pac_len = len;
01673                         break;
01674                 default:
01675                         if (mandatory) {
01676                                 wpa_printf(MSG_DEBUG, "EAP-FAST: Nak unknown "
01677                                            "mandatory TLV type %d", tlv_type);
01678                                 resp = eap_fast_tlv_nak(0, tlv_type,
01679                                                         &resp_len);
01680                                 stop = 1;
01681                         } else {
01682                                 wpa_printf(MSG_DEBUG, "EAP-FAST: ignored "
01683                                            "unknown optional TLV type %d",
01684                                            tlv_type);
01685                         }
01686                         break;
01687                 }
01688 
01689                 pos += len;
01690         }
01691 
01692         if (!resp && result == EAP_TLV_RESULT_FAILURE) {
01693                 resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
01694                                            &resp_len);
01695                 if (!resp) {
01696                         os_free(in_decrypted);
01697                         return 0;
01698                 }
01699         }
01700 
01701         if (!resp && iresult == EAP_TLV_RESULT_FAILURE) {
01702                 resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1,
01703                                            &resp_len);
01704                 if (!resp) {
01705                         os_free(in_decrypted);
01706                         return 0;
01707                 }
01708         }
01709 
01710         if (!resp && eap_payload_tlv) {
01711                 if (eap_payload_tlv_len < sizeof(*hdr)) {
01712                         wpa_printf(MSG_DEBUG, "EAP-FAST: too short EAP "
01713                                    "Payload TLV (len=%lu)",
01714                                    (unsigned long) eap_payload_tlv_len);
01715                         os_free(in_decrypted);
01716                         return 0;
01717                 }
01718                 hdr = (struct eap_hdr *) eap_payload_tlv;
01719                 if (be_to_host16(hdr->length) > eap_payload_tlv_len) {
01720                         wpa_printf(MSG_DEBUG, "EAP-FAST: EAP packet overflow "
01721                                    "in EAP Payload TLV");
01722                         os_free(in_decrypted);
01723                         return 0;
01724                 }
01725                 if (hdr->code == EAP_CODE_REQUEST) {
01726                         if (eap_fast_phase2_request(sm, data, ret, hdr,
01727                                                     &resp, &resp_len)) {
01728                                 os_free(in_decrypted);
01729                                 wpa_printf(MSG_INFO, "EAP-FAST: Phase2 "
01730                                            "Request processing failed");
01731                                 return 0;
01732                         }
01733                         resp = eap_fast_tlv_eap_payload(resp, &resp_len);
01734                         if (resp == NULL) {
01735                                 os_free(in_decrypted);
01736                                 return 0;
01737                         }
01738                 } else {
01739                         wpa_printf(MSG_INFO, "EAP-FAST: Unexpected code=%d in "
01740                                    "Phase 2 EAP header", hdr->code);
01741                         os_free(in_decrypted);
01742                         return 0;
01743                 }
01744         }
01745 
01746         if (!resp && crypto_binding) {
01747                 int final = result == EAP_TLV_RESULT_SUCCESS;
01748                 resp = eap_fast_process_crypto_binding(sm, data, ret,
01749                                                        crypto_binding,
01750                                                        crypto_binding_len,
01751                                                        &resp_len, final);
01752                 if (!resp) {
01753                         os_free(in_decrypted);
01754                         return 0;
01755                 }
01756         }
01757 
01758         if (!resp && pac && result != EAP_TLV_RESULT_SUCCESS) {
01759                 wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV without Result TLV "
01760                            "acknowledging success");
01761                 resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
01762                                            &resp_len);
01763                 if (!resp) {
01764                         os_free(in_decrypted);
01765                         return 0;
01766                 }
01767         }
01768 
01769         if (!resp && pac && result == EAP_TLV_RESULT_SUCCESS) {
01770                 resp = eap_fast_process_pac(sm, data, ret, pac, pac_len,
01771                                             &resp_len);
01772                 if (!resp) {
01773                         os_free(in_decrypted);
01774                         return 0;
01775                 }
01776         }
01777 
01778         os_free(in_decrypted);
01779 
01780         if (resp == NULL) {
01781                 wpa_printf(MSG_DEBUG, "EAP-FAST: No recognized TLVs - send "
01782                            "empty response packet");
01783                 resp = os_malloc(1);
01784                 if (resp == NULL)
01785                         return 0;
01786                 resp_len = 0;
01787         }
01788 
01789         wpa_hexdump(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 data",
01790                     resp, resp_len);
01791         if (eap_fast_encrypt(sm, data, req->identifier, resp, resp_len,
01792                              out_data, out_len)) {
01793                 wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt a Phase 2 "
01794                            "frame");
01795         }
01796         os_free(resp);
01797 
01798         return 0;
01799 }
01800 
01801 
01802 static u8 * eap_fast_process(struct eap_sm *sm, void *priv,
01803                              struct eap_method_ret *ret,
01804                              const u8 *reqData, size_t reqDataLen,
01805                              size_t *respDataLen)
01806 {
01807         const struct eap_hdr *req;
01808         size_t left;
01809         int res;
01810         u8 flags, *resp, id;
01811         const u8 *pos;
01812         struct eap_fast_data *data = priv;
01813 
01814         pos = eap_tls_process_init(sm, &data->ssl, EAP_TYPE_FAST, ret,
01815                                    reqData, reqDataLen, &left, &flags);
01816         if (pos == NULL)
01817                 return NULL;
01818         req = (const struct eap_hdr *) reqData;
01819         id = req->identifier;
01820 
01821         if (flags & EAP_TLS_FLAGS_START) {
01822                 const u8 *a_id;
01823                 size_t a_id_len;
01824                 struct pac_tlv_hdr *hdr;
01825 
01826                 wpa_printf(MSG_DEBUG, "EAP-FAST: Start (server ver=%d, own "
01827                            "ver=%d)", flags & EAP_PEAP_VERSION_MASK,
01828                         data->fast_version);
01829                 if ((flags & EAP_PEAP_VERSION_MASK) < data->fast_version)
01830                         data->fast_version = flags & EAP_PEAP_VERSION_MASK;
01831                 wpa_printf(MSG_DEBUG, "EAP-FAST: Using FAST version %d",
01832                            data->fast_version);
01833 
01834                 a_id = pos;
01835                 a_id_len = left;
01836                 if (left > sizeof(*hdr)) {
01837                         int tlen;
01838                         hdr = (struct pac_tlv_hdr *) pos;
01839                         tlen = be_to_host16(hdr->len);
01840                         if (be_to_host16(hdr->type) == PAC_TYPE_A_ID &&
01841                             sizeof(*hdr) + tlen <= left) {
01842                                 a_id = (u8 *) (hdr + 1);
01843                                 a_id_len = tlen;
01844                         }
01845                 }
01846                 wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: A-ID", a_id, a_id_len);
01847 
01848                 data->current_pac = eap_fast_get_pac(data, a_id, a_id_len);
01849                 if (data->current_pac) {
01850                         wpa_printf(MSG_DEBUG, "EAP-FAST: PAC found for this "
01851                                    "A-ID");
01852                         wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-FAST: A-ID-Info",
01853                                           data->current_pac->a_id_info,
01854                                           data->current_pac->a_id_info_len);
01855                 }
01856 
01857                 if (data->resuming && data->current_pac) {
01858                         wpa_printf(MSG_DEBUG, "EAP-FAST: Trying to resume "
01859                                    "session - do not add PAC-Opaque to TLS "
01860                                    "ClientHello");
01861                         if (tls_connection_client_hello_ext(
01862                                     sm->ssl_ctx, data->ssl.conn,
01863                                     TLS_EXT_PAC_OPAQUE, NULL, 0) < 0) {
01864                                 wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to "
01865                                            "remove PAC-Opaque TLS extension");
01866                                 return NULL;
01867                         }
01868 
01869                 } else if (data->current_pac) {
01870                         u8 *tlv;
01871                         size_t tlv_len, olen;
01872                         struct eap_tlv_hdr *ehdr;
01873                         olen = data->current_pac->pac_opaque_len;
01874                         tlv_len = sizeof(*ehdr) + olen;
01875                         tlv = os_malloc(tlv_len);
01876                         if (tlv) {
01877                                 ehdr = (struct eap_tlv_hdr *) tlv;
01878                                 ehdr->tlv_type =
01879                                         host_to_be16(PAC_TYPE_PAC_OPAQUE);
01880                                 ehdr->length = host_to_be16(olen);
01881                                 os_memcpy(ehdr + 1,
01882                                           data->current_pac->pac_opaque, olen);
01883                         }
01884                         if (tlv == NULL ||
01885                             tls_connection_client_hello_ext(
01886                                     sm->ssl_ctx, data->ssl.conn,
01887                                     TLS_EXT_PAC_OPAQUE, tlv, tlv_len) < 0) {
01888                                 wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to "
01889                                            "add PAC-Opaque TLS extension");
01890                                 os_free(tlv);
01891                                 return NULL;
01892                         }
01893                         os_free(tlv);
01894                 } else {
01895                         u8 ciphers[2];
01896                         if (!data->provisioning_allowed) {
01897                                 wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC found "
01898                                            "and provisioning disabled");
01899                                 return NULL;
01900                         }
01901                         wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC found - "
01902                                    "starting provisioning");
01903                         ciphers[0] = TLS_CIPHER_ANON_DH_AES128_SHA;
01904                         ciphers[1] = TLS_CIPHER_NONE;
01905                         if (tls_connection_set_cipher_list(sm->ssl_ctx,
01906                                                            data->ssl.conn,
01907                                                            ciphers)) {
01908                                 wpa_printf(MSG_INFO, "EAP-FAST: Could not "
01909                                            "configure anonymous DH for TLS "
01910                                            "connection");
01911                                 return NULL;
01912                         }
01913                         if (tls_connection_client_hello_ext(
01914                                     sm->ssl_ctx, data->ssl.conn,
01915                                     TLS_EXT_PAC_OPAQUE, NULL, 0) < 0) {
01916                                 wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to "
01917                                            "remove PAC-Opaque TLS extension");
01918                                 return NULL;
01919                         }
01920                         data->provisioning = 1;
01921                 }
01922 
01923                 left = 0; /* A-ID is not used in further packet processing */
01924         }
01925 
01926         resp = NULL;
01927         if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
01928             !data->resuming) {
01929                 res = eap_fast_decrypt(sm, data, ret, req, pos, left,
01930                                        &resp, respDataLen);
01931                 if (res < 0) {
01932                         ret->methodState = METHOD_DONE;
01933                         ret->decision = DECISION_FAIL;
01934                         /* Ack possible Alert that may have caused failure in
01935                          * decryption */
01936                         res = 1;
01937                 }
01938         } else {
01939                 if (eap_fast_set_tls_master_secret(sm, data, pos, left) < 0) {
01940                         wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to configure "
01941                                    "TLS master secret");
01942                         ret->methodState = METHOD_DONE;
01943                         ret->decision = DECISION_FAIL;
01944                         return NULL;
01945                 }
01946 
01947                 res = eap_tls_process_helper(sm, &data->ssl, EAP_TYPE_FAST,
01948                                              data->fast_version, id, pos, left,
01949                                              &resp, respDataLen);
01950 
01951                 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
01952                         wpa_printf(MSG_DEBUG,
01953                                    "EAP-FAST: TLS done, proceed to Phase 2");
01954                         data->resuming = 0;
01955                         eap_fast_derive_keys(sm, data);
01956                 }
01957         }
01958 
01959         if (res == 1)
01960                 return eap_tls_build_ack(&data->ssl, respDataLen, id,
01961                                          EAP_TYPE_FAST, data->fast_version);
01962         return resp;
01963 }
01964 
01965 
01966 #if 0 /* FIX */
01967 static Boolean eap_fast_has_reauth_data(struct eap_sm *sm, void *priv)
01968 {
01969         struct eap_fast_data *data = priv;
01970         return tls_connection_established(sm->ssl_ctx, data->ssl.conn);
01971 }
01972 
01973 
01974 static void eap_fast_deinit_for_reauth(struct eap_sm *sm, void *priv)
01975 {
01976         struct eap_fast_data *data = priv;
01977         os_free(data->key_block_p);
01978         data->key_block_p = NULL;
01979 }
01980 
01981 
01982 static void * eap_fast_init_for_reauth(struct eap_sm *sm, void *priv)
01983 {
01984         struct eap_fast_data *data = priv;
01985         if (eap_tls_reauth_init(sm, &data->ssl)) {
01986                 os_free(data);
01987                 return NULL;
01988         }
01989         if (data->phase2_priv && data->phase2_method &&
01990             data->phase2_method->init_for_reauth)
01991                 data->phase2_method->init_for_reauth(sm, data->phase2_priv);
01992         data->phase2_success = 0;
01993         data->resuming = 1;
01994         data->provisioning = 0;
01995         data->simck_idx = 0;
01996         return priv;
01997 }
01998 #endif
01999 
02000 
02001 static int eap_fast_get_status(struct eap_sm *sm, void *priv, char *buf,
02002                                size_t buflen, int verbose)
02003 {
02004         struct eap_fast_data *data = priv;
02005         int len, ret;
02006 
02007         len = eap_tls_status(sm, &data->ssl, buf, buflen, verbose);
02008         if (data->phase2_method) {
02009                 ret = os_snprintf(buf + len, buflen - len,
02010                                   "EAP-FAST Phase2 method=%s\n",
02011                                   data->phase2_method->name);
02012                 if (ret < 0 || (size_t) ret >= buflen - len)
02013                         return len;
02014                 len += ret;
02015         }
02016         return len;
02017 }
02018 
02019 
02020 static Boolean eap_fast_isKeyAvailable(struct eap_sm *sm, void *priv)
02021 {
02022         struct eap_fast_data *data = priv;
02023         return data->success;
02024 }
02025 
02026 
02027 static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len)
02028 {
02029         struct eap_fast_data *data = priv;
02030         u8 *key;
02031 
02032         if (!data->success)
02033                 return NULL;
02034 
02035         key = os_malloc(EAP_FAST_KEY_LEN);
02036         if (key == NULL)
02037                 return NULL;
02038 
02039         *len = EAP_FAST_KEY_LEN;
02040         os_memcpy(key, data->key_data, EAP_FAST_KEY_LEN);
02041 
02042         return key;
02043 }
02044 
02045 
02046 static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
02047 {
02048         struct eap_fast_data *data = priv;
02049         u8 *key;
02050 
02051         if (!data->success)
02052                 return NULL;
02053 
02054         key = os_malloc(EAP_EMSK_LEN);
02055         if (key == NULL)
02056                 return NULL;
02057 
02058         *len = EAP_EMSK_LEN;
02059         os_memcpy(key, data->emsk, EAP_EMSK_LEN);
02060 
02061         return key;
02062 }
02063 
02064 
02065 int eap_peer_fast_register(void)
02066 {
02067         struct eap_method *eap;
02068         int ret;
02069 
02070         eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
02071                                     EAP_VENDOR_IETF, EAP_TYPE_FAST, "FAST");
02072         if (eap == NULL)
02073                 return -1;
02074 
02075         eap->init = eap_fast_init;
02076         eap->deinit = eap_fast_deinit;
02077         eap->process = eap_fast_process;
02078         eap->isKeyAvailable = eap_fast_isKeyAvailable;
02079         eap->getKey = eap_fast_getKey;
02080         eap->get_status = eap_fast_get_status;
02081 #if 0
02082         eap->has_reauth_data = eap_fast_has_reauth_data;
02083         eap->deinit_for_reauth = eap_fast_deinit_for_reauth;
02084         eap->init_for_reauth = eap_fast_init_for_reauth;
02085 #endif
02086         eap->get_emsk = eap_fast_get_emsk;
02087 
02088         ret = eap_peer_method_register(eap);
02089         if (ret)
02090                 eap_peer_method_free(eap);
02091         return ret;
02092 }
02093 

Generated on Sun Dec 31 13:48:53 2006 for wpa_supplicant by  doxygen 1.4.2