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 1401264779 Lines: 142 187 75.9 %
Date: 2014-05-28 Functions: 17 18 94.4 %

          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          76 : static const char * eap_tls_state_txt(int state)
      29             : {
      30          76 :         switch (state) {
      31             :         case START:
      32          19 :                 return "START";
      33             :         case CONTINUE:
      34          38 :                 return "CONTINUE";
      35             :         case SUCCESS:
      36          16 :                 return "SUCCESS";
      37             :         case FAILURE:
      38           3 :                 return "FAILURE";
      39             :         default:
      40           0 :                 return "Unknown?!";
      41             :         }
      42             : }
      43             : 
      44             : 
      45          38 : static void eap_tls_state(struct eap_tls_data *data, int state)
      46             : {
      47          76 :         wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s",
      48          38 :                    eap_tls_state_txt(data->state),
      49             :                    eap_tls_state_txt(state));
      50          38 :         data->state = state;
      51          38 : }
      52             : 
      53             : 
      54          15 : static void * eap_tls_init(struct eap_sm *sm)
      55             : {
      56             :         struct eap_tls_data *data;
      57             : 
      58          15 :         data = os_zalloc(sizeof(*data));
      59          15 :         if (data == NULL)
      60           0 :                 return NULL;
      61          15 :         data->state = START;
      62             : 
      63          15 :         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          15 :         data->eap_type = EAP_TYPE_TLS;
      70             : 
      71          15 :         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          19 : static void eap_tls_reset(struct eap_sm *sm, void *priv)
     120             : {
     121          19 :         struct eap_tls_data *data = priv;
     122          19 :         if (data == NULL)
     123          19 :                 return;
     124          19 :         eap_server_tls_ssl_deinit(sm, &data->ssl);
     125          19 :         os_free(data);
     126             : }
     127             : 
     128             : 
     129          19 : 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          19 :         req = eap_tls_msg_alloc(data->eap_type, 1, EAP_CODE_REQUEST, id);
     135          19 :         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          19 :         wpabuf_put_u8(req, EAP_TLS_FLAGS_START);
     143             : 
     144          19 :         eap_tls_state(data, CONTINUE);
     145             : 
     146          19 :         return req;
     147             : }
     148             : 
     149             : 
     150          81 : static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
     151             : {
     152          81 :         struct eap_tls_data *data = priv;
     153             :         struct wpabuf *res;
     154             : 
     155          81 :         if (data->ssl.state == FRAG_ACK) {
     156          12 :                 return eap_server_tls_build_ack(id, data->eap_type, 0);
     157             :         }
     158             : 
     159          69 :         if (data->ssl.state == WAIT_FRAG_ACK) {
     160          15 :                 res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0,
     161             :                                                id);
     162          15 :                 goto check_established;
     163             :         }
     164             : 
     165          54 :         switch (data->state) {
     166             :         case START:
     167          19 :                 return eap_tls_build_start(sm, data, id);
     168             :         case CONTINUE:
     169          35 :                 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
     170          16 :                         data->established = 1;
     171          35 :                 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          35 :         res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0, id);
     179             : 
     180             : check_established:
     181          50 :         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          16 :                 wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
     185          16 :                 eap_tls_state(data, SUCCESS);
     186             :         }
     187             : 
     188          50 :         return res;
     189             : }
     190             : 
     191             : 
     192          81 : static Boolean eap_tls_check(struct eap_sm *sm, void *priv,
     193             :                              struct wpabuf *respData)
     194             : {
     195          81 :         struct eap_tls_data *data = priv;
     196             :         const u8 *pos;
     197             :         size_t len;
     198             : 
     199          81 :         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          73 :         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          65 :                 pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_type,
     209             :                                        respData, &len);
     210          81 :         if (pos == NULL || len < 1) {
     211           0 :                 wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
     212           0 :                 return TRUE;
     213             :         }
     214             : 
     215          81 :         return FALSE;
     216             : }
     217             : 
     218             : 
     219          54 : static void eap_tls_process_msg(struct eap_sm *sm, void *priv,
     220             :                                 const struct wpabuf *respData)
     221             : {
     222          54 :         struct eap_tls_data *data = priv;
     223          54 :         if (data->state == SUCCESS && wpabuf_len(data->ssl.tls_in) == 0) {
     224          16 :                 wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS "
     225             :                            "handshake message");
     226          70 :                 return;
     227             :         }
     228          38 :         if (eap_server_tls_phase1(sm, &data->ssl) < 0)
     229           3 :                 eap_tls_state(data, FAILURE);
     230             : }
     231             : 
     232             : 
     233          81 : static void eap_tls_process(struct eap_sm *sm, void *priv,
     234             :                             struct wpabuf *respData)
     235             : {
     236          81 :         struct eap_tls_data *data = priv;
     237          81 :         if (eap_server_tls_process(sm, &data->ssl, respData, data,
     238          81 :                                    data->eap_type, NULL, eap_tls_process_msg) <
     239             :             0)
     240           0 :                 eap_tls_state(data, FAILURE);
     241          81 : }
     242             : 
     243             : 
     244          84 : static Boolean eap_tls_isDone(struct eap_sm *sm, void *priv)
     245             : {
     246          84 :         struct eap_tls_data *data = priv;
     247          84 :         return data->state == SUCCESS || data->state == FAILURE;
     248             : }
     249             : 
     250             : 
     251          19 : static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
     252             : {
     253          19 :         struct eap_tls_data *data = priv;
     254             :         u8 *eapKeyData;
     255             : 
     256          19 :         if (data->state != SUCCESS)
     257           3 :                 return NULL;
     258             : 
     259          16 :         eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
     260             :                                                "client EAP encryption",
     261             :                                                EAP_TLS_KEY_LEN);
     262          16 :         if (eapKeyData) {
     263          16 :                 *len = EAP_TLS_KEY_LEN;
     264          16 :                 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          16 :         return eapKeyData;
     271             : }
     272             : 
     273             : 
     274           0 : static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
     275             : {
     276           0 :         struct eap_tls_data *data = priv;
     277             :         u8 *eapKeyData, *emsk;
     278             : 
     279           0 :         if (data->state != SUCCESS)
     280           0 :                 return NULL;
     281             : 
     282           0 :         eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
     283             :                                                "client EAP encryption",
     284             :                                                EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
     285           0 :         if (eapKeyData) {
     286           0 :                 emsk = os_malloc(EAP_EMSK_LEN);
     287           0 :                 if (emsk)
     288           0 :                         os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
     289             :                                   EAP_EMSK_LEN);
     290           0 :                 os_free(eapKeyData);
     291             :         } else
     292           0 :                 emsk = NULL;
     293             : 
     294           0 :         if (emsk) {
     295           0 :                 *len = EAP_EMSK_LEN;
     296           0 :                 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           0 :         return emsk;
     303             : }
     304             : 
     305             : 
     306          22 : static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv)
     307             : {
     308          22 :         struct eap_tls_data *data = priv;
     309          22 :         return data->state == SUCCESS;
     310             : }
     311             : 
     312             : 
     313           2 : int eap_server_tls_register(void)
     314             : {
     315             :         struct eap_method *eap;
     316             :         int ret;
     317             : 
     318           2 :         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
     319             :                                       EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
     320           2 :         if (eap == NULL)
     321           0 :                 return -1;
     322             : 
     323           2 :         eap->init = eap_tls_init;
     324           2 :         eap->reset = eap_tls_reset;
     325           2 :         eap->buildReq = eap_tls_buildReq;
     326           2 :         eap->check = eap_tls_check;
     327           2 :         eap->process = eap_tls_process;
     328           2 :         eap->isDone = eap_tls_isDone;
     329           2 :         eap->getKey = eap_tls_getKey;
     330           2 :         eap->isSuccess = eap_tls_isSuccess;
     331           2 :         eap->get_emsk = eap_tls_get_emsk;
     332             : 
     333           2 :         ret = eap_server_method_register(eap);
     334           2 :         if (ret)
     335           0 :                 eap_server_method_free(eap);
     336           2 :         return ret;
     337             : }
     338             : 
     339             : 
     340             : #ifdef EAP_SERVER_UNAUTH_TLS
     341           2 : int eap_server_unauth_tls_register(void)
     342             : {
     343             :         struct eap_method *eap;
     344             :         int ret;
     345             : 
     346           2 :         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
     347             :                                       EAP_VENDOR_UNAUTH_TLS,
     348             :                                       EAP_VENDOR_TYPE_UNAUTH_TLS,
     349             :                                       "UNAUTH-TLS");
     350           2 :         if (eap == NULL)
     351           0 :                 return -1;
     352             : 
     353           2 :         eap->init = eap_unauth_tls_init;
     354           2 :         eap->reset = eap_tls_reset;
     355           2 :         eap->buildReq = eap_tls_buildReq;
     356           2 :         eap->check = eap_tls_check;
     357           2 :         eap->process = eap_tls_process;
     358           2 :         eap->isDone = eap_tls_isDone;
     359           2 :         eap->getKey = eap_tls_getKey;
     360           2 :         eap->isSuccess = eap_tls_isSuccess;
     361           2 :         eap->get_emsk = eap_tls_get_emsk;
     362             : 
     363           2 :         ret = eap_server_method_register(eap);
     364           2 :         if (ret)
     365           0 :                 eap_server_method_free(eap);
     366           2 :         return ret;
     367             : }
     368             : #endif /* EAP_SERVER_UNAUTH_TLS */
     369             : 
     370             : 
     371             : #ifdef CONFIG_HS20
     372           2 : int eap_server_wfa_unauth_tls_register(void)
     373             : {
     374             :         struct eap_method *eap;
     375             :         int ret;
     376             : 
     377           2 :         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
     378             :                                       EAP_VENDOR_WFA_NEW,
     379             :                                       EAP_VENDOR_WFA_UNAUTH_TLS,
     380             :                                       "WFA-UNAUTH-TLS");
     381           2 :         if (eap == NULL)
     382           0 :                 return -1;
     383             : 
     384           2 :         eap->init = eap_wfa_unauth_tls_init;
     385           2 :         eap->reset = eap_tls_reset;
     386           2 :         eap->buildReq = eap_tls_buildReq;
     387           2 :         eap->check = eap_tls_check;
     388           2 :         eap->process = eap_tls_process;
     389           2 :         eap->isDone = eap_tls_isDone;
     390           2 :         eap->getKey = eap_tls_getKey;
     391           2 :         eap->isSuccess = eap_tls_isSuccess;
     392           2 :         eap->get_emsk = eap_tls_get_emsk;
     393             : 
     394           2 :         ret = eap_server_method_register(eap);
     395           2 :         if (ret)
     396           0 :                 eap_server_method_free(eap);
     397           2 :         return ret;
     398             : }
     399             : #endif /* CONFIG_HS20 */

Generated by: LCOV version 1.10