Updated through tag hostap_2_5 from git://w1.fi/hostap.git
[mech_eap.git] / libeap / src / eap_server / eap_server_peap.c
index 674ecd2..51062b0 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -17,6 +11,7 @@
 #include "common.h"
 #include "crypto/sha1.h"
 #include "crypto/tls.h"
+#include "crypto/random.h"
 #include "eap_i.h"
 #include "eap_tls_common.h"
 #include "eap_common/eap_tlv_common.h"
@@ -27,7 +22,6 @@
 /* Maximum supported PEAP version
  * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
  * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
- * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt
  */
 #define EAP_PEAP_VERSION 1
 
@@ -101,33 +95,37 @@ static void eap_peap_state(struct eap_peap_data *data, int state)
                   eap_peap_state_txt(data->state),
                   eap_peap_state_txt(state));
        data->state = state;
+       if (state == FAILURE || state == FAILURE_REQ)
+               tls_connection_remove_session(data->ssl.conn);
 }
 
 
-static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf)
+static void eap_peap_valid_session(struct eap_sm *sm,
+                                  struct eap_peap_data *data)
 {
-       struct wpabuf *e;
-       struct eap_tlv_hdr *tlv;
+       struct wpabuf *buf;
 
-       if (buf == NULL)
-               return NULL;
+       if (!sm->tls_session_lifetime ||
+           tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
+               return;
 
-       /* Encapsulate EAP packet in EAP-Payload TLV */
-       wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV");
-       e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf));
-       if (e == NULL) {
-               wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory "
-                          "for TLV encapsulation");
-               wpabuf_free(buf);
-               return NULL;
+       buf = wpabuf_alloc(1 + 1 + sm->identity_len);
+       if (!buf)
+               return;
+       wpabuf_put_u8(buf, EAP_TYPE_PEAP);
+       if (sm->identity) {
+               u8 id_len;
+
+               if (sm->identity_len <= 255)
+                       id_len = sm->identity_len;
+               else
+                       id_len = 255;
+               wpabuf_put_u8(buf, id_len);
+               wpabuf_put_data(buf, sm->identity, id_len);
+       } else {
+               wpabuf_put_u8(buf, 0);
        }
-       tlv = wpabuf_put(e, sizeof(*tlv));
-       tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
-                                    EAP_TLV_EAP_PAYLOAD_TLV);
-       tlv->length = host_to_be16(wpabuf_len(buf));
-       wpabuf_put_buf(e, buf);
-       wpabuf_free(buf);
-       return e;
+       tls_connection_set_success_data(data->ssl.conn, buf);
 }
 
 
@@ -184,7 +182,7 @@ static void * eap_peap_init(struct eap_sm *sm)
        data->state = START;
        data->crypto_binding = OPTIONAL_BINDING;
 
-       if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
+       if (eap_server_tls_ssl_init(sm, &data->ssl, 0, EAP_TYPE_PEAP)) {
                wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
                eap_peap_reset(sm, data);
                return NULL;
@@ -205,7 +203,7 @@ static void eap_peap_reset(struct eap_sm *sm, void *priv)
        wpabuf_free(data->pending_phase2_resp);
        os_free(data->phase2_key);
        wpabuf_free(data->soh_response);
-       os_free(data);
+       bin_clear_free(data, sizeof(*data));
 }
 
 
@@ -244,8 +242,6 @@ static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm,
                return NULL;
        }
        buf = data->phase2_method->buildReq(sm, data->phase2_priv, id);
-       if (data->peap_version >= 2 && buf)
-               buf = eap_peapv2_tlv_eap_payload(buf);
        if (buf == NULL)
                return NULL;
 
@@ -350,8 +346,12 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
         * in the end of the label just before ISK; is that just a typo?)
         */
        wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
-       peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys",
-                    isk, sizeof(isk), imck, sizeof(imck));
+       if (peap_prfplus(data->peap_version, tk, 40,
+                        "Inner Methods Compound Keys",
+                        isk, sizeof(isk), imck, sizeof(imck)) < 0) {
+               os_free(tk);
+               return -1;
+       }
        wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
                        imck, sizeof(imck));
 
@@ -375,12 +375,14 @@ static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm,
        size_t mlen;
 
        mlen = 6; /* Result TLV */
-       if (data->crypto_binding != NO_BINDING)
+       if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS &&
+           data->crypto_binding != NO_BINDING) {
                mlen += 60; /* Cryptobinding TLV */
 #ifdef EAP_SERVER_TNC
-       if (data->soh_response)
-               mlen += wpabuf_len(data->soh_response);
+               if (data->soh_response)
+                       mlen += wpabuf_len(data->soh_response);
 #endif /* EAP_SERVER_TNC */
+       }
 
        buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, mlen,
                            EAP_CODE_REQUEST, id);
@@ -414,7 +416,7 @@ static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm,
 #endif /* EAP_SERVER_TNC */
 
                if (eap_peap_derive_cmk(sm, data) < 0 ||
-                   os_get_random(data->binding_nonce, 32)) {
+                   random_get_bytes(data->binding_nonce, 32)) {
                        wpabuf_free(buf);
                        return NULL;
                }
@@ -426,8 +428,6 @@ static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm,
                len[1] = 1;
 
                tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
-               if (data->peap_version >= 2)
-                       tlv_type |= EAP_TLV_TYPE_MANDATORY;
                wpabuf_put_be16(buf, tlv_type);
                wpabuf_put_be16(buf, 56);
 
@@ -506,8 +506,7 @@ static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id)
                return eap_peap_build_start(sm, data, id);
        case PHASE1:
        case PHASE1_ID2:
-               if (data->peap_version < 2 &&
-                   tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+               if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
                        wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, "
                                   "starting Phase2");
                        eap_peap_state(data, PHASE2_START);
@@ -571,15 +570,14 @@ static Boolean eap_peap_check(struct eap_sm *sm, void *priv,
 
 
 static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
-                               EapType eap_type)
+                               int vendor, EapType eap_type)
 {
        if (data->phase2_priv && data->phase2_method) {
                data->phase2_method->reset(sm, data->phase2_priv);
                data->phase2_method = NULL;
                data->phase2_priv = NULL;
        }
-       data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
-                                                       eap_type);
+       data->phase2_method = eap_server_get_eap_method(vendor, eap_type);
        if (!data->phase2_method)
                return -1;
 
@@ -627,7 +625,7 @@ static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
        buf[60] = EAP_TYPE_PEAP;
        hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
 
-       if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) {
+       if (os_memcmp_const(mac, pos, SHA1_MAC_LEN) != 0) {
                wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
                           "cryptobinding TLV");
                wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK", data->cmk, 20);
@@ -741,10 +739,12 @@ static void eap_peap_process_phase2_tlv(struct eap_sm *sm,
                if (status == EAP_TLV_RESULT_SUCCESS) {
                        wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Success "
                                   "- requested %s", requested);
-                       if (data->tlv_request == TLV_REQ_SUCCESS)
+                       if (data->tlv_request == TLV_REQ_SUCCESS) {
                                eap_peap_state(data, SUCCESS);
-                       else
+                               eap_peap_valid_session(sm, data);
+                       } else {
                                eap_peap_state(data, FAILURE);
+                       }
                        
                } else if (status == EAP_TLV_RESULT_FAILURE) {
                        wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Failure "
@@ -769,7 +769,7 @@ static void eap_peap_process_phase2_soh(struct eap_sm *sm,
        const u8 *soh_tlv = NULL;
        size_t soh_tlv_len = 0;
        int tlv_type, mandatory, tlv_len, vtlv_len;
-       u8 next_type;
+       u32 next_type;
        u32 vendor_id;
 
        pos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, in_data, &left);
@@ -884,8 +884,9 @@ auth_method:
        eap_peap_state(data, PHASE2_METHOD);
        next_type = sm->user->methods[0].method;
        sm->user_eap_method_index = 1;
-       wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
-       eap_peap_phase2_init(sm, data, next_type);
+       wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP vendor %d type %d",
+                  sm->user->methods[0].vendor, next_type);
+       eap_peap_phase2_init(sm, data, sm->user->methods[0].vendor, next_type);
 }
 #endif /* EAP_SERVER_TNC */
 
@@ -894,7 +895,8 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm,
                                             struct eap_peap_data *data,
                                             struct wpabuf *in_data)
 {
-       u8 next_type = EAP_TYPE_NONE;
+       int next_vendor = EAP_VENDOR_IETF;
+       u32 next_type = EAP_TYPE_NONE;
        const struct eap_hdr *hdr;
        const u8 *pos;
        size_t left;
@@ -926,17 +928,23 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm,
                            "allowed types", pos + 1, left - 1);
                eap_sm_process_nak(sm, pos + 1, left - 1);
                if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
-                   sm->user->methods[sm->user_eap_method_index].method !=
-                   EAP_TYPE_NONE) {
+                   (sm->user->methods[sm->user_eap_method_index].vendor !=
+                    EAP_VENDOR_IETF ||
+                    sm->user->methods[sm->user_eap_method_index].method !=
+                    EAP_TYPE_NONE)) {
+                       next_vendor = sm->user->methods[
+                               sm->user_eap_method_index].vendor;
                        next_type = sm->user->methods[
                                sm->user_eap_method_index++].method;
-                       wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d",
-                                  next_type);
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-PEAP: try EAP vendor %d type 0x%x",
+                                  next_vendor, next_type);
                } else {
                        eap_peap_req_failure(sm, data);
+                       next_vendor = EAP_VENDOR_IETF;
                        next_type = EAP_TYPE_NONE;
                }
-               eap_peap_phase2_init(sm, data, next_type);
+               eap_peap_phase2_init(sm, data, next_vendor, next_type);
                return;
        }
 
@@ -961,8 +969,9 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm,
        if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) {
                wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed");
                eap_peap_req_failure(sm, data);
+               next_vendor = EAP_VENDOR_IETF;
                next_type = EAP_TYPE_NONE;
-               eap_peap_phase2_init(sm, data, next_type);
+               eap_peap_phase2_init(sm, data, next_vendor, next_type);
                return;
        }
 
@@ -974,7 +983,8 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm,
                        wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 getKey "
                                   "failed");
                        eap_peap_req_failure(sm, data);
-                       eap_peap_phase2_init(sm, data, EAP_TYPE_NONE);
+                       eap_peap_phase2_init(sm, data, EAP_VENDOR_IETF,
+                                            EAP_TYPE_NONE);
                        return;
                }
        }
@@ -989,6 +999,7 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm,
                                          "database",
                                          sm->identity, sm->identity_len);
                        eap_peap_req_failure(sm, data);
+                       next_vendor = EAP_VENDOR_IETF;
                        next_type = EAP_TYPE_NONE;
                        break;
                }
@@ -999,18 +1010,22 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm,
                        eap_peap_state(data, PHASE2_SOH);
                        wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize "
                                   "TNC (NAP SOH)");
+                       next_vendor = EAP_VENDOR_IETF;
                        next_type = EAP_TYPE_NONE;
                        break;
                }
 #endif /* EAP_SERVER_TNC */
 
                eap_peap_state(data, PHASE2_METHOD);
+               next_vendor = sm->user->methods[0].vendor;
                next_type = sm->user->methods[0].method;
                sm->user_eap_method_index = 1;
-               wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
+               wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP vendor %d type 0x%x",
+                          next_vendor, next_type);
                break;
        case PHASE2_METHOD:
                eap_peap_req_success(sm, data);
+               next_vendor = EAP_VENDOR_IETF;
                next_type = EAP_TYPE_NONE;
                break;
        case FAILURE:
@@ -1021,7 +1036,7 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm,
                break;
        }
 
-       eap_peap_phase2_init(sm, data, next_type);
+       eap_peap_phase2_init(sm, data, next_vendor, next_type);
 }
 
 
@@ -1059,8 +1074,6 @@ static void eap_peap_process_phase2(struct eap_sm *sm,
        wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
                            in_decrypted);
 
-       hdr = wpabuf_head(in_decrypted);
-
        if (data->peap_version == 0 && data->state != PHASE2_TLV) {
                const struct eap_hdr *resp;
                struct eap_hdr *nhdr;
@@ -1082,47 +1095,6 @@ static void eap_peap_process_phase2(struct eap_sm *sm,
                wpabuf_free(in_decrypted);
 
                in_decrypted = nbuf;
-       } else if (data->peap_version >= 2) {
-               struct eap_tlv_hdr *tlv;
-               struct wpabuf *nmsg;
-
-               if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) {
-                       wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 "
-                                  "EAP TLV");
-                       wpabuf_free(in_decrypted);
-                       return;
-               }
-               tlv = wpabuf_mhead(in_decrypted);
-               if ((be_to_host16(tlv->tlv_type) & EAP_TLV_TYPE_MASK) !=
-                   EAP_TLV_EAP_PAYLOAD_TLV) {
-                       wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV");
-                       wpabuf_free(in_decrypted);
-                       return;
-               }
-               if (sizeof(*tlv) + be_to_host16(tlv->length) >
-                   wpabuf_len(in_decrypted)) {
-                       wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV "
-                                  "length");
-                       wpabuf_free(in_decrypted);
-                       return;
-               }
-               hdr = (struct eap_hdr *) (tlv + 1);
-               if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) {
-                       wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full "
-                                  "EAP packet in EAP TLV");
-                       wpabuf_free(in_decrypted);
-                       return;
-               }
-
-               nmsg = wpabuf_alloc(be_to_host16(hdr->length));
-               if (nmsg == NULL) {
-                       wpabuf_free(in_decrypted);
-                       return;
-               }
-
-               wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length));
-               wpabuf_free(in_decrypted);
-               in_decrypted = nmsg;
        }
 
        hdr = wpabuf_head(in_decrypted);
@@ -1155,6 +1127,7 @@ static void eap_peap_process_phase2(struct eap_sm *sm,
                wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
                if (data->state == SUCCESS_REQ) {
                        eap_peap_state(data, SUCCESS);
+                       eap_peap_valid_session(sm, data);
                }
                break;
        case EAP_CODE_FAILURE:
@@ -1171,53 +1144,6 @@ static void eap_peap_process_phase2(struct eap_sm *sm,
 }
 
 
-static int eap_peapv2_start_phase2(struct eap_sm *sm,
-                                  struct eap_peap_data *data)
-{
-       struct wpabuf *buf, *buf2;
-
-       wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Phase1 done, include first Phase2 "
-                  "payload in the same message");
-       eap_peap_state(data, PHASE1_ID2);
-       if (eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY))
-               return -1;
-
-       /* TODO: which Id to use here? */
-       buf = data->phase2_method->buildReq(sm, data->phase2_priv, 6);
-       if (buf == NULL)
-               return -1;
-
-       buf2 = eap_peapv2_tlv_eap_payload(buf);
-       if (buf2 == NULL)
-               return -1;
-
-       wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Identity Request", buf2);
-
-       buf = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
-                                    buf2);
-       wpabuf_free(buf2);
-
-       if (buf == NULL) {
-               wpa_printf(MSG_INFO, "EAP-PEAPv2: Failed to encrypt Phase 2 "
-                          "data");
-               return -1;
-       }
-
-       wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Encrypted Identity Request",
-                       buf);
-
-       /* Append TLS data into the pending buffer after the Server Finished */
-       if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(buf)) < 0) {
-               wpabuf_free(buf);
-               return -1;
-       }
-       wpabuf_put_buf(data->ssl.tls_out, buf);
-       wpabuf_free(buf);
-
-       return 0;
-}
-
-
 static int eap_peap_process_version(struct eap_sm *sm, void *priv,
                                    int peer_version)
 {
@@ -1252,18 +1178,11 @@ static void eap_peap_process_msg(struct eap_sm *sm, void *priv,
                        eap_peap_state(data, FAILURE);
                        break;
                }
-
-               if (data->peap_version >= 2 &&
-                   tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
-                       if (eap_peapv2_start_phase2(sm, data)) {
-                               eap_peap_state(data, FAILURE);
-                               break;
-                       }
-               }
                break;
        case PHASE2_START:
                eap_peap_state(data, PHASE2_ID);
-               eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY);
+               eap_peap_phase2_init(sm, data, EAP_VENDOR_IETF,
+                                    EAP_TYPE_IDENTITY);
                break;
        case PHASE1_ID2:
        case PHASE2_ID:
@@ -1274,6 +1193,7 @@ static void eap_peap_process_msg(struct eap_sm *sm, void *priv,
                break;
        case SUCCESS_REQ:
                eap_peap_state(data, SUCCESS);
+               eap_peap_valid_session(sm, data);
                break;
        case FAILURE_REQ:
                eap_peap_state(data, FAILURE);
@@ -1290,10 +1210,65 @@ static void eap_peap_process(struct eap_sm *sm, void *priv,
                             struct wpabuf *respData)
 {
        struct eap_peap_data *data = priv;
+       const struct wpabuf *buf;
+       const u8 *pos;
+       u8 id_len;
+
        if (eap_server_tls_process(sm, &data->ssl, respData, data,
                                   EAP_TYPE_PEAP, eap_peap_process_version,
-                                  eap_peap_process_msg) < 0)
+                                  eap_peap_process_msg) < 0) {
                eap_peap_state(data, FAILURE);
+               return;
+       }
+
+       if (data->state == SUCCESS ||
+           !tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
+           !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
+               return;
+
+       buf = tls_connection_get_success_data(data->ssl.conn);
+       if (!buf || wpabuf_len(buf) < 2) {
+               wpa_printf(MSG_DEBUG,
+                          "EAP-PEAP: No success data in resumed session - reject attempt");
+               eap_peap_state(data, FAILURE);
+               return;
+       }
+
+       pos = wpabuf_head(buf);
+       if (*pos != EAP_TYPE_PEAP) {
+               wpa_printf(MSG_DEBUG,
+                          "EAP-PEAP: Resumed session for another EAP type (%u) - reject attempt",
+                          *pos);
+               eap_peap_state(data, FAILURE);
+               return;
+       }
+
+       pos++;
+       id_len = *pos++;
+       wpa_hexdump_ascii(MSG_DEBUG, "EAP-PEAP: Identity from cached session",
+                         pos, id_len);
+       os_free(sm->identity);
+       sm->identity = os_malloc(id_len ? id_len : 1);
+       if (!sm->identity) {
+               sm->identity_len = 0;
+               eap_peap_state(data, FAILURE);
+               return;
+       }
+
+       os_memcpy(sm->identity, pos, id_len);
+       sm->identity_len = id_len;
+
+       if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
+               wpa_hexdump_ascii(MSG_DEBUG, "EAP-PEAP: Phase2 Identity not found in the user database",
+                                 sm->identity, sm->identity_len);
+               eap_peap_state(data, FAILURE);
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG,
+                  "EAP-PEAP: Resuming previous session - skip Phase2");
+       eap_peap_state(data, SUCCESS_REQ);
+       tls_connection_set_success_data_resumed(data->ssl.conn);
 }
 
 
@@ -1319,9 +1294,10 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
                 * termination for this label while the one used for deriving
                 * IPMK|CMK did not use null termination.
                 */
-               peap_prfplus(data->peap_version, data->ipmk, 40,
-                            "Session Key Generating Function",
-                            (u8 *) "\00", 1, csk, sizeof(csk));
+               if (peap_prfplus(data->peap_version, data->ipmk, 40,
+                                "Session Key Generating Function",
+                                (u8 *) "\00", 1, csk, sizeof(csk)) < 0)
+                       return NULL;
                wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
                eapKeyData = os_malloc(EAP_TLS_KEY_LEN);
                if (eapKeyData) {
@@ -1360,6 +1336,18 @@ static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv)
 }
 
 
+static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_peap_data *data = priv;
+
+       if (data->state != SUCCESS)
+               return NULL;
+
+       return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_PEAP,
+                                               len);
+}
+
+
 int eap_server_peap_register(void)
 {
        struct eap_method *eap;
@@ -1378,6 +1366,7 @@ int eap_server_peap_register(void)
        eap->isDone = eap_peap_isDone;
        eap->getKey = eap_peap_getKey;
        eap->isSuccess = eap_peap_isSuccess;
+       eap->getSessionId = eap_peap_get_session_id;
 
        ret = eap_server_method_register(eap);
        if (ret)