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 1443382998 Lines: 180 221 81.4 %
Date: 2015-09-27 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         220 : static const char * eap_tls_state_txt(int state)
      29             : {
      30         220 :         switch (state) {
      31             :         case START:
      32          57 :                 return "START";
      33             :         case CONTINUE:
      34         110 :                 return "CONTINUE";
      35             :         case SUCCESS:
      36          45 :                 return "SUCCESS";
      37             :         case FAILURE:
      38           8 :                 return "FAILURE";
      39             :         default:
      40           0 :                 return "Unknown?!";
      41             :         }
      42             : }
      43             : 
      44             : 
      45         110 : static void eap_tls_state(struct eap_tls_data *data, int state)
      46             : {
      47         220 :         wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s",
      48         110 :                    eap_tls_state_txt(data->state),
      49             :                    eap_tls_state_txt(state));
      50         110 :         data->state = state;
      51         110 :         if (state == FAILURE)
      52           8 :                 tls_connection_remove_session(data->ssl.conn);
      53         110 : }
      54             : 
      55             : 
      56          41 : static void eap_tls_valid_session(struct eap_sm *sm, struct eap_tls_data *data)
      57             : {
      58             :         struct wpabuf *buf;
      59             : 
      60          41 :         if (!sm->tls_session_lifetime)
      61          37 :                 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          53 : static void * eap_tls_init(struct eap_sm *sm)
      72             : {
      73             :         struct eap_tls_data *data;
      74             : 
      75          53 :         data = os_zalloc(sizeof(*data));
      76          53 :         if (data == NULL)
      77           0 :                 return NULL;
      78          53 :         data->state = START;
      79             : 
      80          53 :         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          53 :         data->eap_type = EAP_TYPE_TLS;
      87             : 
      88          53 :         return data;
      89             : }
      90             : 
      91             : 
      92             : #ifdef EAP_SERVER_UNAUTH_TLS
      93           2 : static void * eap_unauth_tls_init(struct eap_sm *sm)
      94             : {
      95             :         struct eap_tls_data *data;
      96             : 
      97           2 :         data = os_zalloc(sizeof(*data));
      98           2 :         if (data == NULL)
      99           0 :                 return NULL;
     100           2 :         data->state = START;
     101             : 
     102           2 :         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           2 :         data->eap_type = EAP_UNAUTH_TLS_TYPE;
     109           2 :         return data;
     110             : }
     111             : #endif /* EAP_SERVER_UNAUTH_TLS */
     112             : 
     113             : 
     114             : #ifdef CONFIG_HS20
     115           2 : static void * eap_wfa_unauth_tls_init(struct eap_sm *sm)
     116             : {
     117             :         struct eap_tls_data *data;
     118             : 
     119           2 :         data = os_zalloc(sizeof(*data));
     120           2 :         if (data == NULL)
     121           0 :                 return NULL;
     122           2 :         data->state = START;
     123             : 
     124           2 :         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           2 :         data->eap_type = EAP_WFA_UNAUTH_TLS_TYPE;
     132           2 :         return data;
     133             : }
     134             : #endif /* CONFIG_HS20 */
     135             : 
     136             : 
     137          57 : static void eap_tls_reset(struct eap_sm *sm, void *priv)
     138             : {
     139          57 :         struct eap_tls_data *data = priv;
     140          57 :         if (data == NULL)
     141          57 :                 return;
     142          57 :         eap_server_tls_ssl_deinit(sm, &data->ssl);
     143          57 :         os_free(data);
     144             : }
     145             : 
     146             : 
     147          57 : 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          57 :         req = eap_tls_msg_alloc(data->eap_type, 1, EAP_CODE_REQUEST, id);
     153          57 :         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          57 :         wpabuf_put_u8(req, EAP_TLS_FLAGS_START);
     161             : 
     162          57 :         eap_tls_state(data, CONTINUE);
     163             : 
     164          57 :         return req;
     165             : }
     166             : 
     167             : 
     168         225 : static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
     169             : {
     170         225 :         struct eap_tls_data *data = priv;
     171             :         struct wpabuf *res;
     172             : 
     173         225 :         if (data->ssl.state == FRAG_ACK) {
     174          34 :                 return eap_server_tls_build_ack(id, data->eap_type, 0);
     175             :         }
     176             : 
     177         191 :         if (data->ssl.state == WAIT_FRAG_ACK) {
     178          40 :                 res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0,
     179             :                                                id);
     180          40 :                 goto check_established;
     181             :         }
     182             : 
     183         151 :         switch (data->state) {
     184             :         case START:
     185          57 :                 return eap_tls_build_start(sm, data, id);
     186             :         case CONTINUE:
     187          94 :                 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
     188          41 :                         data->established = 1;
     189          94 :                 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          94 :         res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0, id);
     197             : 
     198             : check_established:
     199         134 :         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          41 :                 wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
     203          41 :                 eap_tls_state(data, SUCCESS);
     204          41 :                 eap_tls_valid_session(sm, data);
     205             :         }
     206             : 
     207         134 :         return res;
     208             : }
     209             : 
     210             : 
     211         221 : static Boolean eap_tls_check(struct eap_sm *sm, void *priv,
     212             :                              struct wpabuf *respData)
     213             : {
     214         221 :         struct eap_tls_data *data = priv;
     215             :         const u8 *pos;
     216             :         size_t len;
     217             : 
     218         221 :         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         213 :         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         205 :                 pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_type,
     228             :                                        respData, &len);
     229         221 :         if (pos == NULL || len < 1) {
     230           0 :                 wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
     231           0 :                 return TRUE;
     232             :         }
     233             : 
     234         221 :         return FALSE;
     235             : }
     236             : 
     237             : 
     238         147 : static void eap_tls_process_msg(struct eap_sm *sm, void *priv,
     239             :                                 const struct wpabuf *respData)
     240             : {
     241         147 :         struct eap_tls_data *data = priv;
     242         147 :         if (data->state == SUCCESS && wpabuf_len(data->ssl.tls_in) == 0) {
     243          41 :                 wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS "
     244             :                            "handshake message");
     245         188 :                 return;
     246             :         }
     247         106 :         if (eap_server_tls_phase1(sm, &data->ssl) < 0)
     248           8 :                 eap_tls_state(data, FAILURE);
     249             : }
     250             : 
     251             : 
     252         221 : static void eap_tls_process(struct eap_sm *sm, void *priv,
     253             :                             struct wpabuf *respData)
     254             : {
     255         221 :         struct eap_tls_data *data = priv;
     256             :         const struct wpabuf *buf;
     257             :         const u8 *pos;
     258             : 
     259         221 :         if (eap_server_tls_process(sm, &data->ssl, respData, data,
     260         221 :                                    data->eap_type, NULL, eap_tls_process_msg) <
     261             :             0) {
     262           0 :                 eap_tls_state(data, FAILURE);
     263           0 :                 return;
     264             :         }
     265             : 
     266         307 :         if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
     267          86 :             !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
     268         217 :                 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         229 : static Boolean eap_tls_isDone(struct eap_sm *sm, void *priv)
     295             : {
     296         229 :         struct eap_tls_data *data = priv;
     297         229 :         return data->state == SUCCESS || data->state == FAILURE;
     298             : }
     299             : 
     300             : 
     301          53 : static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
     302             : {
     303          53 :         struct eap_tls_data *data = priv;
     304             :         u8 *eapKeyData;
     305             : 
     306          53 :         if (data->state != SUCCESS)
     307           8 :                 return NULL;
     308             : 
     309          45 :         eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
     310             :                                                "client EAP encryption",
     311             :                                                EAP_TLS_KEY_LEN);
     312          45 :         if (eapKeyData) {
     313          45 :                 *len = EAP_TLS_KEY_LEN;
     314          45 :                 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          45 :         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          61 : static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv)
     357             : {
     358          61 :         struct eap_tls_data *data = priv;
     359          61 :         return data->state == SUCCESS;
     360             : }
     361             : 
     362             : 
     363          47 : static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
     364             : {
     365          47 :         struct eap_tls_data *data = priv;
     366             : 
     367          47 :         if (data->state != SUCCESS)
     368           8 :                 return NULL;
     369             : 
     370          39 :         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             :         int ret;
     379             : 
     380          25 :         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
     381             :                                       EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
     382          25 :         if (eap == NULL)
     383           0 :                 return -1;
     384             : 
     385          25 :         eap->init = eap_tls_init;
     386          25 :         eap->reset = eap_tls_reset;
     387          25 :         eap->buildReq = eap_tls_buildReq;
     388          25 :         eap->check = eap_tls_check;
     389          25 :         eap->process = eap_tls_process;
     390          25 :         eap->isDone = eap_tls_isDone;
     391          25 :         eap->getKey = eap_tls_getKey;
     392          25 :         eap->isSuccess = eap_tls_isSuccess;
     393          25 :         eap->get_emsk = eap_tls_get_emsk;
     394          25 :         eap->getSessionId = eap_tls_get_session_id;
     395             : 
     396          25 :         ret = eap_server_method_register(eap);
     397          25 :         if (ret)
     398           0 :                 eap_server_method_free(eap);
     399          25 :         return ret;
     400             : }
     401             : 
     402             : 
     403             : #ifdef EAP_SERVER_UNAUTH_TLS
     404          25 : int eap_server_unauth_tls_register(void)
     405             : {
     406             :         struct eap_method *eap;
     407             :         int ret;
     408             : 
     409          25 :         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
     410             :                                       EAP_VENDOR_UNAUTH_TLS,
     411             :                                       EAP_VENDOR_TYPE_UNAUTH_TLS,
     412             :                                       "UNAUTH-TLS");
     413          25 :         if (eap == NULL)
     414           0 :                 return -1;
     415             : 
     416          25 :         eap->init = eap_unauth_tls_init;
     417          25 :         eap->reset = eap_tls_reset;
     418          25 :         eap->buildReq = eap_tls_buildReq;
     419          25 :         eap->check = eap_tls_check;
     420          25 :         eap->process = eap_tls_process;
     421          25 :         eap->isDone = eap_tls_isDone;
     422          25 :         eap->getKey = eap_tls_getKey;
     423          25 :         eap->isSuccess = eap_tls_isSuccess;
     424          25 :         eap->get_emsk = eap_tls_get_emsk;
     425             : 
     426          25 :         ret = eap_server_method_register(eap);
     427          25 :         if (ret)
     428           0 :                 eap_server_method_free(eap);
     429          25 :         return ret;
     430             : }
     431             : #endif /* EAP_SERVER_UNAUTH_TLS */
     432             : 
     433             : 
     434             : #ifdef CONFIG_HS20
     435          25 : int eap_server_wfa_unauth_tls_register(void)
     436             : {
     437             :         struct eap_method *eap;
     438             :         int ret;
     439             : 
     440          25 :         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
     441             :                                       EAP_VENDOR_WFA_NEW,
     442             :                                       EAP_VENDOR_WFA_UNAUTH_TLS,
     443             :                                       "WFA-UNAUTH-TLS");
     444          25 :         if (eap == NULL)
     445           0 :                 return -1;
     446             : 
     447          25 :         eap->init = eap_wfa_unauth_tls_init;
     448          25 :         eap->reset = eap_tls_reset;
     449          25 :         eap->buildReq = eap_tls_buildReq;
     450          25 :         eap->check = eap_tls_check;
     451          25 :         eap->process = eap_tls_process;
     452          25 :         eap->isDone = eap_tls_isDone;
     453          25 :         eap->getKey = eap_tls_getKey;
     454          25 :         eap->isSuccess = eap_tls_isSuccess;
     455          25 :         eap->get_emsk = eap_tls_get_emsk;
     456             : 
     457          25 :         ret = eap_server_method_register(eap);
     458          25 :         if (ret)
     459           0 :                 eap_server_method_free(eap);
     460          25 :         return ret;
     461             : }
     462             : #endif /* CONFIG_HS20 */

Generated by: LCOV version 1.10