EAP-PEAP server: Add support for session resumption
authorJouni Malinen <j@w1.fi>
Sun, 23 Aug 2015 19:06:55 +0000 (22:06 +0300)
committerJouni Malinen <j@w1.fi>
Mon, 24 Aug 2015 15:01:40 +0000 (18:01 +0300)
This allows TLS session resumption to be used to enable abbreviated
handshake and skipping of Phase 2.

Signed-off-by: Jouni Malinen <j@w1.fi>
src/eap_server/eap_server_peap.c

index ff3401b..51062b0 100644 (file)
@@ -95,6 +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 void eap_peap_valid_session(struct eap_sm *sm,
+                                  struct eap_peap_data *data)
+{
+       struct wpabuf *buf;
+
+       if (!sm->tls_session_lifetime ||
+           tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
+               return;
+
+       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);
+       }
+       tls_connection_set_success_data(data->ssl.conn, buf);
 }
 
 
@@ -708,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 "
@@ -1094,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:
@@ -1159,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);
@@ -1175,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);
 }