LCOV - code coverage report
Current view: top level - src/eap_server - eap_server_tls.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1475438200 Lines: 174 212 82.1 %
Date: 2016-10-02 Functions: 20 20 100.0 %

          Line data    Source code
       1             : /*
       2             :  * hostapd / EAP-TLS (RFC 2716)
       3             :  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
       4             :  *
       5             :  * This software may be distributed under the terms of the BSD license.
       6             :  * See README for more details.
       7             :  */
       8             : 
       9             : #include "includes.h"
      10             : 
      11             : #include "common.h"
      12             : #include "eap_i.h"
      13             : #include "eap_tls_common.h"
      14             : #include "crypto/tls.h"
      15             : 
      16             : 
      17             : static void eap_tls_reset(struct eap_sm *sm, void *priv);
      18             : 
      19             : 
      20             : struct eap_tls_data {
      21             :         struct eap_ssl_data ssl;
      22             :         enum { START, CONTINUE, SUCCESS, FAILURE } state;
      23             :         int established;
      24             :         u8 eap_type;
      25             : };
      26             : 
      27             : 
      28         346 : static const char * eap_tls_state_txt(int state)
      29             : {
      30         346 :         switch (state) {
      31             :         case START:
      32          94 :                 return "START";
      33             :         case CONTINUE:
      34         173 :                 return "CONTINUE";
      35             :         case SUCCESS:
      36          67 :                 return "SUCCESS";
      37             :         case FAILURE:
      38          12 :                 return "FAILURE";
      39             :         default:
      40           0 :                 return "Unknown?!";
      41             :         }
      42             : }
      43             : 
      44             : 
      45         173 : static void eap_tls_state(struct eap_tls_data *data, int state)
      46             : {
      47         346 :         wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s",
      48         173 :                    eap_tls_state_txt(data->state),
      49             :                    eap_tls_state_txt(state));
      50         173 :         data->state = state;
      51         173 :         if (state == FAILURE)
      52          12 :                 tls_connection_remove_session(data->ssl.conn);
      53         173 : }
      54             : 
      55             : 
      56          63 : static void eap_tls_valid_session(struct eap_sm *sm, struct eap_tls_data *data)
      57             : {
      58             :         struct wpabuf *buf;
      59             : 
      60          63 :         if (!sm->tls_session_lifetime)
      61          59 :                 return;
      62             : 
      63           4 :         buf = wpabuf_alloc(1);
      64           4 :         if (!buf)
      65           0 :                 return;
      66           4 :         wpabuf_put_u8(buf, data->eap_type);
      67           4 :         tls_connection_set_success_data(data->ssl.conn, buf);
      68             : }
      69             : 
      70             : 
      71          86 : static void * eap_tls_init(struct eap_sm *sm)
      72             : {
      73             :         struct eap_tls_data *data;
      74             : 
      75          86 :         data = os_zalloc(sizeof(*data));
      76          86 :         if (data == NULL)
      77           0 :                 return NULL;
      78          86 :         data->state = START;
      79             : 
      80          86 :         if (eap_server_tls_ssl_init(sm, &data->ssl, 1, EAP_TYPE_TLS)) {
      81           0 :                 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
      82           0 :                 eap_tls_reset(sm, data);
      83           0 :                 return NULL;
      84             :         }
      85             : 
      86          86 :         data->eap_type = EAP_TYPE_TLS;
      87             : 
      88          86 :         return data;
      89             : }
      90             : 
      91             : 
      92             : #ifdef EAP_SERVER_UNAUTH_TLS
      93           4 : static void * eap_unauth_tls_init(struct eap_sm *sm)
      94             : {
      95             :         struct eap_tls_data *data;
      96             : 
      97           4 :         data = os_zalloc(sizeof(*data));
      98           4 :         if (data == NULL)
      99           0 :                 return NULL;
     100           4 :         data->state = START;
     101             : 
     102           4 :         if (eap_server_tls_ssl_init(sm, &data->ssl, 0, EAP_UNAUTH_TLS_TYPE)) {
     103           0 :                 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
     104           0 :                 eap_tls_reset(sm, data);
     105           0 :                 return NULL;
     106             :         }
     107             : 
     108           4 :         data->eap_type = EAP_UNAUTH_TLS_TYPE;
     109           4 :         return data;
     110             : }
     111             : #endif /* EAP_SERVER_UNAUTH_TLS */
     112             : 
     113             : 
     114             : #ifdef CONFIG_HS20
     115           4 : static void * eap_wfa_unauth_tls_init(struct eap_sm *sm)
     116             : {
     117             :         struct eap_tls_data *data;
     118             : 
     119           4 :         data = os_zalloc(sizeof(*data));
     120           4 :         if (data == NULL)
     121           0 :                 return NULL;
     122           4 :         data->state = START;
     123             : 
     124           4 :         if (eap_server_tls_ssl_init(sm, &data->ssl, 0,
     125             :                                     EAP_WFA_UNAUTH_TLS_TYPE)) {
     126           0 :                 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
     127           0 :                 eap_tls_reset(sm, data);
     128           0 :                 return NULL;
     129             :         }
     130             : 
     131           4 :         data->eap_type = EAP_WFA_UNAUTH_TLS_TYPE;
     132           4 :         return data;
     133             : }
     134             : #endif /* CONFIG_HS20 */
     135             : 
     136             : 
     137          94 : static void eap_tls_reset(struct eap_sm *sm, void *priv)
     138             : {
     139          94 :         struct eap_tls_data *data = priv;
     140          94 :         if (data == NULL)
     141          94 :                 return;
     142          94 :         eap_server_tls_ssl_deinit(sm, &data->ssl);
     143          94 :         os_free(data);
     144             : }
     145             : 
     146             : 
     147          94 : static struct wpabuf * eap_tls_build_start(struct eap_sm *sm,
     148             :                                            struct eap_tls_data *data, u8 id)
     149             : {
     150             :         struct wpabuf *req;
     151             : 
     152          94 :         req = eap_tls_msg_alloc(data->eap_type, 1, EAP_CODE_REQUEST, id);
     153          94 :         if (req == NULL) {
     154           0 :                 wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for "
     155             :                            "request");
     156           0 :                 eap_tls_state(data, FAILURE);
     157           0 :                 return NULL;
     158             :         }
     159             : 
     160          94 :         wpabuf_put_u8(req, EAP_TLS_FLAGS_START);
     161             : 
     162          94 :         eap_tls_state(data, CONTINUE);
     163             : 
     164          94 :         return req;
     165             : }
     166             : 
     167             : 
     168         462 : static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
     169             : {
     170         462 :         struct eap_tls_data *data = priv;
     171             :         struct wpabuf *res;
     172             : 
     173         462 :         if (data->ssl.state == FRAG_ACK) {
     174          58 :                 return eap_server_tls_build_ack(id, data->eap_type, 0);
     175             :         }
     176             : 
     177         404 :         if (data->ssl.state == WAIT_FRAG_ACK) {
     178         166 :                 res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0,
     179             :                                                id);
     180         166 :                 goto check_established;
     181             :         }
     182             : 
     183         238 :         switch (data->state) {
     184             :         case START:
     185          94 :                 return eap_tls_build_start(sm, data, id);
     186             :         case CONTINUE:
     187         144 :                 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
     188          63 :                         data->established = 1;
     189         144 :                 break;
     190             :         default:
     191           0 :                 wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d",
     192           0 :                            __func__, data->state);
     193           0 :                 return NULL;
     194             :         }
     195             : 
     196         144 :         res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0, id);
     197             : 
     198             : check_established:
     199         310 :         if (data->established && data->ssl.state != WAIT_FRAG_ACK) {
     200             :                 /* TLS handshake has been completed and there are no more
     201             :                  * fragments waiting to be sent out. */
     202          63 :                 wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
     203          63 :                 eap_tls_state(data, SUCCESS);
     204          63 :                 eap_tls_valid_session(sm, data);
     205             :         }
     206             : 
     207         310 :         return res;
     208             : }
     209             : 
     210             : 
     211         447 : static Boolean eap_tls_check(struct eap_sm *sm, void *priv,
     212             :                              struct wpabuf *respData)
     213             : {
     214         447 :         struct eap_tls_data *data = priv;
     215             :         const u8 *pos;
     216             :         size_t len;
     217             : 
     218         447 :         if (data->eap_type == EAP_UNAUTH_TLS_TYPE)
     219           8 :                 pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
     220             :                                        EAP_VENDOR_TYPE_UNAUTH_TLS, respData,
     221             :                                        &len);
     222         439 :         else if (data->eap_type == EAP_WFA_UNAUTH_TLS_TYPE)
     223           8 :                 pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW,
     224             :                                        EAP_VENDOR_WFA_UNAUTH_TLS, respData,
     225             :                                        &len);
     226             :         else
     227         431 :                 pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_type,
     228             :                                        respData, &len);
     229         447 :         if (pos == NULL || len < 1) {
     230           0 :                 wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
     231           0 :                 return TRUE;
     232             :         }
     233             : 
     234         447 :         return FALSE;
     235             : }
     236             : 
     237             : 
     238         223 : static void eap_tls_process_msg(struct eap_sm *sm, void *priv,
     239             :                                 const struct wpabuf *respData)
     240             : {
     241         223 :         struct eap_tls_data *data = priv;
     242         223 :         if (data->state == SUCCESS && wpabuf_len(data->ssl.tls_in) == 0) {
     243          63 :                 wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS "
     244             :                            "handshake message");
     245         286 :                 return;
     246             :         }
     247         160 :         if (eap_server_tls_phase1(sm, &data->ssl) < 0)
     248          12 :                 eap_tls_state(data, FAILURE);
     249             : }
     250             : 
     251             : 
     252         447 : static void eap_tls_process(struct eap_sm *sm, void *priv,
     253             :                             struct wpabuf *respData)
     254             : {
     255         447 :         struct eap_tls_data *data = priv;
     256             :         const struct wpabuf *buf;
     257             :         const u8 *pos;
     258             : 
     259         447 :         if (eap_server_tls_process(sm, &data->ssl, respData, data,
     260         447 :                                    data->eap_type, NULL, eap_tls_process_msg) <
     261             :             0) {
     262           0 :                 eap_tls_state(data, FAILURE);
     263           0 :                 return;
     264             :         }
     265             : 
     266         577 :         if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
     267         130 :             !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
     268         443 :                 return;
     269             : 
     270           4 :         buf = tls_connection_get_success_data(data->ssl.conn);
     271           4 :         if (!buf || wpabuf_len(buf) < 1) {
     272           0 :                 wpa_printf(MSG_DEBUG,
     273             :                            "EAP-TLS: No success data in resumed session - reject attempt");
     274           0 :                 eap_tls_state(data, FAILURE);
     275           0 :                 return;
     276             :         }
     277             : 
     278           4 :         pos = wpabuf_head(buf);
     279           4 :         if (*pos != data->eap_type) {
     280           0 :                 wpa_printf(MSG_DEBUG,
     281             :                            "EAP-TLS: Resumed session for another EAP type (%u) - reject attempt",
     282           0 :                            *pos);
     283           0 :                 eap_tls_state(data, FAILURE);
     284           0 :                 return;
     285             :         }
     286             : 
     287           4 :         wpa_printf(MSG_DEBUG,
     288             :                    "EAP-TLS: Resuming previous session");
     289           4 :         eap_tls_state(data, SUCCESS);
     290           4 :         tls_connection_set_success_data_resumed(data->ssl.conn);
     291             : }
     292             : 
     293             : 
     294         459 : static Boolean eap_tls_isDone(struct eap_sm *sm, void *priv)
     295             : {
     296         459 :         struct eap_tls_data *data = priv;
     297         459 :         return data->state == SUCCESS || data->state == FAILURE;
     298             : }
     299             : 
     300             : 
     301          79 : static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
     302             : {
     303          79 :         struct eap_tls_data *data = priv;
     304             :         u8 *eapKeyData;
     305             : 
     306          79 :         if (data->state != SUCCESS)
     307          12 :                 return NULL;
     308             : 
     309          67 :         eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
     310             :                                                "client EAP encryption",
     311             :                                                EAP_TLS_KEY_LEN);
     312          67 :         if (eapKeyData) {
     313          67 :                 *len = EAP_TLS_KEY_LEN;
     314          67 :                 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key",
     315             :                             eapKeyData, EAP_TLS_KEY_LEN);
     316             :         } else {
     317           0 :                 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key");
     318             :         }
     319             : 
     320          67 :         return eapKeyData;
     321             : }
     322             : 
     323             : 
     324           1 : static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
     325             : {
     326           1 :         struct eap_tls_data *data = priv;
     327             :         u8 *eapKeyData, *emsk;
     328             : 
     329           1 :         if (data->state != SUCCESS)
     330           0 :                 return NULL;
     331             : 
     332           1 :         eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
     333             :                                                "client EAP encryption",
     334             :                                                EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
     335           1 :         if (eapKeyData) {
     336           1 :                 emsk = os_malloc(EAP_EMSK_LEN);
     337           1 :                 if (emsk)
     338           1 :                         os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
     339             :                                   EAP_EMSK_LEN);
     340           1 :                 bin_clear_free(eapKeyData, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
     341             :         } else
     342           0 :                 emsk = NULL;
     343             : 
     344           1 :         if (emsk) {
     345           1 :                 *len = EAP_EMSK_LEN;
     346           1 :                 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK",
     347             :                             emsk, EAP_EMSK_LEN);
     348             :         } else {
     349           0 :                 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK");
     350             :         }
     351             : 
     352           1 :         return emsk;
     353             : }
     354             : 
     355             : 
     356          91 : static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv)
     357             : {
     358          91 :         struct eap_tls_data *data = priv;
     359          91 :         return data->state == SUCCESS;
     360             : }
     361             : 
     362             : 
     363          72 : static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
     364             : {
     365          72 :         struct eap_tls_data *data = priv;
     366             : 
     367          72 :         if (data->state != SUCCESS)
     368          12 :                 return NULL;
     369             : 
     370          60 :         return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_TLS,
     371             :                                                 len);
     372             : }
     373             : 
     374             : 
     375          25 : int eap_server_tls_register(void)
     376             : {
     377             :         struct eap_method *eap;
     378             : 
     379          25 :         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
     380             :                                       EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
     381          25 :         if (eap == NULL)
     382           0 :                 return -1;
     383             : 
     384          25 :         eap->init = eap_tls_init;
     385          25 :         eap->reset = eap_tls_reset;
     386          25 :         eap->buildReq = eap_tls_buildReq;
     387          25 :         eap->check = eap_tls_check;
     388          25 :         eap->process = eap_tls_process;
     389          25 :         eap->isDone = eap_tls_isDone;
     390          25 :         eap->getKey = eap_tls_getKey;
     391          25 :         eap->isSuccess = eap_tls_isSuccess;
     392          25 :         eap->get_emsk = eap_tls_get_emsk;
     393          25 :         eap->getSessionId = eap_tls_get_session_id;
     394             : 
     395          25 :         return eap_server_method_register(eap);
     396             : }
     397             : 
     398             : 
     399             : #ifdef EAP_SERVER_UNAUTH_TLS
     400          25 : int eap_server_unauth_tls_register(void)
     401             : {
     402             :         struct eap_method *eap;
     403             : 
     404          25 :         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
     405             :                                       EAP_VENDOR_UNAUTH_TLS,
     406             :                                       EAP_VENDOR_TYPE_UNAUTH_TLS,
     407             :                                       "UNAUTH-TLS");
     408          25 :         if (eap == NULL)
     409           0 :                 return -1;
     410             : 
     411          25 :         eap->init = eap_unauth_tls_init;
     412          25 :         eap->reset = eap_tls_reset;
     413          25 :         eap->buildReq = eap_tls_buildReq;
     414          25 :         eap->check = eap_tls_check;
     415          25 :         eap->process = eap_tls_process;
     416          25 :         eap->isDone = eap_tls_isDone;
     417          25 :         eap->getKey = eap_tls_getKey;
     418          25 :         eap->isSuccess = eap_tls_isSuccess;
     419          25 :         eap->get_emsk = eap_tls_get_emsk;
     420             : 
     421          25 :         return eap_server_method_register(eap);
     422             : }
     423             : #endif /* EAP_SERVER_UNAUTH_TLS */
     424             : 
     425             : 
     426             : #ifdef CONFIG_HS20
     427          25 : int eap_server_wfa_unauth_tls_register(void)
     428             : {
     429             :         struct eap_method *eap;
     430             : 
     431          25 :         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
     432             :                                       EAP_VENDOR_WFA_NEW,
     433             :                                       EAP_VENDOR_WFA_UNAUTH_TLS,
     434             :                                       "WFA-UNAUTH-TLS");
     435          25 :         if (eap == NULL)
     436           0 :                 return -1;
     437             : 
     438          25 :         eap->init = eap_wfa_unauth_tls_init;
     439          25 :         eap->reset = eap_tls_reset;
     440          25 :         eap->buildReq = eap_tls_buildReq;
     441          25 :         eap->check = eap_tls_check;
     442          25 :         eap->process = eap_tls_process;
     443          25 :         eap->isDone = eap_tls_isDone;
     444          25 :         eap->getKey = eap_tls_getKey;
     445          25 :         eap->isSuccess = eap_tls_isSuccess;
     446          25 :         eap->get_emsk = eap_tls_get_emsk;
     447             : 
     448          25 :         return eap_server_method_register(eap);
     449             : }
     450             : #endif /* CONFIG_HS20 */

Generated by: LCOV version 1.10