eap_peap.c

Go to the documentation of this file.
00001 
00016 #include <stdlib.h>
00017 #include <stdio.h>
00018 #include <string.h>
00019 
00020 #include "common.h"
00021 #include "eap_i.h"
00022 #include "eap_tls_common.h"
00023 #include "wpa_supplicant.h"
00024 #include "config_ssid.h"
00025 #include "tls.h"
00026 #include "eap_tlv.h"
00027 
00028 
00029 /* Maximum supported PEAP version
00030  * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
00031  * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
00032  * 2 = draft-josefsson-ppext-eap-tls-eap-07.txt
00033  */
00034 #define EAP_PEAP_VERSION 1
00035 
00036 
00037 static void eap_peap_deinit(struct eap_sm *sm, void *priv);
00038 
00039 
00040 struct eap_peap_data {
00041         struct eap_ssl_data ssl;
00042 
00043         int peap_version, force_peap_version, force_new_label;
00044 
00045         const struct eap_method *phase2_method;
00046         void *phase2_priv;
00047         int phase2_success;
00048 
00049         u8 phase2_type;
00050         u8 *phase2_types;
00051         size_t num_phase2_types;
00052 
00053         int peap_outer_success; /* 0 = PEAP terminated on Phase 2 inner
00054                                  * EAP-Success
00055                                  * 1 = reply with tunneled EAP-Success to inner
00056                                  * EAP-Success and expect AS to send outer
00057                                  * (unencrypted) EAP-Success after this
00058                                  * 2 = reply with PEAP/TLS ACK to inner
00059                                  * EAP-Success and expect AS to send outer
00060                                  * (unencrypted) EAP-Success after this */
00061         int resuming; /* starting a resumed session */
00062         u8 *key_data;
00063 
00064         u8 *pending_phase2_req;
00065         size_t pending_phase2_req_len;
00066 };
00067 
00068 
00069 static void * eap_peap_init(struct eap_sm *sm)
00070 {
00071         struct eap_peap_data *data;
00072         struct wpa_ssid *config = eap_get_config(sm);
00073 
00074         data = malloc(sizeof(*data));
00075         if (data == NULL)
00076                 return NULL;
00077         sm->peap_done = FALSE;
00078         memset(data, 0, sizeof(*data));
00079         data->peap_version = EAP_PEAP_VERSION;
00080         data->force_peap_version = -1;
00081         data->peap_outer_success = 2;
00082 
00083         if (config && config->phase1) {
00084                 char *pos = strstr(config->phase1, "peapver=");
00085                 if (pos) {
00086                         data->force_peap_version = atoi(pos + 8);
00087                         data->peap_version = data->force_peap_version;
00088                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Forced PEAP version "
00089                                    "%d", data->force_peap_version);
00090                 }
00091 
00092                 if (strstr(config->phase1, "peaplabel=1")) {
00093                         data->force_new_label = 1;
00094                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Force new label for "
00095                                    "key derivation");
00096                 }
00097 
00098                 if (strstr(config->phase1, "peap_outer_success=0")) {
00099                         data->peap_outer_success = 0;
00100                         wpa_printf(MSG_DEBUG, "EAP-PEAP: terminate "
00101                                    "authentication on tunneled EAP-Success");
00102                 } else if (strstr(config->phase1, "peap_outer_success=1")) {
00103                         data->peap_outer_success = 1;
00104                         wpa_printf(MSG_DEBUG, "EAP-PEAP: send tunneled "
00105                                    "EAP-Success after receiving tunneled "
00106                                    "EAP-Success");
00107                 } else if (strstr(config->phase1, "peap_outer_success=2")) {
00108                         data->peap_outer_success = 2;
00109                         wpa_printf(MSG_DEBUG, "EAP-PEAP: send PEAP/TLS ACK "
00110                                    "after receiving tunneled EAP-Success");
00111                 }
00112         }
00113 
00114         if (config && config->phase2) {
00115                 char *start, *pos, *buf;
00116                 u8 method, *methods = NULL, *_methods;
00117                 size_t num_methods = 0;
00118                 start = buf = strdup(config->phase2);
00119                 if (buf == NULL) {
00120                         eap_peap_deinit(sm, data);
00121                         return NULL;
00122                 }
00123                 while (start && *start != '\0') {
00124                         pos = strstr(start, "auth=");
00125                         if (pos == NULL)
00126                                 break;
00127                         if (start != pos && *(pos - 1) != ' ') {
00128                                 start = pos + 5;
00129                                 continue;
00130                         }
00131 
00132                         start = pos + 5;
00133                         pos = strchr(start, ' ');
00134                         if (pos)
00135                                 *pos++ = '\0';
00136                         method = eap_get_phase2_type(start);
00137                         if (method == EAP_TYPE_NONE) {
00138                                 wpa_printf(MSG_ERROR, "EAP-PEAP: Unsupported "
00139                                            "Phase2 method '%s'", start);
00140                         } else {
00141                                 num_methods++;
00142                                 _methods = realloc(methods, num_methods);
00143                                 if (_methods == NULL) {
00144                                         free(methods);
00145                                         free(buf);
00146                                         eap_peap_deinit(sm, data);
00147                                         return NULL;
00148                                 }
00149                                 methods = _methods;
00150                                 methods[num_methods - 1] = method;
00151                         }
00152 
00153                         start = pos;
00154                 }
00155                 free(buf);
00156                 data->phase2_types = methods;
00157                 data->num_phase2_types = num_methods;
00158         }
00159         if (data->phase2_types == NULL) {
00160                 data->phase2_types =
00161                         eap_get_phase2_types(config, &data->num_phase2_types);
00162         }
00163         if (data->phase2_types == NULL) {
00164                 wpa_printf(MSG_ERROR, "EAP-PEAP: No Phase2 method available");
00165                 eap_peap_deinit(sm, data);
00166                 return NULL;
00167         }
00168         wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 EAP types",
00169                     data->phase2_types, data->num_phase2_types);
00170         data->phase2_type = EAP_TYPE_NONE;
00171 
00172         if (eap_tls_ssl_init(sm, &data->ssl, config)) {
00173                 wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
00174                 eap_peap_deinit(sm, data);
00175                 return NULL;
00176         }
00177 
00178         return data;
00179 }
00180 
00181 
00182 static void eap_peap_deinit(struct eap_sm *sm, void *priv)
00183 {
00184         struct eap_peap_data *data = priv;
00185         if (data == NULL)
00186                 return;
00187         if (data->phase2_priv && data->phase2_method)
00188                 data->phase2_method->deinit(sm, data->phase2_priv);
00189         free(data->phase2_types);
00190         eap_tls_ssl_deinit(sm, &data->ssl);
00191         free(data->key_data);
00192         free(data->pending_phase2_req);
00193         free(data);
00194 }
00195 
00196 
00197 static int eap_peap_encrypt(struct eap_sm *sm, struct eap_peap_data *data,
00198                             int id, const u8 *plain, size_t plain_len,
00199                             u8 **out_data, size_t *out_len)
00200 {
00201         int res;
00202         u8 *pos;
00203         struct eap_hdr *resp;
00204 
00205         /* TODO: add support for fragmentation, if needed. This will need to
00206          * add TLS Message Length field, if the frame is fragmented.
00207          * Note: Microsoft IAS did not seem to like TLS Message Length with
00208          * PEAP/MSCHAPv2. */
00209         resp = malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
00210         if (resp == NULL)
00211                 return -1;
00212 
00213         resp->code = EAP_CODE_RESPONSE;
00214         resp->identifier = id;
00215 
00216         pos = (u8 *) (resp + 1);
00217         *pos++ = EAP_TYPE_PEAP;
00218         *pos++ = data->peap_version;
00219 
00220         res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
00221                                      plain, plain_len,
00222                                      pos, data->ssl.tls_out_limit);
00223         if (res < 0) {
00224                 wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt Phase 2 "
00225                            "data");
00226                 free(resp);
00227                 return -1;
00228         }
00229 
00230         *out_len = sizeof(struct eap_hdr) + 2 + res;
00231         resp->length = host_to_be16(*out_len);
00232         *out_data = (u8 *) resp;
00233         return 0;
00234 }
00235 
00236 
00237 static int eap_peap_phase2_nak(struct eap_sm *sm,
00238                                struct eap_peap_data *data,
00239                                struct eap_hdr *hdr,
00240                                u8 **resp, size_t *resp_len)
00241 {
00242         struct eap_hdr *resp_hdr;
00243         u8 *pos = (u8 *) (hdr + 1);
00244 
00245         wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: Nak type=%d", *pos);
00246         wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Allowed Phase2 EAP types",
00247                     data->phase2_types, data->num_phase2_types);
00248         *resp_len = sizeof(struct eap_hdr) + 1 + data->num_phase2_types;
00249         *resp = malloc(*resp_len);
00250         if (*resp == NULL)
00251                 return -1;
00252 
00253         resp_hdr = (struct eap_hdr *) (*resp);
00254         resp_hdr->code = EAP_CODE_RESPONSE;
00255         resp_hdr->identifier = hdr->identifier;
00256         resp_hdr->length = host_to_be16(*resp_len);
00257         pos = (u8 *) (resp_hdr + 1);
00258         *pos++ = EAP_TYPE_NAK;
00259         memcpy(pos, data->phase2_types, data->num_phase2_types);
00260 
00261         return 0;
00262 }
00263 
00264 
00265 static int eap_peap_phase2_request(struct eap_sm *sm,
00266                                    struct eap_peap_data *data,
00267                                    struct eap_method_ret *ret,
00268                                    const struct eap_hdr *req,
00269                                    struct eap_hdr *hdr,
00270                                    u8 **resp, size_t *resp_len)
00271 {
00272         size_t len = be_to_host16(hdr->length);
00273         u8 *pos;
00274         struct eap_method_ret iret;
00275         struct wpa_ssid *config = eap_get_config(sm);
00276 
00277         if (len <= sizeof(struct eap_hdr)) {
00278                 wpa_printf(MSG_INFO, "EAP-PEAP: too short "
00279                            "Phase 2 request (len=%lu)", (unsigned long) len);
00280                 return -1;
00281         }
00282         pos = (u8 *) (hdr + 1);
00283         wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos);
00284         switch (*pos) {
00285         case EAP_TYPE_IDENTITY:
00286                 *resp = eap_sm_buildIdentity(sm, req->identifier, resp_len, 1);
00287                 break;
00288         case EAP_TYPE_TLV:
00289                 memset(&iret, 0, sizeof(iret));
00290                 if (eap_tlv_process(sm, &iret, hdr, resp, resp_len)) {
00291                         ret->methodState = METHOD_DONE;
00292                         ret->decision = DECISION_FAIL;
00293                         return -1;
00294                 }
00295                 if (iret.methodState == METHOD_DONE ||
00296                     iret.methodState == METHOD_MAY_CONT) {
00297                         ret->methodState = iret.methodState;
00298                         ret->decision = iret.decision;
00299                         data->phase2_success = 1;
00300                 }
00301                 break;
00302         default:
00303                 if (data->phase2_type == EAP_TYPE_NONE) {
00304                         int i;
00305                         for (i = 0; i < data->num_phase2_types; i++) {
00306                                 if (data->phase2_types[i] != *pos)
00307                                         continue;
00308 
00309                                 data->phase2_type = *pos;
00310                                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected "
00311                                            "Phase 2 EAP method %d",
00312                                            data->phase2_type);
00313                                 break;
00314                         }
00315                 }
00316                 if (*pos != data->phase2_type || *pos == EAP_TYPE_NONE) {
00317                         if (eap_peap_phase2_nak(sm, data, hdr, resp, resp_len))
00318                                 return -1;
00319                         return 0;
00320                 }
00321 
00322                 if (data->phase2_priv == NULL) {
00323                         data->phase2_method = eap_sm_get_eap_methods(*pos);
00324                         if (data->phase2_method) {
00325                                 sm->init_phase2 = 1;
00326                                 data->phase2_priv =
00327                                         data->phase2_method->init(sm);
00328                                 sm->init_phase2 = 0;
00329                         }
00330                 }
00331                 if (data->phase2_priv == NULL || data->phase2_method == NULL) {
00332                         wpa_printf(MSG_INFO, "EAP-PEAP: failed to initialize "
00333                                    "Phase 2 EAP method %d", *pos);
00334                         ret->methodState = METHOD_DONE;
00335                         ret->decision = DECISION_FAIL;
00336                         return -1;
00337                 }
00338                 memset(&iret, 0, sizeof(iret));
00339                 *resp = data->phase2_method->process(sm, data->phase2_priv,
00340                                                      &iret, (u8 *) hdr, len,
00341                                                      resp_len);
00342                 if ((iret.methodState == METHOD_DONE ||
00343                      iret.methodState == METHOD_MAY_CONT) &&
00344                     (iret.decision == DECISION_UNCOND_SUCC ||
00345                      iret.decision == DECISION_COND_SUCC)) {
00346                         data->phase2_success = 1;
00347                 }
00348                 break;
00349         }
00350 
00351         if (*resp == NULL &&
00352             (config->pending_req_identity || config->pending_req_password ||
00353              config->pending_req_otp || config->pending_req_new_password)) {
00354                 free(data->pending_phase2_req);
00355                 data->pending_phase2_req = malloc(len);
00356                 if (data->pending_phase2_req) {
00357                         memcpy(data->pending_phase2_req, hdr, len);
00358                         data->pending_phase2_req_len = len;
00359                 }
00360         }
00361 
00362         return 0;
00363 }
00364 
00365 
00366 static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,
00367                             struct eap_method_ret *ret,
00368                             const struct eap_hdr *req,
00369                             const u8 *in_data, size_t in_len,
00370                             u8 **out_data, size_t *out_len)
00371 {
00372         u8 *in_decrypted;
00373         int buf_len, len_decrypted, len, skip_change = 0;
00374         struct eap_hdr *hdr, *rhdr;
00375         u8 *resp = NULL;
00376         size_t resp_len;
00377         const u8 *msg;
00378         size_t msg_len;
00379         int need_more_input;
00380 
00381         wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
00382                    " Phase 2", (unsigned long) in_len);
00383 
00384         if (data->pending_phase2_req) {
00385                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 request - "
00386                            "skip decryption and use old data");
00387                 /* Clear TLS reassembly state. */
00388                 free(data->ssl.tls_in);
00389                 data->ssl.tls_in = NULL;
00390                 data->ssl.tls_in_len = 0;
00391                 data->ssl.tls_in_left = 0;
00392                 data->ssl.tls_in_total = 0;
00393                 in_decrypted = data->pending_phase2_req;
00394                 data->pending_phase2_req = NULL;
00395                 len_decrypted = data->pending_phase2_req_len;
00396                 skip_change = 1;
00397                 goto continue_req;
00398         }
00399 
00400         msg = eap_tls_data_reassemble(sm, &data->ssl, in_data, in_len,
00401                                       &msg_len, &need_more_input);
00402         if (msg == NULL)
00403                 return need_more_input ? 1 : -1;
00404 
00405         if (in_len == 0 && sm->workaround && data->phase2_success) {
00406                 /*
00407                  * Cisco ACS seems to be using TLS ACK to terminate
00408                  * EAP-PEAPv0/GTC. Try to reply with TLS ACK.
00409                  */
00410                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Received TLS ACK, but "
00411                            "expected data - acknowledge with TLS ACK since "
00412                            "Phase 2 has been completed");
00413                 ret->decision = DECISION_COND_SUCC;
00414                 ret->methodState = METHOD_DONE;
00415                 return 1;
00416         }
00417 
00418         buf_len = in_len;
00419         if (data->ssl.tls_in_total > buf_len)
00420                 buf_len = data->ssl.tls_in_total;
00421         in_decrypted = malloc(buf_len);
00422         if (in_decrypted == NULL) {
00423                 free(data->ssl.tls_in);
00424                 data->ssl.tls_in = NULL;
00425                 data->ssl.tls_in_len = 0;
00426                 wpa_printf(MSG_WARNING, "EAP-PEAP: failed to allocate memory "
00427                            "for decryption");
00428                 return -1;
00429         }
00430 
00431         len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
00432                                                msg, msg_len,
00433                                                in_decrypted, buf_len);
00434         free(data->ssl.tls_in);
00435         data->ssl.tls_in = NULL;
00436         data->ssl.tls_in_len = 0;
00437         if (len_decrypted < 0) {
00438                 wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 "
00439                            "data");
00440                 free(in_decrypted);
00441                 return 0;
00442         }
00443 
00444 continue_req:
00445         wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", in_decrypted,
00446                     len_decrypted);
00447 
00448         hdr = (struct eap_hdr *) in_decrypted;
00449         if (len_decrypted == 5 && hdr->code == EAP_CODE_REQUEST &&
00450             be_to_host16(hdr->length) == 5 &&
00451             in_decrypted[4] == EAP_TYPE_IDENTITY) {
00452                 /* At least FreeRADIUS seems to send full EAP header with
00453                  * EAP Request Identity */
00454                 skip_change = 1;
00455         }
00456         if (len_decrypted >= 5 && hdr->code == EAP_CODE_REQUEST &&
00457             in_decrypted[4] == EAP_TYPE_TLV) {
00458                 skip_change = 1;
00459         }
00460 
00461         if (data->peap_version == 0 && !skip_change) {
00462                 struct eap_hdr *nhdr = malloc(sizeof(struct eap_hdr) +
00463                                               len_decrypted);
00464                 if (nhdr == NULL) {
00465                         free(in_decrypted);
00466                         return 0;
00467                 }
00468                 memcpy((u8 *) (nhdr + 1), in_decrypted, len_decrypted);
00469                 free(in_decrypted);
00470                 nhdr->code = req->code;
00471                 nhdr->identifier = req->identifier;
00472                 nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
00473                                             len_decrypted);
00474 
00475                 len_decrypted += sizeof(struct eap_hdr);
00476                 in_decrypted = (u8 *) nhdr;
00477         }
00478         hdr = (struct eap_hdr *) in_decrypted;
00479         if (len_decrypted < sizeof(*hdr)) {
00480                 free(in_decrypted);
00481                 wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
00482                            "EAP frame (len=%d)", len_decrypted);
00483                 return 0;
00484         }
00485         len = be_to_host16(hdr->length);
00486         if (len > len_decrypted) {
00487                 free(in_decrypted);
00488                 wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
00489                            "Phase 2 EAP frame (len=%d hdr->length=%d)",
00490                            len_decrypted, len);
00491                 return 0;
00492         }
00493         if (len < len_decrypted) {
00494                 wpa_printf(MSG_INFO, "EAP-PEAP: Odd.. Phase 2 EAP header has "
00495                            "shorter length than full decrypted data (%d < %d)",
00496                            len, len_decrypted);
00497                 if (sm->workaround && len == 4 && len_decrypted == 5 &&
00498                     in_decrypted[4] == EAP_TYPE_IDENTITY) {
00499                         /* Radiator 3.9 seems to set Phase 2 EAP header to use
00500                          * incorrect length for the EAP-Request Identity
00501                          * packet, so fix the inner header to interoperate..
00502                          * This was fixed in 2004-06-23 patch for Radiator and
00503                          * this workaround can be removed at some point. */
00504                         wpa_printf(MSG_INFO, "EAP-PEAP: workaround -> replace "
00505                                    "Phase 2 EAP header len (%d) with real "
00506                                    "decrypted len (%d)", len, len_decrypted);
00507                         len = len_decrypted;
00508                         hdr->length = host_to_be16(len);
00509                 }
00510         }
00511         wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
00512                    "identifier=%d length=%d", hdr->code, hdr->identifier, len);
00513         switch (hdr->code) {
00514         case EAP_CODE_REQUEST:
00515                 if (eap_peap_phase2_request(sm, data, ret, req, hdr,
00516                                             &resp, &resp_len)) {
00517                         free(in_decrypted);
00518                         wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request "
00519                                    "processing failed");
00520                         return 0;
00521                 }
00522                 break;
00523         case EAP_CODE_SUCCESS:
00524                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
00525                 if (data->peap_version == 1) {
00526                         /* EAP-Success within TLS tunnel is used to indicate
00527                          * shutdown of the TLS channel. The authentication has
00528                          * been completed. */
00529                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - "
00530                                    "EAP-Success within TLS tunnel - "
00531                                    "authentication completed");
00532                         ret->decision = DECISION_UNCOND_SUCC;
00533                         ret->methodState = METHOD_DONE;
00534                         data->phase2_success = 1;
00535                         if (data->peap_outer_success == 2) {
00536                                 free(in_decrypted);
00537                                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK "
00538                                            "to finish authentication");
00539                                 return 1;
00540                         } else if (data->peap_outer_success == 1) {
00541                                 /* Reply with EAP-Success within the TLS
00542                                  * channel to complete the authentication. */
00543                                 resp_len = sizeof(struct eap_hdr);
00544                                 resp = malloc(resp_len);
00545                                 if (resp) {
00546                                         memset(resp, 0, resp_len);
00547                                         rhdr = (struct eap_hdr *) resp;
00548                                         rhdr->code = EAP_CODE_SUCCESS;
00549                                         rhdr->identifier = hdr->identifier;
00550                                         rhdr->length = host_to_be16(resp_len);
00551                                 }
00552                         } else {
00553                                 /* No EAP-Success expected for Phase 1 (outer,
00554                                  * unencrypted auth), so force EAP state
00555                                  * machine to SUCCESS state. */
00556                                 sm->peap_done = TRUE;
00557                         }
00558                 } else {
00559                         /* FIX: ? */
00560                 }
00561                 break;
00562         case EAP_CODE_FAILURE:
00563                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
00564                 ret->decision = DECISION_FAIL;
00565                 ret->methodState = METHOD_MAY_CONT;
00566                 ret->allowNotifications = FALSE;
00567                 /* Reply with EAP-Failure within the TLS channel to complete
00568                  * failure reporting. */
00569                 resp_len = sizeof(struct eap_hdr);
00570                 resp = malloc(resp_len);
00571                 if (resp) {
00572                         memset(resp, 0, resp_len);
00573                         rhdr = (struct eap_hdr *) resp;
00574                         rhdr->code = EAP_CODE_FAILURE;
00575                         rhdr->identifier = hdr->identifier;
00576                         rhdr->length = host_to_be16(resp_len);
00577                 }
00578                 break;
00579         default:
00580                 wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
00581                            "Phase 2 EAP header", hdr->code);
00582                 break;
00583         }
00584 
00585         free(in_decrypted);
00586 
00587         if (resp) {
00588                 u8 *resp_pos;
00589                 size_t resp_send_len;
00590                 int skip_change = 0;
00591 
00592                 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
00593                                 resp, resp_len);
00594                 /* PEAP version changes */
00595                 if (resp_len >= 5 && resp[0] == EAP_CODE_RESPONSE &&
00596                     resp[4] == EAP_TYPE_TLV)
00597                         skip_change = 1;
00598                 if (data->peap_version == 0 && !skip_change) {
00599                         resp_pos = resp + sizeof(struct eap_hdr);
00600                         resp_send_len = resp_len - sizeof(struct eap_hdr);
00601                 } else {
00602                         resp_pos = resp;
00603                         resp_send_len = resp_len;
00604                 }
00605 
00606                 if (eap_peap_encrypt(sm, data, req->identifier,
00607                                      resp_pos, resp_send_len,
00608                                      out_data, out_len)) {
00609                         wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt "
00610                                    "a Phase 2 frame");
00611                 }
00612                 free(resp);
00613         }
00614 
00615         return 0;
00616 }
00617 
00618 
00619 static u8 * eap_peap_process(struct eap_sm *sm, void *priv,
00620                              struct eap_method_ret *ret,
00621                              const u8 *reqData, size_t reqDataLen,
00622                              size_t *respDataLen)
00623 {
00624         const struct eap_hdr *req;
00625         size_t left;
00626         int res;
00627         u8 flags, *resp, id;
00628         const u8 *pos;
00629         struct eap_peap_data *data = priv;
00630 
00631         pos = eap_tls_process_init(sm, &data->ssl, EAP_TYPE_PEAP, ret,
00632                                    reqData, reqDataLen, &left, &flags);
00633         if (pos == NULL)
00634                 return NULL;
00635         req = (const struct eap_hdr *) reqData;
00636         id = req->identifier;
00637 
00638         if (flags & EAP_TLS_FLAGS_START) {
00639                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own "
00640                            "ver=%d)", flags & EAP_PEAP_VERSION_MASK,
00641                         data->peap_version);
00642                 if ((flags & EAP_PEAP_VERSION_MASK) < data->peap_version)
00643                         data->peap_version = flags & EAP_PEAP_VERSION_MASK;
00644                 if (data->force_peap_version >= 0 &&
00645                     data->force_peap_version != data->peap_version) {
00646                         wpa_printf(MSG_WARNING, "EAP-PEAP: Failed to select "
00647                                    "forced PEAP version %d",
00648                                    data->force_peap_version);
00649                         ret->methodState = METHOD_DONE;
00650                         ret->decision = DECISION_FAIL;
00651                         ret->allowNotifications = FALSE;
00652                         return NULL;
00653                 }
00654                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d",
00655                            data->peap_version);
00656                 left = 0; /* make sure that this frame is empty, even though it
00657                            * should always be, anyway */
00658         }
00659 
00660         resp = NULL;
00661         if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
00662             !data->resuming) {
00663                 res = eap_peap_decrypt(sm, data, ret, req, pos, left,
00664                                        &resp, respDataLen);
00665         } else {
00666                 res = eap_tls_process_helper(sm, &data->ssl, EAP_TYPE_PEAP,
00667                                              data->peap_version, id, pos, left,
00668                                              &resp, respDataLen);
00669 
00670                 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
00671                         char *label;
00672                         wpa_printf(MSG_DEBUG,
00673                                    "EAP-PEAP: TLS done, proceed to Phase 2");
00674                         free(data->key_data);
00675                         /* draft-josefsson-ppext-eap-tls-eap-05.txt
00676                          * specifies that PEAPv1 would use "client PEAP
00677                          * encryption" as the label. However, most existing
00678                          * PEAPv1 implementations seem to be using the old
00679                          * label, "client EAP encryption", instead. Use the old
00680                          * label by default, but allow it to be configured with
00681                          * phase1 parameter peaplabel=1. */
00682                         if (data->peap_version > 1 || data->force_new_label)
00683                                 label = "client PEAP encryption";
00684                         else
00685                                 label = "client EAP encryption";
00686                         wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in "
00687                                    "key derivation", label);
00688                         data->key_data =
00689                                 eap_tls_derive_key(sm, &data->ssl, label,
00690                                                    EAP_TLS_KEY_LEN);
00691                         if (data->key_data) {
00692                                 wpa_hexdump_key(MSG_DEBUG, 
00693                                                 "EAP-PEAP: Derived key",
00694                                                 data->key_data,
00695                                                 EAP_TLS_KEY_LEN);
00696                         } else {
00697                                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to "
00698                                            "derive key");
00699                         }
00700 
00701                         if (sm->workaround && data->resuming) {
00702                                 /*
00703                                  * At least few RADIUS servers (Aegis v1.1.6;
00704                                  * but not v1.1.4; and Cisco ACS) seem to be
00705                                  * terminating PEAPv1 (Aegis) or PEAPv0 (Cisco
00706                                  * ACS) session resumption with outer
00707                                  * EAP-Success. This does not seem to follow
00708                                  * draft-josefsson-pppext-eap-tls-eap-05.txt
00709                                  * section 4.2, so only allow this if EAP
00710                                  * workarounds are enabled.
00711                                  */
00712                                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Workaround - "
00713                                            "allow outer EAP-Success to "
00714                                            "terminate PEAP resumption");
00715                                 ret->decision = DECISION_COND_SUCC;
00716                                 data->phase2_success = 1;
00717                         }
00718 
00719                         data->resuming = 0;
00720                 }
00721         }
00722 
00723         if (ret->methodState == METHOD_DONE) {
00724                 ret->allowNotifications = FALSE;
00725         }
00726 
00727         if (res == 1) {
00728                 return eap_tls_build_ack(&data->ssl, respDataLen, id,
00729                                          EAP_TYPE_PEAP, data->peap_version);
00730         }
00731 
00732         return resp;
00733 }
00734 
00735 
00736 static Boolean eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
00737 {
00738         struct eap_peap_data *data = priv;
00739         return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
00740                 data->phase2_success;
00741 }
00742 
00743 
00744 static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
00745 {
00746         struct eap_peap_data *data = priv;
00747         free(data->pending_phase2_req);
00748         data->pending_phase2_req = NULL;
00749 }
00750 
00751 
00752 static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)
00753 {
00754         struct eap_peap_data *data = priv;
00755         free(data->key_data);
00756         data->key_data = NULL;
00757         if (eap_tls_reauth_init(sm, &data->ssl)) {
00758                 free(data);
00759                 return NULL;
00760         }
00761         data->phase2_success = 0;
00762         data->resuming = 1;
00763         sm->peap_done = FALSE;
00764         return priv;
00765 }
00766 
00767 
00768 static int eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf,
00769                                size_t buflen, int verbose)
00770 {
00771         struct eap_peap_data *data = priv;
00772         int len;
00773 
00774         len = eap_tls_status(sm, &data->ssl, buf, buflen, verbose);
00775         if (data->phase2_method) {
00776                 len += snprintf(buf + len, buflen - len,
00777                                 "EAP-PEAPv%d Phase2 method=%s\n",
00778                                 data->peap_version, data->phase2_method->name);
00779         }
00780         return len;
00781 }
00782 
00783 
00784 static Boolean eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv)
00785 {
00786         struct eap_peap_data *data = priv;
00787         return data->key_data != NULL && data->phase2_success;
00788 }
00789 
00790 
00791 static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
00792 {
00793         struct eap_peap_data *data = priv;
00794         u8 *key;
00795 
00796         if (data->key_data == NULL || !data->phase2_success)
00797                 return NULL;
00798 
00799         key = malloc(EAP_TLS_KEY_LEN);
00800         if (key == NULL)
00801                 return NULL;
00802 
00803         *len = EAP_TLS_KEY_LEN;
00804         memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
00805 
00806         return key;
00807 }
00808 
00809 
00810 const struct eap_method eap_method_peap =
00811 {
00812         .method = EAP_TYPE_PEAP,
00813         .name = "PEAP",
00814         .init = eap_peap_init,
00815         .deinit = eap_peap_deinit,
00816         .process = eap_peap_process,
00817         .isKeyAvailable = eap_peap_isKeyAvailable,
00818         .getKey = eap_peap_getKey,
00819         .get_status = eap_peap_get_status,
00820         .has_reauth_data = eap_peap_has_reauth_data,
00821         .deinit_for_reauth = eap_peap_deinit_for_reauth,
00822         .init_for_reauth = eap_peap_init_for_reauth,
00823 };
00824 

Generated on Sat May 6 21:13:35 2006 for wpa_supplicant by  doxygen 1.4.2