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

Generated by: LCOV version 1.10