LCOV - code coverage report
Current view: top level - src/eap_peer - eap_tls.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1475438200 Lines: 218 230 94.8 %
Date: 2016-10-02 Functions: 19 19 100.0 %

          Line data    Source code
       1             : /*
       2             :  * EAP peer method: EAP-TLS (RFC 2716)
       3             :  * Copyright (c) 2004-2008, 2012-2015, 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 "crypto/tls.h"
      13             : #include "eap_i.h"
      14             : #include "eap_tls_common.h"
      15             : #include "eap_config.h"
      16             : 
      17             : 
      18             : static void eap_tls_deinit(struct eap_sm *sm, void *priv);
      19             : 
      20             : 
      21             : struct eap_tls_data {
      22             :         struct eap_ssl_data ssl;
      23             :         u8 *key_data;
      24             :         u8 *session_id;
      25             :         size_t id_len;
      26             :         void *ssl_ctx;
      27             :         u8 eap_type;
      28             :         struct wpabuf *pending_resp;
      29             : };
      30             : 
      31             : 
      32          82 : static void * eap_tls_init(struct eap_sm *sm)
      33             : {
      34             :         struct eap_tls_data *data;
      35          82 :         struct eap_peer_config *config = eap_get_config(sm);
      36         166 :         if (config == NULL ||
      37         164 :             ((sm->init_phase2 ? config->private_key2 : config->private_key)
      38          80 :              == NULL &&
      39           0 :              (sm->init_phase2 ? config->engine2 : config->engine) == 0)) {
      40           0 :                 wpa_printf(MSG_INFO, "EAP-TLS: Private key not configured");
      41           0 :                 return NULL;
      42             :         }
      43             : 
      44          82 :         data = os_zalloc(sizeof(*data));
      45          82 :         if (data == NULL)
      46           1 :                 return NULL;
      47             : 
      48          81 :         data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
      49             :                 sm->ssl_ctx;
      50             : 
      51          81 :         if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TLS)) {
      52           7 :                 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
      53           7 :                 eap_tls_deinit(sm, data);
      54           7 :                 if (config->engine) {
      55           1 :                         wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting Smartcard "
      56             :                                    "PIN");
      57           1 :                         eap_sm_request_pin(sm);
      58           1 :                         sm->ignore = TRUE;
      59           6 :                 } else if (config->private_key && !config->private_key_passwd)
      60             :                 {
      61           6 :                         wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting private "
      62             :                                    "key passphrase");
      63           6 :                         eap_sm_request_passphrase(sm);
      64           6 :                         sm->ignore = TRUE;
      65             :                 }
      66           7 :                 return NULL;
      67             :         }
      68             : 
      69          74 :         data->eap_type = EAP_TYPE_TLS;
      70             : 
      71          74 :         return data;
      72             : }
      73             : 
      74             : 
      75             : #ifdef EAP_UNAUTH_TLS
      76           3 : static void * eap_unauth_tls_init(struct eap_sm *sm)
      77             : {
      78             :         struct eap_tls_data *data;
      79           3 :         struct eap_peer_config *config = eap_get_config(sm);
      80             : 
      81           3 :         data = os_zalloc(sizeof(*data));
      82           3 :         if (data == NULL)
      83           1 :                 return NULL;
      84             : 
      85           2 :         data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
      86             :                 sm->ssl_ctx;
      87             : 
      88           2 :         if (eap_peer_tls_ssl_init(sm, &data->ssl, config,
      89             :                                   EAP_UNAUTH_TLS_TYPE)) {
      90           1 :                 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
      91           1 :                 eap_tls_deinit(sm, data);
      92           1 :                 return NULL;
      93             :         }
      94             : 
      95           1 :         data->eap_type = EAP_UNAUTH_TLS_TYPE;
      96             : 
      97           1 :         return data;
      98             : }
      99             : #endif /* EAP_UNAUTH_TLS */
     100             : 
     101             : 
     102             : #ifdef CONFIG_HS20
     103           4 : static void * eap_wfa_unauth_tls_init(struct eap_sm *sm)
     104             : {
     105             :         struct eap_tls_data *data;
     106           4 :         struct eap_peer_config *config = eap_get_config(sm);
     107             : 
     108           4 :         data = os_zalloc(sizeof(*data));
     109           4 :         if (data == NULL)
     110           1 :                 return NULL;
     111             : 
     112           3 :         data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
     113             :                 sm->ssl_ctx;
     114             : 
     115           3 :         if (eap_peer_tls_ssl_init(sm, &data->ssl, config,
     116             :                                   EAP_WFA_UNAUTH_TLS_TYPE)) {
     117           1 :                 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
     118           1 :                 eap_tls_deinit(sm, data);
     119           1 :                 return NULL;
     120             :         }
     121             : 
     122           2 :         data->eap_type = EAP_WFA_UNAUTH_TLS_TYPE;
     123             : 
     124           2 :         return data;
     125             : }
     126             : #endif /* CONFIG_HS20 */
     127             : 
     128             : 
     129         164 : static void eap_tls_free_key(struct eap_tls_data *data)
     130             : {
     131         164 :         if (data->key_data) {
     132          66 :                 bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
     133          66 :                 data->key_data = NULL;
     134             :         }
     135         164 : }
     136             : 
     137             : 
     138          86 : static void eap_tls_deinit(struct eap_sm *sm, void *priv)
     139             : {
     140          86 :         struct eap_tls_data *data = priv;
     141          86 :         if (data == NULL)
     142          86 :                 return;
     143          86 :         eap_peer_tls_ssl_deinit(sm, &data->ssl);
     144          86 :         eap_tls_free_key(data);
     145          86 :         os_free(data->session_id);
     146          86 :         wpabuf_free(data->pending_resp);
     147          86 :         os_free(data);
     148             : }
     149             : 
     150             : 
     151          16 : static struct wpabuf * eap_tls_failure(struct eap_sm *sm,
     152             :                                        struct eap_tls_data *data,
     153             :                                        struct eap_method_ret *ret, int res,
     154             :                                        struct wpabuf *resp, u8 id)
     155             : {
     156          16 :         wpa_printf(MSG_DEBUG, "EAP-TLS: TLS processing failed");
     157             : 
     158          16 :         ret->methodState = METHOD_DONE;
     159          16 :         ret->decision = DECISION_FAIL;
     160             : 
     161          16 :         if (resp) {
     162             :                 /*
     163             :                  * This is likely an alert message, so send it instead of just
     164             :                  * ACKing the error.
     165             :                  */
     166          11 :                 return resp;
     167             :         }
     168             : 
     169           5 :         return eap_peer_tls_build_ack(id, data->eap_type, 0);
     170             : }
     171             : 
     172             : 
     173          67 : static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data,
     174             :                             struct eap_method_ret *ret)
     175             : {
     176          67 :         wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
     177             : 
     178          67 :         ret->methodState = METHOD_DONE;
     179          67 :         ret->decision = DECISION_UNCOND_SUCC;
     180             : 
     181          67 :         eap_tls_free_key(data);
     182          67 :         data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
     183             :                                                  "client EAP encryption",
     184             :                                                  EAP_TLS_KEY_LEN +
     185             :                                                  EAP_EMSK_LEN);
     186          67 :         if (data->key_data) {
     187          66 :                 wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived key",
     188          66 :                                 data->key_data, EAP_TLS_KEY_LEN);
     189          66 :                 wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived EMSK",
     190          66 :                                 data->key_data + EAP_TLS_KEY_LEN,
     191             :                                 EAP_EMSK_LEN);
     192             :         } else {
     193           1 :                 wpa_printf(MSG_INFO, "EAP-TLS: Failed to derive key");
     194             :         }
     195             : 
     196          67 :         os_free(data->session_id);
     197          67 :         data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl,
     198             :                                                           EAP_TYPE_TLS,
     199             :                                                           &data->id_len);
     200          67 :         if (data->session_id) {
     201         132 :                 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived Session-Id",
     202          66 :                             data->session_id, data->id_len);
     203             :         } else {
     204           1 :                 wpa_printf(MSG_ERROR, "EAP-TLS: Failed to derive Session-Id");
     205             :         }
     206          67 : }
     207             : 
     208             : 
     209         508 : static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
     210             :                                        struct eap_method_ret *ret,
     211             :                                        const struct wpabuf *reqData)
     212             : {
     213             :         size_t left;
     214             :         int res;
     215             :         struct wpabuf *resp;
     216             :         u8 flags, id;
     217             :         const u8 *pos;
     218         508 :         struct eap_tls_data *data = priv;
     219             :         struct wpabuf msg;
     220             : 
     221         508 :         if (sm->waiting_ext_cert_check && data->pending_resp) {
     222           2 :                 struct eap_peer_config *config = eap_get_config(sm);
     223             : 
     224           2 :                 if (config->pending_ext_cert_check == EXT_CERT_CHECK_GOOD) {
     225           1 :                         wpa_printf(MSG_DEBUG,
     226             :                                    "EAP-TLS: External certificate check succeeded - continue handshake");
     227           1 :                         resp = data->pending_resp;
     228           1 :                         data->pending_resp = NULL;
     229           1 :                         sm->waiting_ext_cert_check = 0;
     230           1 :                         return resp;
     231             :                 }
     232             : 
     233           1 :                 if (config->pending_ext_cert_check == EXT_CERT_CHECK_BAD) {
     234           1 :                         wpa_printf(MSG_DEBUG,
     235             :                                    "EAP-TLS: External certificate check failed - force authentication failure");
     236           1 :                         ret->methodState = METHOD_DONE;
     237           1 :                         ret->decision = DECISION_FAIL;
     238           1 :                         sm->waiting_ext_cert_check = 0;
     239           1 :                         return NULL;
     240             :                 }
     241             : 
     242           0 :                 wpa_printf(MSG_DEBUG,
     243             :                            "EAP-TLS: Continuing to wait external server certificate validation");
     244           0 :                 return NULL;
     245             :         }
     246             : 
     247         506 :         pos = eap_peer_tls_process_init(sm, &data->ssl, data->eap_type, ret,
     248             :                                         reqData, &left, &flags);
     249         506 :         if (pos == NULL)
     250           3 :                 return NULL;
     251         503 :         id = eap_get_id(reqData);
     252             : 
     253         503 :         if (flags & EAP_TLS_FLAGS_START) {
     254          86 :                 wpa_printf(MSG_DEBUG, "EAP-TLS: Start");
     255          86 :                 left = 0; /* make sure that this frame is empty, even though it
     256             :                            * should always be, anyway */
     257             :         }
     258             : 
     259         503 :         resp = NULL;
     260         503 :         wpabuf_set(&msg, pos, left);
     261         503 :         res = eap_peer_tls_process_helper(sm, &data->ssl, data->eap_type, 0,
     262             :                                           id, &msg, &resp);
     263             : 
     264         503 :         if (res < 0) {
     265          16 :                 return eap_tls_failure(sm, data, ret, res, resp, id);
     266             :         }
     267             : 
     268         487 :         if (sm->waiting_ext_cert_check) {
     269           2 :                 wpa_printf(MSG_DEBUG,
     270             :                            "EAP-TLS: Waiting external server certificate validation");
     271           2 :                 wpabuf_free(data->pending_resp);
     272           2 :                 data->pending_resp = resp;
     273           2 :                 return NULL;
     274             :         }
     275             : 
     276         485 :         if (tls_connection_established(data->ssl_ctx, data->ssl.conn))
     277          67 :                 eap_tls_success(sm, data, ret);
     278             : 
     279         485 :         if (res == 1) {
     280         275 :                 wpabuf_free(resp);
     281         275 :                 return eap_peer_tls_build_ack(id, data->eap_type, 0);
     282             :         }
     283             : 
     284         210 :         return resp;
     285             : }
     286             : 
     287             : 
     288          25 : static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv)
     289             : {
     290          25 :         struct eap_tls_data *data = priv;
     291          25 :         return tls_connection_established(data->ssl_ctx, data->ssl.conn);
     292             : }
     293             : 
     294             : 
     295          15 : static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv)
     296             : {
     297          15 :         struct eap_tls_data *data = priv;
     298             : 
     299          15 :         wpabuf_free(data->pending_resp);
     300          15 :         data->pending_resp = NULL;
     301          15 : }
     302             : 
     303             : 
     304          11 : static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv)
     305             : {
     306          11 :         struct eap_tls_data *data = priv;
     307          11 :         eap_tls_free_key(data);
     308          11 :         os_free(data->session_id);
     309          11 :         data->session_id = NULL;
     310          11 :         if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
     311           0 :                 os_free(data);
     312           0 :                 return NULL;
     313             :         }
     314          11 :         return priv;
     315             : }
     316             : 
     317             : 
     318          44 : static int eap_tls_get_status(struct eap_sm *sm, void *priv, char *buf,
     319             :                               size_t buflen, int verbose)
     320             : {
     321          44 :         struct eap_tls_data *data = priv;
     322          44 :         return eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
     323             : }
     324             : 
     325             : 
     326         490 : static Boolean eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv)
     327             : {
     328         490 :         struct eap_tls_data *data = priv;
     329         490 :         return data->key_data != NULL;
     330             : }
     331             : 
     332             : 
     333          63 : static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
     334             : {
     335          63 :         struct eap_tls_data *data = priv;
     336             :         u8 *key;
     337             : 
     338          63 :         if (data->key_data == NULL)
     339           0 :                 return NULL;
     340             : 
     341          63 :         key = os_malloc(EAP_TLS_KEY_LEN);
     342          63 :         if (key == NULL)
     343           1 :                 return NULL;
     344             : 
     345          62 :         *len = EAP_TLS_KEY_LEN;
     346          62 :         os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
     347             : 
     348          62 :         return key;
     349             : }
     350             : 
     351             : 
     352           3 : static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
     353             : {
     354           3 :         struct eap_tls_data *data = priv;
     355             :         u8 *key;
     356             : 
     357           3 :         if (data->key_data == NULL)
     358           0 :                 return NULL;
     359             : 
     360           3 :         key = os_malloc(EAP_EMSK_LEN);
     361           3 :         if (key == NULL)
     362           1 :                 return NULL;
     363             : 
     364           2 :         *len = EAP_EMSK_LEN;
     365           2 :         os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
     366             : 
     367           2 :         return key;
     368             : }
     369             : 
     370             : 
     371          59 : static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
     372             : {
     373          59 :         struct eap_tls_data *data = priv;
     374             :         u8 *id;
     375             : 
     376          59 :         if (data->session_id == NULL)
     377           1 :                 return NULL;
     378             : 
     379          58 :         id = os_malloc(data->id_len);
     380          58 :         if (id == NULL)
     381           1 :                 return NULL;
     382             : 
     383          57 :         *len = data->id_len;
     384          57 :         os_memcpy(id, data->session_id, data->id_len);
     385             : 
     386          57 :         return id;
     387             : }
     388             : 
     389             : 
     390          49 : int eap_peer_tls_register(void)
     391             : {
     392             :         struct eap_method *eap;
     393             : 
     394          49 :         eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
     395             :                                     EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
     396          49 :         if (eap == NULL)
     397           0 :                 return -1;
     398             : 
     399          49 :         eap->init = eap_tls_init;
     400          49 :         eap->deinit = eap_tls_deinit;
     401          49 :         eap->process = eap_tls_process;
     402          49 :         eap->isKeyAvailable = eap_tls_isKeyAvailable;
     403          49 :         eap->getKey = eap_tls_getKey;
     404          49 :         eap->getSessionId = eap_tls_get_session_id;
     405          49 :         eap->get_status = eap_tls_get_status;
     406          49 :         eap->has_reauth_data = eap_tls_has_reauth_data;
     407          49 :         eap->deinit_for_reauth = eap_tls_deinit_for_reauth;
     408          49 :         eap->init_for_reauth = eap_tls_init_for_reauth;
     409          49 :         eap->get_emsk = eap_tls_get_emsk;
     410             : 
     411          49 :         return eap_peer_method_register(eap);
     412             : }
     413             : 
     414             : 
     415             : #ifdef EAP_UNAUTH_TLS
     416          49 : int eap_peer_unauth_tls_register(void)
     417             : {
     418             :         struct eap_method *eap;
     419             : 
     420          49 :         eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
     421             :                                     EAP_VENDOR_UNAUTH_TLS,
     422             :                                     EAP_VENDOR_TYPE_UNAUTH_TLS, "UNAUTH-TLS");
     423          49 :         if (eap == NULL)
     424           0 :                 return -1;
     425             : 
     426          49 :         eap->init = eap_unauth_tls_init;
     427          49 :         eap->deinit = eap_tls_deinit;
     428          49 :         eap->process = eap_tls_process;
     429          49 :         eap->isKeyAvailable = eap_tls_isKeyAvailable;
     430          49 :         eap->getKey = eap_tls_getKey;
     431          49 :         eap->get_status = eap_tls_get_status;
     432          49 :         eap->has_reauth_data = eap_tls_has_reauth_data;
     433          49 :         eap->deinit_for_reauth = eap_tls_deinit_for_reauth;
     434          49 :         eap->init_for_reauth = eap_tls_init_for_reauth;
     435          49 :         eap->get_emsk = eap_tls_get_emsk;
     436             : 
     437          49 :         return eap_peer_method_register(eap);
     438             : }
     439             : #endif /* EAP_UNAUTH_TLS */
     440             : 
     441             : 
     442             : #ifdef CONFIG_HS20
     443          49 : int eap_peer_wfa_unauth_tls_register(void)
     444             : {
     445             :         struct eap_method *eap;
     446             : 
     447          49 :         eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
     448             :                                     EAP_VENDOR_WFA_NEW,
     449             :                                     EAP_VENDOR_WFA_UNAUTH_TLS,
     450             :                                     "WFA-UNAUTH-TLS");
     451          49 :         if (eap == NULL)
     452           0 :                 return -1;
     453             : 
     454          49 :         eap->init = eap_wfa_unauth_tls_init;
     455          49 :         eap->deinit = eap_tls_deinit;
     456          49 :         eap->process = eap_tls_process;
     457          49 :         eap->isKeyAvailable = eap_tls_isKeyAvailable;
     458          49 :         eap->getKey = eap_tls_getKey;
     459          49 :         eap->get_status = eap_tls_get_status;
     460          49 :         eap->has_reauth_data = eap_tls_has_reauth_data;
     461          49 :         eap->deinit_for_reauth = eap_tls_deinit_for_reauth;
     462          49 :         eap->init_for_reauth = eap_tls_init_for_reauth;
     463          49 :         eap->get_emsk = eap_tls_get_emsk;
     464             : 
     465          49 :         return eap_peer_method_register(eap);
     466             : }
     467             : #endif /* CONFIG_HS20 */

Generated by: LCOV version 1.10