eap_peap.c

Go to the documentation of this file.
00001 
00016 #include "includes.h"
00017 
00018 #include "common.h"
00019 #include "sha1.h"
00020 #include "eap_i.h"
00021 #include "eap_tls_common.h"
00022 #include "eap_common/eap_tlv_common.h"
00023 #include "eap_common/eap_peap_common.h"
00024 #include "tls.h"
00025 #include "tncs.h"
00026 
00027 
00028 /* Maximum supported PEAP version
00029  * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
00030  * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
00031  * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt
00032  */
00033 #define EAP_PEAP_VERSION 1
00034 
00035 
00036 static void eap_peap_reset(struct eap_sm *sm, void *priv);
00037 
00038 
00039 struct eap_peap_data {
00040         struct eap_ssl_data ssl;
00041         enum {
00042                 START, PHASE1, PHASE1_ID2, PHASE2_START, PHASE2_ID,
00043                 PHASE2_METHOD, PHASE2_SOH,
00044                 PHASE2_TLV, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE
00045         } state;
00046 
00047         int peap_version;
00048         int recv_version;
00049         const struct eap_method *phase2_method;
00050         void *phase2_priv;
00051         int force_version;
00052         struct wpabuf *pending_phase2_resp;
00053         enum { TLV_REQ_NONE, TLV_REQ_SUCCESS, TLV_REQ_FAILURE } tlv_request;
00054         int crypto_binding_sent;
00055         int crypto_binding_used;
00056         enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
00057         u8 binding_nonce[32];
00058         u8 ipmk[40];
00059         u8 cmk[20];
00060         u8 *phase2_key;
00061         size_t phase2_key_len;
00062         struct wpabuf *soh_response;
00063 };
00064 
00065 
00066 static const char * eap_peap_state_txt(int state)
00067 {
00068         switch (state) {
00069         case START:
00070                 return "START";
00071         case PHASE1:
00072                 return "PHASE1";
00073         case PHASE1_ID2:
00074                 return "PHASE1_ID2";
00075         case PHASE2_START:
00076                 return "PHASE2_START";
00077         case PHASE2_ID:
00078                 return "PHASE2_ID";
00079         case PHASE2_METHOD:
00080                 return "PHASE2_METHOD";
00081         case PHASE2_SOH:
00082                 return "PHASE2_SOH";
00083         case PHASE2_TLV:
00084                 return "PHASE2_TLV";
00085         case SUCCESS_REQ:
00086                 return "SUCCESS_REQ";
00087         case FAILURE_REQ:
00088                 return "FAILURE_REQ";
00089         case SUCCESS:
00090                 return "SUCCESS";
00091         case FAILURE:
00092                 return "FAILURE";
00093         default:
00094                 return "Unknown?!";
00095         }
00096 }
00097 
00098 
00099 static void eap_peap_state(struct eap_peap_data *data, int state)
00100 {
00101         wpa_printf(MSG_DEBUG, "EAP-PEAP: %s -> %s",
00102                    eap_peap_state_txt(data->state),
00103                    eap_peap_state_txt(state));
00104         data->state = state;
00105 }
00106 
00107 
00108 static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf)
00109 {
00110         struct wpabuf *e;
00111         struct eap_tlv_hdr *tlv;
00112 
00113         if (buf == NULL)
00114                 return NULL;
00115 
00116         /* Encapsulate EAP packet in EAP-Payload TLV */
00117         wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV");
00118         e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf));
00119         if (e == NULL) {
00120                 wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory "
00121                            "for TLV encapsulation");
00122                 wpabuf_free(buf);
00123                 return NULL;
00124         }
00125         tlv = wpabuf_put(e, sizeof(*tlv));
00126         tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
00127                                      EAP_TLV_EAP_PAYLOAD_TLV);
00128         tlv->length = host_to_be16(wpabuf_len(buf));
00129         wpabuf_put_buf(e, buf);
00130         wpabuf_free(buf);
00131         return e;
00132 }
00133 
00134 
00135 static void eap_peap_req_success(struct eap_sm *sm,
00136                                  struct eap_peap_data *data)
00137 {
00138         if (data->state == FAILURE || data->state == FAILURE_REQ) {
00139                 eap_peap_state(data, FAILURE);
00140                 return;
00141         }
00142 
00143         if (data->peap_version == 0) {
00144                 data->tlv_request = TLV_REQ_SUCCESS;
00145                 eap_peap_state(data, PHASE2_TLV);
00146         } else {
00147                 eap_peap_state(data, SUCCESS_REQ);
00148         }
00149 }
00150 
00151 
00152 static void eap_peap_req_failure(struct eap_sm *sm,
00153                                  struct eap_peap_data *data)
00154 {
00155         if (data->state == FAILURE || data->state == FAILURE_REQ ||
00156             data->state == SUCCESS_REQ || data->tlv_request != TLV_REQ_NONE) {
00157                 eap_peap_state(data, FAILURE);
00158                 return;
00159         }
00160 
00161         if (data->peap_version == 0) {
00162                 data->tlv_request = TLV_REQ_FAILURE;
00163                 eap_peap_state(data, PHASE2_TLV);
00164         } else {
00165                 eap_peap_state(data, FAILURE_REQ);
00166         }
00167 }
00168 
00169 
00170 static void * eap_peap_init(struct eap_sm *sm)
00171 {
00172         struct eap_peap_data *data;
00173 
00174         data = os_zalloc(sizeof(*data));
00175         if (data == NULL)
00176                 return NULL;
00177         data->peap_version = EAP_PEAP_VERSION;
00178         data->force_version = -1;
00179         if (sm->user && sm->user->force_version >= 0) {
00180                 data->force_version = sm->user->force_version;
00181                 wpa_printf(MSG_DEBUG, "EAP-PEAP: forcing version %d",
00182                            data->force_version);
00183                 data->peap_version = data->force_version;
00184         }
00185         data->state = START;
00186         data->crypto_binding = OPTIONAL_BINDING;
00187 
00188         if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
00189                 wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
00190                 eap_peap_reset(sm, data);
00191                 return NULL;
00192         }
00193 
00194         return data;
00195 }
00196 
00197 
00198 static void eap_peap_reset(struct eap_sm *sm, void *priv)
00199 {
00200         struct eap_peap_data *data = priv;
00201         if (data == NULL)
00202                 return;
00203         if (data->phase2_priv && data->phase2_method)
00204                 data->phase2_method->reset(sm, data->phase2_priv);
00205         eap_server_tls_ssl_deinit(sm, &data->ssl);
00206         wpabuf_free(data->pending_phase2_resp);
00207         os_free(data->phase2_key);
00208         wpabuf_free(data->soh_response);
00209         os_free(data);
00210 }
00211 
00212 
00213 static struct wpabuf * eap_peap_build_start(struct eap_sm *sm,
00214                                             struct eap_peap_data *data, u8 id)
00215 {
00216         struct wpabuf *req;
00217 
00218         req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PEAP, 1,
00219                             EAP_CODE_REQUEST, id);
00220         if (req == NULL) {
00221                 wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to allocate memory for"
00222                            " request");
00223                 eap_peap_state(data, FAILURE);
00224                 return NULL;
00225         }
00226 
00227         wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->peap_version);
00228 
00229         eap_peap_state(data, PHASE1);
00230 
00231         return req;
00232 }
00233 
00234 
00235 static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm,
00236                                                  struct eap_peap_data *data,
00237                                                  u8 id)
00238 {
00239         struct wpabuf *buf, *encr_req;
00240         const u8 *req;
00241         size_t req_len;
00242 
00243         if (data->phase2_method == NULL || data->phase2_priv == NULL) {
00244                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 method not ready");
00245                 return NULL;
00246         }
00247         buf = data->phase2_method->buildReq(sm, data->phase2_priv, id);
00248         if (data->peap_version >= 2 && buf)
00249                 buf = eap_peapv2_tlv_eap_payload(buf);
00250         if (buf == NULL)
00251                 return NULL;
00252 
00253         req = wpabuf_head(buf);
00254         req_len = wpabuf_len(buf);
00255         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
00256                         req, req_len);
00257 
00258         if (data->peap_version == 0 &&
00259             data->phase2_method->method != EAP_TYPE_TLV) {
00260                 req += sizeof(struct eap_hdr);
00261                 req_len -= sizeof(struct eap_hdr);
00262         }
00263 
00264         encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len);
00265         wpabuf_free(buf);
00266 
00267         return encr_req;
00268 }
00269 
00270 
00271 #ifdef EAP_SERVER_TNC
00272 static struct wpabuf * eap_peap_build_phase2_soh(struct eap_sm *sm,
00273                                                  struct eap_peap_data *data,
00274                                                  u8 id)
00275 {
00276         struct wpabuf *buf1, *buf, *encr_req;
00277         const u8 *req;
00278         size_t req_len;
00279 
00280         buf1 = tncs_build_soh_request();
00281         if (buf1 == NULL)
00282                 return NULL;
00283 
00284         buf = eap_msg_alloc(EAP_VENDOR_MICROSOFT, 0x21, wpabuf_len(buf1),
00285                             EAP_CODE_REQUEST, id);
00286         if (buf == NULL) {
00287                 wpabuf_free(buf1);
00288                 return NULL;
00289         }
00290         wpabuf_put_buf(buf, buf1);
00291         wpabuf_free(buf1);
00292 
00293         req = wpabuf_head(buf);
00294         req_len = wpabuf_len(buf);
00295 
00296         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 SOH data",
00297                         req, req_len);
00298 
00299         req += sizeof(struct eap_hdr);
00300         req_len -= sizeof(struct eap_hdr);
00301 
00302         encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len);
00303         wpabuf_free(buf);
00304 
00305         return encr_req;
00306 }
00307 #endif /* EAP_SERVER_TNC */
00308 
00309 
00310 static void eap_peap_get_isk(struct eap_peap_data *data,
00311                              u8 *isk, size_t isk_len)
00312 {
00313         size_t key_len;
00314 
00315         os_memset(isk, 0, isk_len);
00316         if (data->phase2_key == NULL)
00317                 return;
00318 
00319         key_len = data->phase2_key_len;
00320         if (key_len > isk_len)
00321                 key_len = isk_len;
00322         os_memcpy(isk, data->phase2_key, key_len);
00323 }
00324 
00325 
00326 static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
00327 {
00328         u8 *tk;
00329         u8 isk[32], imck[60];
00330 
00331         /*
00332          * Tunnel key (TK) is the first 60 octets of the key generated by
00333          * phase 1 of PEAP (based on TLS).
00334          */
00335         tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption",
00336                                        EAP_TLS_KEY_LEN);
00337         if (tk == NULL)
00338                 return -1;
00339         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
00340 
00341         eap_peap_get_isk(data, isk, sizeof(isk));
00342         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
00343 
00344         /*
00345          * IPMK Seed = "Inner Methods Compound Keys" | ISK
00346          * TempKey = First 40 octets of TK
00347          * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60)
00348          * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space
00349          * in the end of the label just before ISK; is that just a typo?)
00350          */
00351         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
00352         peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys",
00353                      isk, sizeof(isk), imck, sizeof(imck));
00354         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
00355                         imck, sizeof(imck));
00356 
00357         os_free(tk);
00358 
00359         /* TODO: fast-connect: IPMK|CMK = TK */
00360         os_memcpy(data->ipmk, imck, 40);
00361         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
00362         os_memcpy(data->cmk, imck + 40, 20);
00363         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
00364 
00365         return 0;
00366 }
00367 
00368 
00369 static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm,
00370                                                  struct eap_peap_data *data,
00371                                                  u8 id)
00372 {
00373         struct wpabuf *buf, *encr_req;
00374         size_t mlen;
00375 
00376         mlen = 6; /* Result TLV */
00377         if (data->crypto_binding != NO_BINDING)
00378                 mlen += 60; /* Cryptobinding TLV */
00379 #ifdef EAP_SERVER_TNC
00380         if (data->soh_response)
00381                 mlen += wpabuf_len(data->soh_response);
00382 #endif /* EAP_SERVER_TNC */
00383 
00384         buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, mlen,
00385                             EAP_CODE_REQUEST, id);
00386         if (buf == NULL)
00387                 return NULL;
00388 
00389         wpabuf_put_u8(buf, 0x80); /* Mandatory */
00390         wpabuf_put_u8(buf, EAP_TLV_RESULT_TLV);
00391         /* Length */
00392         wpabuf_put_be16(buf, 2);
00393         /* Status */
00394         wpabuf_put_be16(buf, data->tlv_request == TLV_REQ_SUCCESS ?
00395                         EAP_TLV_RESULT_SUCCESS : EAP_TLV_RESULT_FAILURE);
00396 
00397         if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS &&
00398             data->crypto_binding != NO_BINDING) {
00399                 u8 *mac;
00400                 u8 eap_type = EAP_TYPE_PEAP;
00401                 const u8 *addr[2];
00402                 size_t len[2];
00403                 u16 tlv_type;
00404 
00405 #ifdef EAP_SERVER_TNC
00406                 if (data->soh_response) {
00407                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Adding MS-SOH "
00408                                    "Response TLV");
00409                         wpabuf_put_buf(buf, data->soh_response);
00410                         wpabuf_free(data->soh_response);
00411                         data->soh_response = NULL;
00412                 }
00413 #endif /* EAP_SERVER_TNC */
00414 
00415                 if (eap_peap_derive_cmk(sm, data) < 0 ||
00416                     os_get_random(data->binding_nonce, 32)) {
00417                         wpabuf_free(buf);
00418                         return NULL;
00419                 }
00420 
00421                 /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
00422                 addr[0] = wpabuf_put(buf, 0);
00423                 len[0] = 60;
00424                 addr[1] = &eap_type;
00425                 len[1] = 1;
00426 
00427                 tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
00428                 if (data->peap_version >= 2)
00429                         tlv_type |= EAP_TLV_TYPE_MANDATORY;
00430                 wpabuf_put_be16(buf, tlv_type);
00431                 wpabuf_put_be16(buf, 56);
00432 
00433                 wpabuf_put_u8(buf, 0); /* Reserved */
00434                 wpabuf_put_u8(buf, data->peap_version); /* Version */
00435                 wpabuf_put_u8(buf, data->recv_version); /* RecvVersion */
00436                 wpabuf_put_u8(buf, 0); /* SubType: 0 = Request, 1 = Response */
00437                 wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */
00438                 mac = wpabuf_put(buf, 20); /* Compound_MAC */
00439                 wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK",
00440                             data->cmk, 20);
00441                 wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
00442                             addr[0], len[0]);
00443                 wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2",
00444                             addr[1], len[1]);
00445                 hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac);
00446                 wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC",
00447                             mac, SHA1_MAC_LEN);
00448                 data->crypto_binding_sent = 1;
00449         }
00450 
00451         wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 TLV data",
00452                             buf);
00453 
00454         encr_req = eap_server_tls_encrypt(sm, &data->ssl, wpabuf_head(buf),
00455                                           wpabuf_len(buf));
00456         wpabuf_free(buf);
00457 
00458         return encr_req;
00459 }
00460 
00461 
00462 static struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm,
00463                                                   struct eap_peap_data *data,
00464                                                   u8 id, int success)
00465 {
00466         struct wpabuf *encr_req;
00467         size_t req_len;
00468         struct eap_hdr *hdr;
00469 
00470         req_len = sizeof(*hdr);
00471         hdr = os_zalloc(req_len);
00472         if (hdr == NULL)
00473                 return NULL;
00474 
00475         hdr->code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
00476         hdr->identifier = id;
00477         hdr->length = host_to_be16(req_len);
00478 
00479         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
00480                         (u8 *) hdr, req_len);
00481 
00482         encr_req = eap_server_tls_encrypt(sm, &data->ssl, (u8 *) hdr, req_len);
00483         os_free(hdr);
00484 
00485         return encr_req;
00486 }
00487 
00488 
00489 static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id)
00490 {
00491         struct eap_peap_data *data = priv;
00492 
00493         if (data->ssl.state == FRAG_ACK) {
00494                 return eap_server_tls_build_ack(id, EAP_TYPE_PEAP,
00495                                                 data->peap_version);
00496         }
00497 
00498         if (data->ssl.state == WAIT_FRAG_ACK) {
00499                 return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
00500                                                 data->peap_version, id);
00501         }
00502 
00503         switch (data->state) {
00504         case START:
00505                 return eap_peap_build_start(sm, data, id);
00506         case PHASE1:
00507         case PHASE1_ID2:
00508                 if (data->peap_version < 2 &&
00509                     tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
00510                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, "
00511                                    "starting Phase2");
00512                         eap_peap_state(data, PHASE2_START);
00513                 }
00514                 break;
00515         case PHASE2_ID:
00516         case PHASE2_METHOD:
00517                 wpabuf_free(data->ssl.out_buf);
00518                 data->ssl.out_used = 0;
00519                 data->ssl.out_buf = eap_peap_build_phase2_req(sm, data, id);
00520                 break;
00521 #ifdef EAP_SERVER_TNC
00522         case PHASE2_SOH:
00523                 wpabuf_free(data->ssl.out_buf);
00524                 data->ssl.out_used = 0;
00525                 data->ssl.out_buf = eap_peap_build_phase2_soh(sm, data, id);
00526                 break;
00527 #endif /* EAP_SERVER_TNC */
00528         case PHASE2_TLV:
00529                 wpabuf_free(data->ssl.out_buf);
00530                 data->ssl.out_used = 0;
00531                 data->ssl.out_buf = eap_peap_build_phase2_tlv(sm, data, id);
00532                 break;
00533         case SUCCESS_REQ:
00534                 wpabuf_free(data->ssl.out_buf);
00535                 data->ssl.out_used = 0;
00536                 data->ssl.out_buf = eap_peap_build_phase2_term(sm, data, id,
00537                                                                1);
00538                 break;
00539         case FAILURE_REQ:
00540                 wpabuf_free(data->ssl.out_buf);
00541                 data->ssl.out_used = 0;
00542                 data->ssl.out_buf = eap_peap_build_phase2_term(sm, data, id,
00543                                                                0);
00544                 break;
00545         default:
00546                 wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
00547                            __func__, data->state);
00548                 return NULL;
00549         }
00550 
00551         return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
00552                                         data->peap_version, id);
00553 }
00554 
00555 
00556 static Boolean eap_peap_check(struct eap_sm *sm, void *priv,
00557                               struct wpabuf *respData)
00558 {
00559         const u8 *pos;
00560         size_t len;
00561 
00562         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PEAP, respData, &len);
00563         if (pos == NULL || len < 1) {
00564                 wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame");
00565                 return TRUE;
00566         }
00567 
00568         return FALSE;
00569 }
00570 
00571 
00572 static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
00573                                 EapType eap_type)
00574 {
00575         if (data->phase2_priv && data->phase2_method) {
00576                 data->phase2_method->reset(sm, data->phase2_priv);
00577                 data->phase2_method = NULL;
00578                 data->phase2_priv = NULL;
00579         }
00580         data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
00581                                                         eap_type);
00582         if (!data->phase2_method)
00583                 return -1;
00584 
00585         sm->init_phase2 = 1;
00586         data->phase2_priv = data->phase2_method->init(sm);
00587         sm->init_phase2 = 0;
00588         return 0;
00589 }
00590 
00591 
00592 static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
00593                                           struct eap_peap_data *data,
00594                                           const u8 *crypto_tlv,
00595                                           size_t crypto_tlv_len)
00596 {
00597         u8 buf[61], mac[SHA1_MAC_LEN];
00598         const u8 *pos;
00599 
00600         if (crypto_tlv_len != 4 + 56) {
00601                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV "
00602                            "length %d", (int) crypto_tlv_len);
00603                 return -1;
00604         }
00605 
00606         pos = crypto_tlv;
00607         pos += 4; /* TLV header */
00608         if (pos[1] != data->peap_version) {
00609                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version "
00610                            "mismatch (was %d; expected %d)",
00611                            pos[1], data->peap_version);
00612                 return -1;
00613         }
00614 
00615         if (pos[3] != 1) {
00616                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV "
00617                            "SubType %d", pos[3]);
00618                 return -1;
00619         }
00620         pos += 4;
00621         pos += 32; /* Nonce */
00622 
00623         /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
00624         os_memcpy(buf, crypto_tlv, 60);
00625         os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
00626         buf[60] = EAP_TYPE_PEAP;
00627         hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
00628 
00629         if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) {
00630                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
00631                            "cryptobinding TLV");
00632                 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK", data->cmk, 20);
00633                 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding seed data",
00634                             buf, 61);
00635                 return -1;
00636         }
00637 
00638         wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
00639 
00640         return 0;
00641 }
00642 
00643 
00644 static void eap_peap_process_phase2_tlv(struct eap_sm *sm,
00645                                         struct eap_peap_data *data,
00646                                         struct wpabuf *in_data)
00647 {
00648         const u8 *pos;
00649         size_t left;
00650         const u8 *result_tlv = NULL, *crypto_tlv = NULL;
00651         size_t result_tlv_len = 0, crypto_tlv_len = 0;
00652         int tlv_type, mandatory, tlv_len;
00653 
00654         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, in_data, &left);
00655         if (pos == NULL) {
00656                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid EAP-TLV header");
00657                 return;
00658         }
00659 
00660         /* Parse TLVs */
00661         wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs", pos, left);
00662         while (left >= 4) {
00663                 mandatory = !!(pos[0] & 0x80);
00664                 tlv_type = pos[0] & 0x3f;
00665                 tlv_type = (tlv_type << 8) | pos[1];
00666                 tlv_len = ((int) pos[2] << 8) | pos[3];
00667                 pos += 4;
00668                 left -= 4;
00669                 if ((size_t) tlv_len > left) {
00670                         wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun "
00671                                    "(tlv_len=%d left=%lu)", tlv_len,
00672                                    (unsigned long) left);
00673                         eap_peap_state(data, FAILURE);
00674                         return;
00675                 }
00676                 switch (tlv_type) {
00677                 case EAP_TLV_RESULT_TLV:
00678                         result_tlv = pos;
00679                         result_tlv_len = tlv_len;
00680                         break;
00681                 case EAP_TLV_CRYPTO_BINDING_TLV:
00682                         crypto_tlv = pos;
00683                         crypto_tlv_len = tlv_len;
00684                         break;
00685                 default:
00686                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type "
00687                                    "%d%s", tlv_type,
00688                                    mandatory ? " (mandatory)" : "");
00689                         if (mandatory) {
00690                                 eap_peap_state(data, FAILURE);
00691                                 return;
00692                         }
00693                         /* Ignore this TLV, but process other TLVs */
00694                         break;
00695                 }
00696 
00697                 pos += tlv_len;
00698                 left -= tlv_len;
00699         }
00700         if (left) {
00701                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in "
00702                            "Request (left=%lu)", (unsigned long) left);
00703                 eap_peap_state(data, FAILURE);
00704                 return;
00705         }
00706 
00707         /* Process supported TLVs */
00708         if (crypto_tlv && data->crypto_binding_sent) {
00709                 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
00710                             crypto_tlv, crypto_tlv_len);
00711                 if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4,
00712                                                    crypto_tlv_len + 4) < 0) {
00713                         eap_peap_state(data, FAILURE);
00714                         return;
00715                 }
00716                 data->crypto_binding_used = 1;
00717         } else if (!crypto_tlv && data->crypto_binding_sent &&
00718                    data->crypto_binding == REQUIRE_BINDING) {
00719                 wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV");
00720                 eap_peap_state(data, FAILURE);
00721                 return;
00722         }
00723 
00724         if (result_tlv) {
00725                 int status;
00726                 const char *requested;
00727 
00728                 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Result TLV",
00729                             result_tlv, result_tlv_len);
00730                 if (result_tlv_len < 2) {
00731                         wpa_printf(MSG_INFO, "EAP-PEAP: Too short Result TLV "
00732                                    "(len=%lu)",
00733                                    (unsigned long) result_tlv_len);
00734                         eap_peap_state(data, FAILURE);
00735                         return;
00736                 }
00737                 requested = data->tlv_request == TLV_REQ_SUCCESS ? "Success" :
00738                         "Failure";
00739                 status = WPA_GET_BE16(result_tlv);
00740                 if (status == EAP_TLV_RESULT_SUCCESS) {
00741                         wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Success "
00742                                    "- requested %s", requested);
00743                         if (data->tlv_request == TLV_REQ_SUCCESS)
00744                                 eap_peap_state(data, SUCCESS);
00745                         else
00746                                 eap_peap_state(data, FAILURE);
00747                         
00748                 } else if (status == EAP_TLV_RESULT_FAILURE) {
00749                         wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Failure "
00750                                    "- requested %s", requested);
00751                         eap_peap_state(data, FAILURE);
00752                 } else {
00753                         wpa_printf(MSG_INFO, "EAP-PEAP: Unknown TLV Result "
00754                                    "Status %d", status);
00755                         eap_peap_state(data, FAILURE);
00756                 }
00757         }
00758 }
00759 
00760 
00761 #ifdef EAP_SERVER_TNC
00762 static void eap_peap_process_phase2_soh(struct eap_sm *sm,
00763                                         struct eap_peap_data *data,
00764                                         struct wpabuf *in_data)
00765 {
00766         const u8 *pos, *vpos;
00767         size_t left;
00768         const u8 *soh_tlv = NULL;
00769         size_t soh_tlv_len = 0;
00770         int tlv_type, mandatory, tlv_len, vtlv_len;
00771         u8 next_type;
00772         u32 vendor_id;
00773 
00774         pos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, in_data, &left);
00775         if (pos == NULL) {
00776                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Not a valid SoH EAP "
00777                            "Extensions Method header - skip TNC");
00778                 goto auth_method;
00779         }
00780 
00781         /* Parse TLVs */
00782         wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs (SoH)", pos, left);
00783         while (left >= 4) {
00784                 mandatory = !!(pos[0] & 0x80);
00785                 tlv_type = pos[0] & 0x3f;
00786                 tlv_type = (tlv_type << 8) | pos[1];
00787                 tlv_len = ((int) pos[2] << 8) | pos[3];
00788                 pos += 4;
00789                 left -= 4;
00790                 if ((size_t) tlv_len > left) {
00791                         wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun "
00792                                    "(tlv_len=%d left=%lu)", tlv_len,
00793                                    (unsigned long) left);
00794                         eap_peap_state(data, FAILURE);
00795                         return;
00796                 }
00797                 switch (tlv_type) {
00798                 case EAP_TLV_VENDOR_SPECIFIC_TLV:
00799                         if (tlv_len < 4) {
00800                                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Too short "
00801                                            "vendor specific TLV (len=%d)",
00802                                            (int) tlv_len);
00803                                 eap_peap_state(data, FAILURE);
00804                                 return;
00805                         }
00806 
00807                         vendor_id = WPA_GET_BE32(pos);
00808                         if (vendor_id != EAP_VENDOR_MICROSOFT) {
00809                                 if (mandatory) {
00810                                         eap_peap_state(data, FAILURE);
00811                                         return;
00812                                 }
00813                                 break;
00814                         }
00815 
00816                         vpos = pos + 4;
00817                         mandatory = !!(vpos[0] & 0x80);
00818                         tlv_type = vpos[0] & 0x3f;
00819                         tlv_type = (tlv_type << 8) | vpos[1];
00820                         vtlv_len = ((int) vpos[2] << 8) | vpos[3];
00821                         vpos += 4;
00822                         if (vpos + vtlv_len > pos + left) {
00823                                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Vendor TLV "
00824                                            "underrun");
00825                                 eap_peap_state(data, FAILURE);
00826                                 return;
00827                         }
00828 
00829                         if (tlv_type == 1) {
00830                                 soh_tlv = vpos;
00831                                 soh_tlv_len = vtlv_len;
00832                                 break;
00833                         }
00834 
00835                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported MS-TLV "
00836                                    "Type %d%s", tlv_type,
00837                                    mandatory ? " (mandatory)" : "");
00838                         if (mandatory) {
00839                                 eap_peap_state(data, FAILURE);
00840                                 return;
00841                         }
00842                         /* Ignore this TLV, but process other TLVs */
00843                         break;
00844                 default:
00845                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type "
00846                                    "%d%s", tlv_type,
00847                                    mandatory ? " (mandatory)" : "");
00848                         if (mandatory) {
00849                                 eap_peap_state(data, FAILURE);
00850                                 return;
00851                         }
00852                         /* Ignore this TLV, but process other TLVs */
00853                         break;
00854                 }
00855 
00856                 pos += tlv_len;
00857                 left -= tlv_len;
00858         }
00859         if (left) {
00860                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in "
00861                            "Request (left=%lu)", (unsigned long) left);
00862                 eap_peap_state(data, FAILURE);
00863                 return;
00864         }
00865 
00866         /* Process supported TLVs */
00867         if (soh_tlv) {
00868                 int failure = 0;
00869                 wpabuf_free(data->soh_response);
00870                 data->soh_response = tncs_process_soh(soh_tlv, soh_tlv_len,
00871                                                       &failure);
00872                 if (failure) {
00873                         eap_peap_state(data, FAILURE);
00874                         return;
00875                 }
00876         } else {
00877                 wpa_printf(MSG_DEBUG, "EAP-PEAP: No SoH TLV received");
00878                 eap_peap_state(data, FAILURE);
00879                 return;
00880         }
00881 
00882 auth_method:
00883         eap_peap_state(data, PHASE2_METHOD);
00884         next_type = sm->user->methods[0].method;
00885         sm->user_eap_method_index = 1;
00886         wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
00887         eap_peap_phase2_init(sm, data, next_type);
00888 }
00889 #endif /* EAP_SERVER_TNC */
00890 
00891 
00892 static void eap_peap_process_phase2_response(struct eap_sm *sm,
00893                                              struct eap_peap_data *data,
00894                                              struct wpabuf *in_data)
00895 {
00896         u8 next_type = EAP_TYPE_NONE;
00897         const struct eap_hdr *hdr;
00898         const u8 *pos;
00899         size_t left;
00900 
00901         if (data->state == PHASE2_TLV) {
00902                 eap_peap_process_phase2_tlv(sm, data, in_data);
00903                 return;
00904         }
00905 
00906 #ifdef EAP_SERVER_TNC
00907         if (data->state == PHASE2_SOH) {
00908                 eap_peap_process_phase2_soh(sm, data, in_data);
00909                 return;
00910         }
00911 #endif /* EAP_SERVER_TNC */
00912 
00913         if (data->phase2_priv == NULL) {
00914                 wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - Phase2 not "
00915                            "initialized?!", __func__);
00916                 return;
00917         }
00918 
00919         hdr = wpabuf_head(in_data);
00920         pos = (const u8 *) (hdr + 1);
00921 
00922         if (wpabuf_len(in_data) > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
00923                 left = wpabuf_len(in_data) - sizeof(*hdr);
00924                 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 type Nak'ed; "
00925                             "allowed types", pos + 1, left - 1);
00926                 eap_sm_process_nak(sm, pos + 1, left - 1);
00927                 if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
00928                     sm->user->methods[sm->user_eap_method_index].method !=
00929                     EAP_TYPE_NONE) {
00930                         next_type = sm->user->methods[
00931                                 sm->user_eap_method_index++].method;
00932                         wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d",
00933                                    next_type);
00934                 } else {
00935                         eap_peap_req_failure(sm, data);
00936                         next_type = EAP_TYPE_NONE;
00937                 }
00938                 eap_peap_phase2_init(sm, data, next_type);
00939                 return;
00940         }
00941 
00942         if (data->phase2_method->check(sm, data->phase2_priv, in_data)) {
00943                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 check() asked to "
00944                            "ignore the packet");
00945                 return;
00946         }
00947 
00948         data->phase2_method->process(sm, data->phase2_priv, in_data);
00949 
00950         if (sm->method_pending == METHOD_PENDING_WAIT) {
00951                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method is in "
00952                            "pending wait state - save decrypted response");
00953                 wpabuf_free(data->pending_phase2_resp);
00954                 data->pending_phase2_resp = wpabuf_dup(in_data);
00955         }
00956 
00957         if (!data->phase2_method->isDone(sm, data->phase2_priv))
00958                 return;
00959 
00960         if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) {
00961                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed");
00962                 eap_peap_req_failure(sm, data);
00963                 next_type = EAP_TYPE_NONE;
00964                 eap_peap_phase2_init(sm, data, next_type);
00965                 return;
00966         }
00967 
00968         os_free(data->phase2_key);
00969         if (data->phase2_method->getKey) {
00970                 data->phase2_key = data->phase2_method->getKey(
00971                         sm, data->phase2_priv, &data->phase2_key_len);
00972                 if (data->phase2_key == NULL) {
00973                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 getKey "
00974                                    "failed");
00975                         eap_peap_req_failure(sm, data);
00976                         eap_peap_phase2_init(sm, data, EAP_TYPE_NONE);
00977                         return;
00978                 }
00979         }
00980 
00981         switch (data->state) {
00982         case PHASE1_ID2:
00983         case PHASE2_ID:
00984         case PHASE2_SOH:
00985                 if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
00986                         wpa_hexdump_ascii(MSG_DEBUG, "EAP_PEAP: Phase2 "
00987                                           "Identity not found in the user "
00988                                           "database",
00989                                           sm->identity, sm->identity_len);
00990                         eap_peap_req_failure(sm, data);
00991                         next_type = EAP_TYPE_NONE;
00992                         break;
00993                 }
00994 
00995 #ifdef EAP_SERVER_TNC
00996                 if (data->state != PHASE2_SOH && sm->tnc &&
00997                     data->peap_version == 0) {
00998                         eap_peap_state(data, PHASE2_SOH);
00999                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize "
01000                                    "TNC (NAP SOH)");
01001                         next_type = EAP_TYPE_NONE;
01002                         break;
01003                 }
01004 #endif /* EAP_SERVER_TNC */
01005 
01006                 eap_peap_state(data, PHASE2_METHOD);
01007                 next_type = sm->user->methods[0].method;
01008                 sm->user_eap_method_index = 1;
01009                 wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
01010                 break;
01011         case PHASE2_METHOD:
01012                 eap_peap_req_success(sm, data);
01013                 next_type = EAP_TYPE_NONE;
01014                 break;
01015         case FAILURE:
01016                 break;
01017         default:
01018                 wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
01019                            __func__, data->state);
01020                 break;
01021         }
01022 
01023         eap_peap_phase2_init(sm, data, next_type);
01024 }
01025 
01026 
01027 static void eap_peap_process_phase2(struct eap_sm *sm,
01028                                     struct eap_peap_data *data,
01029                                     const struct wpabuf *respData,
01030                                     struct wpabuf *in_buf)
01031 {
01032         struct wpabuf *in_decrypted;
01033         int len_decrypted;
01034         const struct eap_hdr *hdr;
01035         size_t buf_len, len;
01036         u8 *in_data;
01037         size_t in_len;
01038 
01039         in_data = wpabuf_mhead(in_buf);
01040         in_len = wpabuf_len(in_buf);
01041 
01042         wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
01043                    " Phase 2", (unsigned long) in_len);
01044 
01045         if (data->pending_phase2_resp) {
01046                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - "
01047                            "skip decryption and use old data");
01048                 eap_peap_process_phase2_response(sm, data,
01049                                                  data->pending_phase2_resp);
01050                 wpabuf_free(data->pending_phase2_resp);
01051                 data->pending_phase2_resp = NULL;
01052                 return;
01053         }
01054 
01055         buf_len = in_len;
01056         /*
01057          * Even though we try to disable TLS compression, it is possible that
01058          * this cannot be done with all TLS libraries. Add extra buffer space
01059          * to handle the possibility of the decrypted data being longer than
01060          * input data.
01061          */
01062         buf_len += 500;
01063         buf_len *= 3;
01064         in_decrypted = wpabuf_alloc(buf_len);
01065         if (in_decrypted == NULL) {
01066                 wpa_printf(MSG_WARNING, "EAP-PEAP: failed to allocate memory "
01067                            "for decryption");
01068                 return;
01069         }
01070 
01071         len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
01072                                                in_data, in_len,
01073                                                wpabuf_mhead(in_decrypted),
01074                                                buf_len);
01075         if (len_decrypted < 0) {
01076                 wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 "
01077                            "data");
01078                 wpabuf_free(in_decrypted);
01079                 eap_peap_state(data, FAILURE);
01080                 return;
01081         }
01082         wpabuf_put(in_decrypted, len_decrypted);
01083 
01084         wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
01085                             in_decrypted);
01086 
01087         hdr = wpabuf_head(in_decrypted);
01088 
01089         if (data->peap_version == 0 && data->state != PHASE2_TLV) {
01090                 const struct eap_hdr *resp;
01091                 struct eap_hdr *nhdr;
01092                 struct wpabuf *nbuf =
01093                         wpabuf_alloc(sizeof(struct eap_hdr) +
01094                                      wpabuf_len(in_decrypted));
01095                 if (nbuf == NULL) {
01096                         wpabuf_free(in_decrypted);
01097                         return;
01098                 }
01099 
01100                 resp = wpabuf_head(respData);
01101                 nhdr = wpabuf_put(nbuf, sizeof(*nhdr));
01102                 nhdr->code = resp->code;
01103                 nhdr->identifier = resp->identifier;
01104                 nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
01105                                             wpabuf_len(in_decrypted));
01106                 wpabuf_put_buf(nbuf, in_decrypted);
01107                 wpabuf_free(in_decrypted);
01108 
01109                 in_decrypted = nbuf;
01110         } else if (data->peap_version >= 2) {
01111                 struct eap_tlv_hdr *tlv;
01112                 struct wpabuf *nmsg;
01113 
01114                 if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) {
01115                         wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 "
01116                                    "EAP TLV");
01117                         wpabuf_free(in_decrypted);
01118                         return;
01119                 }
01120                 tlv = wpabuf_mhead(in_decrypted);
01121                 if ((be_to_host16(tlv->tlv_type) & EAP_TLV_TYPE_MASK) !=
01122                     EAP_TLV_EAP_PAYLOAD_TLV) {
01123                         wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV");
01124                         wpabuf_free(in_decrypted);
01125                         return;
01126                 }
01127                 if (sizeof(*tlv) + be_to_host16(tlv->length) >
01128                     wpabuf_len(in_decrypted)) {
01129                         wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV "
01130                                    "length");
01131                         wpabuf_free(in_decrypted);
01132                         return;
01133                 }
01134                 hdr = (struct eap_hdr *) (tlv + 1);
01135                 if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) {
01136                         wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full "
01137                                    "EAP packet in EAP TLV");
01138                         wpabuf_free(in_decrypted);
01139                         return;
01140                 }
01141 
01142                 nmsg = wpabuf_alloc(be_to_host16(hdr->length));
01143                 if (nmsg == NULL) {
01144                         wpabuf_free(in_decrypted);
01145                         return;
01146                 }
01147 
01148                 wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length));
01149                 wpabuf_free(in_decrypted);
01150                 in_decrypted = nmsg;
01151         }
01152 
01153         hdr = wpabuf_head(in_decrypted);
01154         if (wpabuf_len(in_decrypted) < (int) sizeof(*hdr)) {
01155                 wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
01156                            "EAP frame (len=%lu)",
01157                            (unsigned long) wpabuf_len(in_decrypted));
01158                 wpabuf_free(in_decrypted);
01159                 eap_peap_req_failure(sm, data);
01160                 return;
01161         }
01162         len = be_to_host16(hdr->length);
01163         if (len > wpabuf_len(in_decrypted)) {
01164                 wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
01165                            "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
01166                            (unsigned long) wpabuf_len(in_decrypted),
01167                            (unsigned long) len);
01168                 wpabuf_free(in_decrypted);
01169                 eap_peap_req_failure(sm, data);
01170                 return;
01171         }
01172         wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
01173                    "identifier=%d length=%lu", hdr->code, hdr->identifier,
01174                    (unsigned long) len);
01175         switch (hdr->code) {
01176         case EAP_CODE_RESPONSE:
01177                 eap_peap_process_phase2_response(sm, data, in_decrypted);
01178                 break;
01179         case EAP_CODE_SUCCESS:
01180                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
01181                 if (data->state == SUCCESS_REQ) {
01182                         eap_peap_state(data, SUCCESS);
01183                 }
01184                 break;
01185         case EAP_CODE_FAILURE:
01186                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
01187                 eap_peap_state(data, FAILURE);
01188                 break;
01189         default:
01190                 wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
01191                            "Phase 2 EAP header", hdr->code);
01192                 break;
01193         }
01194 
01195         os_free(in_decrypted);
01196 }
01197 
01198 
01199 static int eap_peapv2_start_phase2(struct eap_sm *sm,
01200                                    struct eap_peap_data *data)
01201 {
01202         struct wpabuf *buf, *buf2;
01203         int res;
01204 
01205         wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Phase1 done, include first Phase2 "
01206                    "payload in the same message");
01207         eap_peap_state(data, PHASE1_ID2);
01208         if (eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY))
01209                 return -1;
01210 
01211         /* TODO: which Id to use here? */
01212         buf = data->phase2_method->buildReq(sm, data->phase2_priv, 6);
01213         if (buf == NULL)
01214                 return -1;
01215 
01216         buf2 = eap_peapv2_tlv_eap_payload(buf);
01217         if (buf2 == NULL)
01218                 return -1;
01219 
01220         wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Identity Request", buf2);
01221 
01222         buf = wpabuf_alloc(data->ssl.tls_out_limit);
01223         if (buf == NULL) {
01224                 wpabuf_free(buf2);
01225                 return -1;
01226         }
01227 
01228         res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
01229                                      wpabuf_head(buf2), wpabuf_len(buf2),
01230                                      wpabuf_put(buf, 0),
01231                                      data->ssl.tls_out_limit);
01232         wpabuf_free(buf2);
01233 
01234         if (res < 0) {
01235                 wpa_printf(MSG_INFO, "EAP-PEAPv2: Failed to encrypt Phase 2 "
01236                            "data");
01237                 wpabuf_free(buf);
01238                 return -1;
01239         }
01240 
01241         wpabuf_put(buf, res);
01242         wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Encrypted Identity Request",
01243                         buf);
01244 
01245         /* Append TLS data into the pending buffer after the Server Finished */
01246         if (wpabuf_resize(&data->ssl.out_buf, wpabuf_len(buf)) < 0) {
01247                 wpabuf_free(buf);
01248                 return -1;
01249         }
01250         wpabuf_put_buf(data->ssl.out_buf, buf);
01251         wpabuf_free(buf);
01252 
01253         return 0;
01254 }
01255 
01256 
01257 static int eap_peap_process_version(struct eap_sm *sm, void *priv,
01258                                     int peer_version)
01259 {
01260         struct eap_peap_data *data = priv;
01261 
01262         data->recv_version = peer_version;
01263         if (data->force_version >= 0 && peer_version != data->force_version) {
01264                 wpa_printf(MSG_INFO, "EAP-PEAP: peer did not select the forced"
01265                            " version (forced=%d peer=%d) - reject",
01266                            data->force_version, peer_version);
01267                 return -1;
01268         }
01269         if (peer_version < data->peap_version) {
01270                 wpa_printf(MSG_DEBUG, "EAP-PEAP: peer ver=%d, own ver=%d; "
01271                            "use version %d",
01272                            peer_version, data->peap_version, peer_version);
01273                 data->peap_version = peer_version;
01274         }
01275 
01276         return 0;
01277 }
01278 
01279 
01280 static void eap_peap_process_msg(struct eap_sm *sm, void *priv,
01281                                  const struct wpabuf *respData)
01282 {
01283         struct eap_peap_data *data = priv;
01284 
01285         switch (data->state) {
01286         case PHASE1:
01287                 if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
01288                         eap_peap_state(data, FAILURE);
01289                         break;
01290                 }
01291 
01292                 if (data->peap_version >= 2 &&
01293                     tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
01294                         if (eap_peapv2_start_phase2(sm, data)) {
01295                                 eap_peap_state(data, FAILURE);
01296                                 break;
01297                         }
01298                 }
01299                 break;
01300         case PHASE2_START:
01301                 eap_peap_state(data, PHASE2_ID);
01302                 eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY);
01303                 break;
01304         case PHASE1_ID2:
01305         case PHASE2_ID:
01306         case PHASE2_METHOD:
01307         case PHASE2_SOH:
01308         case PHASE2_TLV:
01309                 eap_peap_process_phase2(sm, data, respData, data->ssl.in_buf);
01310                 break;
01311         case SUCCESS_REQ:
01312                 eap_peap_state(data, SUCCESS);
01313                 break;
01314         case FAILURE_REQ:
01315                 eap_peap_state(data, FAILURE);
01316                 break;
01317         default:
01318                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected state %d in %s",
01319                            data->state, __func__);
01320                 break;
01321         }
01322 }
01323 
01324 
01325 static void eap_peap_process(struct eap_sm *sm, void *priv,
01326                              struct wpabuf *respData)
01327 {
01328         struct eap_peap_data *data = priv;
01329         if (eap_server_tls_process(sm, &data->ssl, respData, data,
01330                                    EAP_TYPE_PEAP, eap_peap_process_version,
01331                                    eap_peap_process_msg) < 0)
01332                 eap_peap_state(data, FAILURE);
01333 }
01334 
01335 
01336 static Boolean eap_peap_isDone(struct eap_sm *sm, void *priv)
01337 {
01338         struct eap_peap_data *data = priv;
01339         return data->state == SUCCESS || data->state == FAILURE;
01340 }
01341 
01342 
01343 static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
01344 {
01345         struct eap_peap_data *data = priv;
01346         u8 *eapKeyData;
01347 
01348         if (data->state != SUCCESS)
01349                 return NULL;
01350 
01351         if (data->crypto_binding_used) {
01352                 u8 csk[128];
01353                 /*
01354                  * Note: It looks like Microsoft implementation requires null
01355                  * termination for this label while the one used for deriving
01356                  * IPMK|CMK did not use null termination.
01357                  */
01358                 peap_prfplus(data->peap_version, data->ipmk, 40,
01359                              "Session Key Generating Function",
01360                              (u8 *) "\00", 1, csk, sizeof(csk));
01361                 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
01362                 eapKeyData = os_malloc(EAP_TLS_KEY_LEN);
01363                 if (eapKeyData) {
01364                         os_memcpy(eapKeyData, csk, EAP_TLS_KEY_LEN);
01365                         *len = EAP_TLS_KEY_LEN;
01366                         wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
01367                                     eapKeyData, EAP_TLS_KEY_LEN);
01368                 } else {
01369                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive "
01370                                    "key");
01371                 }
01372 
01373                 return eapKeyData;
01374         }
01375 
01376         /* TODO: PEAPv1 - different label in some cases */
01377         eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
01378                                                "client EAP encryption",
01379                                                EAP_TLS_KEY_LEN);
01380         if (eapKeyData) {
01381                 *len = EAP_TLS_KEY_LEN;
01382                 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
01383                             eapKeyData, EAP_TLS_KEY_LEN);
01384         } else {
01385                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive key");
01386         }
01387 
01388         return eapKeyData;
01389 }
01390 
01391 
01392 static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv)
01393 {
01394         struct eap_peap_data *data = priv;
01395         return data->state == SUCCESS;
01396 }
01397 
01398 
01399 int eap_server_peap_register(void)
01400 {
01401         struct eap_method *eap;
01402         int ret;
01403 
01404         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
01405                                       EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
01406         if (eap == NULL)
01407                 return -1;
01408 
01409         eap->init = eap_peap_init;
01410         eap->reset = eap_peap_reset;
01411         eap->buildReq = eap_peap_buildReq;
01412         eap->check = eap_peap_check;
01413         eap->process = eap_peap_process;
01414         eap->isDone = eap_peap_isDone;
01415         eap->getKey = eap_peap_getKey;
01416         eap->isSuccess = eap_peap_isSuccess;
01417 
01418         ret = eap_server_method_register(eap);
01419         if (ret)
01420                 eap_server_method_free(eap);
01421         return ret;
01422 }
01423 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines

Generated on Sat Nov 21 23:16:52 2009 for hostapd by  doxygen 1.6.1