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


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Apr 24 2014 15:34:34