LCOV - code coverage report
Current view: top level - src/eap_peer - eap_tls_common.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1426431149 Lines: 346 454 76.2 %
Date: 2015-03-15 Functions: 26 26 100.0 %

          Line data    Source code
       1             : /*
       2             :  * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
       3             :  * Copyright (c) 2004-2013, 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/sha1.h"
      13             : #include "crypto/tls.h"
      14             : #include "eap_i.h"
      15             : #include "eap_tls_common.h"
      16             : #include "eap_config.h"
      17             : 
      18             : 
      19        1413 : static struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
      20             :                                          u8 code, u8 identifier)
      21             : {
      22        1413 :         if (type == EAP_UNAUTH_TLS_TYPE)
      23           8 :                 return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS,
      24             :                                      EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len,
      25             :                                      code, identifier);
      26        1405 :         if (type == EAP_WFA_UNAUTH_TLS_TYPE)
      27           8 :                 return eap_msg_alloc(EAP_VENDOR_WFA_NEW,
      28             :                                      EAP_VENDOR_WFA_UNAUTH_TLS, payload_len,
      29             :                                      code, identifier);
      30        1397 :         return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code,
      31             :                              identifier);
      32             : }
      33             : 
      34             : 
      35         996 : static int eap_tls_check_blob(struct eap_sm *sm, const char **name,
      36             :                               const u8 **data, size_t *data_len)
      37             : {
      38             :         const struct wpa_config_blob *blob;
      39             : 
      40         996 :         if (*name == NULL || os_strncmp(*name, "blob://", 7) != 0)
      41         989 :                 return 0;
      42             : 
      43           7 :         blob = eap_get_config_blob(sm, *name + 7);
      44           7 :         if (blob == NULL) {
      45           0 :                 wpa_printf(MSG_ERROR, "%s: Named configuration blob '%s' not "
      46           0 :                            "found", __func__, *name + 7);
      47           0 :                 return -1;
      48             :         }
      49             : 
      50           7 :         *name = NULL;
      51           7 :         *data = blob->data;
      52           7 :         *data_len = blob->len;
      53             : 
      54           7 :         return 0;
      55             : }
      56             : 
      57             : 
      58         249 : static void eap_tls_params_flags(struct tls_connection_params *params,
      59             :                                  const char *txt)
      60             : {
      61         249 :         if (txt == NULL)
      62         460 :                 return;
      63          38 :         if (os_strstr(txt, "tls_allow_md5=1"))
      64           0 :                 params->flags |= TLS_CONN_ALLOW_SIGN_RSA_MD5;
      65          38 :         if (os_strstr(txt, "tls_disable_time_checks=1"))
      66           1 :                 params->flags |= TLS_CONN_DISABLE_TIME_CHECKS;
      67          38 :         if (os_strstr(txt, "tls_disable_session_ticket=1"))
      68           0 :                 params->flags |= TLS_CONN_DISABLE_SESSION_TICKET;
      69          38 :         if (os_strstr(txt, "tls_disable_session_ticket=0"))
      70           0 :                 params->flags &= ~TLS_CONN_DISABLE_SESSION_TICKET;
      71          38 :         if (os_strstr(txt, "tls_disable_tlsv1_1=1"))
      72           0 :                 params->flags |= TLS_CONN_DISABLE_TLSv1_1;
      73          38 :         if (os_strstr(txt, "tls_disable_tlsv1_1=0"))
      74           0 :                 params->flags &= ~TLS_CONN_DISABLE_TLSv1_1;
      75          38 :         if (os_strstr(txt, "tls_disable_tlsv1_2=1"))
      76           0 :                 params->flags |= TLS_CONN_DISABLE_TLSv1_2;
      77          38 :         if (os_strstr(txt, "tls_disable_tlsv1_2=0"))
      78           0 :                 params->flags &= ~TLS_CONN_DISABLE_TLSv1_2;
      79             : }
      80             : 
      81             : 
      82         248 : static void eap_tls_params_from_conf1(struct tls_connection_params *params,
      83             :                                       struct eap_peer_config *config)
      84             : {
      85         248 :         params->ca_cert = (char *) config->ca_cert;
      86         248 :         params->ca_path = (char *) config->ca_path;
      87         248 :         params->client_cert = (char *) config->client_cert;
      88         248 :         params->private_key = (char *) config->private_key;
      89         248 :         params->private_key_passwd = (char *) config->private_key_passwd;
      90         248 :         params->dh_file = (char *) config->dh_file;
      91         248 :         params->subject_match = (char *) config->subject_match;
      92         248 :         params->altsubject_match = (char *) config->altsubject_match;
      93         248 :         params->suffix_match = config->domain_suffix_match;
      94         248 :         params->domain_match = config->domain_match;
      95         248 :         params->engine = config->engine;
      96         248 :         params->engine_id = config->engine_id;
      97         248 :         params->pin = config->pin;
      98         248 :         params->key_id = config->key_id;
      99         248 :         params->cert_id = config->cert_id;
     100         248 :         params->ca_cert_id = config->ca_cert_id;
     101         248 :         eap_tls_params_flags(params, config->phase1);
     102         248 : }
     103             : 
     104             : 
     105           1 : static void eap_tls_params_from_conf2(struct tls_connection_params *params,
     106             :                                       struct eap_peer_config *config)
     107             : {
     108           1 :         params->ca_cert = (char *) config->ca_cert2;
     109           1 :         params->ca_path = (char *) config->ca_path2;
     110           1 :         params->client_cert = (char *) config->client_cert2;
     111           1 :         params->private_key = (char *) config->private_key2;
     112           1 :         params->private_key_passwd = (char *) config->private_key2_passwd;
     113           1 :         params->dh_file = (char *) config->dh_file2;
     114           1 :         params->subject_match = (char *) config->subject_match2;
     115           1 :         params->altsubject_match = (char *) config->altsubject_match2;
     116           1 :         params->suffix_match = config->domain_suffix_match2;
     117           1 :         params->domain_match = config->domain_match2;
     118           1 :         params->engine = config->engine2;
     119           1 :         params->engine_id = config->engine2_id;
     120           1 :         params->pin = config->pin2;
     121           1 :         params->key_id = config->key2_id;
     122           1 :         params->cert_id = config->cert2_id;
     123           1 :         params->ca_cert_id = config->ca_cert2_id;
     124           1 :         eap_tls_params_flags(params, config->phase2);
     125           1 : }
     126             : 
     127             : 
     128         249 : static int eap_tls_params_from_conf(struct eap_sm *sm,
     129             :                                     struct eap_ssl_data *data,
     130             :                                     struct tls_connection_params *params,
     131             :                                     struct eap_peer_config *config, int phase2)
     132             : {
     133         249 :         os_memset(params, 0, sizeof(*params));
     134         249 :         if (sm->workaround && data->eap_type != EAP_TYPE_FAST) {
     135             :                 /*
     136             :                  * Some deployed authentication servers seem to be unable to
     137             :                  * handle the TLS Session Ticket extension (they are supposed
     138             :                  * to ignore unrecognized TLS extensions, but end up rejecting
     139             :                  * the ClientHello instead). As a workaround, disable use of
     140             :                  * TLS Sesson Ticket extension for EAP-TLS, EAP-PEAP, and
     141             :                  * EAP-TTLS (EAP-FAST uses session ticket, so any server that
     142             :                  * supports EAP-FAST does not need this workaround).
     143             :                  */
     144         226 :                 params->flags |= TLS_CONN_DISABLE_SESSION_TICKET;
     145             :         }
     146         249 :         if (phase2) {
     147           1 :                 wpa_printf(MSG_DEBUG, "TLS: using phase2 config options");
     148           1 :                 eap_tls_params_from_conf2(params, config);
     149             :         } else {
     150         248 :                 wpa_printf(MSG_DEBUG, "TLS: using phase1 config options");
     151         248 :                 eap_tls_params_from_conf1(params, config);
     152         248 :                 if (data->eap_type == EAP_TYPE_FAST)
     153          23 :                         params->flags |= TLS_CONN_EAP_FAST;
     154             :         }
     155             : 
     156             :         /*
     157             :          * Use blob data, if available. Otherwise, leave reference to external
     158             :          * file as-is.
     159             :          */
     160         249 :         if (eap_tls_check_blob(sm, &params->ca_cert, &params->ca_cert_blob,
     161         249 :                                &params->ca_cert_blob_len) ||
     162         249 :             eap_tls_check_blob(sm, &params->client_cert,
     163             :                                &params->client_cert_blob,
     164         249 :                                &params->client_cert_blob_len) ||
     165         249 :             eap_tls_check_blob(sm, &params->private_key,
     166             :                                &params->private_key_blob,
     167         249 :                                &params->private_key_blob_len) ||
     168         249 :             eap_tls_check_blob(sm, &params->dh_file, &params->dh_blob,
     169             :                                &params->dh_blob_len)) {
     170           0 :                 wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs");
     171           0 :                 return -1;
     172             :         }
     173             : 
     174         249 :         params->openssl_ciphers = config->openssl_ciphers;
     175             : 
     176         249 :         return 0;
     177             : }
     178             : 
     179             : 
     180         249 : static int eap_tls_init_connection(struct eap_sm *sm,
     181             :                                    struct eap_ssl_data *data,
     182             :                                    struct eap_peer_config *config,
     183             :                                    struct tls_connection_params *params)
     184             : {
     185             :         int res;
     186             : 
     187         249 :         if (config->ocsp)
     188           5 :                 params->flags |= TLS_CONN_REQUEST_OCSP;
     189         249 :         if (config->ocsp == 2)
     190           4 :                 params->flags |= TLS_CONN_REQUIRE_OCSP;
     191         249 :         data->conn = tls_connection_init(data->ssl_ctx);
     192         249 :         if (data->conn == NULL) {
     193           0 :                 wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
     194             :                            "connection");
     195           0 :                 return -1;
     196             :         }
     197             : 
     198         249 :         res = tls_connection_set_params(data->ssl_ctx, data->conn, params);
     199         249 :         if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) {
     200             :                 /*
     201             :                  * At this point with the pkcs11 engine the PIN might be wrong.
     202             :                  * We reset the PIN in the configuration to be sure to not use
     203             :                  * it again and the calling function must request a new one.
     204             :                  */
     205           0 :                 os_free(config->pin);
     206           0 :                 config->pin = NULL;
     207         249 :         } else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) {
     208           0 :                 wpa_printf(MSG_INFO, "TLS: Failed to load private key");
     209             :                 /*
     210             :                  * We do not know exactly but maybe the PIN was wrong,
     211             :                  * so ask for a new one.
     212             :                  */
     213           0 :                 os_free(config->pin);
     214           0 :                 config->pin = NULL;
     215           0 :                 eap_sm_request_pin(sm);
     216           0 :                 sm->ignore = TRUE;
     217           0 :                 tls_connection_deinit(data->ssl_ctx, data->conn);
     218           0 :                 data->conn = NULL;
     219           0 :                 return -1;
     220         249 :         } else if (res) {
     221           4 :                 wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection "
     222             :                            "parameters");
     223           4 :                 tls_connection_deinit(data->ssl_ctx, data->conn);
     224           4 :                 data->conn = NULL;
     225           4 :                 return -1;
     226             :         }
     227             : 
     228         245 :         return 0;
     229             : }
     230             : 
     231             : 
     232             : /**
     233             :  * eap_peer_tls_ssl_init - Initialize shared TLS functionality
     234             :  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
     235             :  * @data: Data for TLS processing
     236             :  * @config: Pointer to the network configuration
     237             :  * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
     238             :  * Returns: 0 on success, -1 on failure
     239             :  *
     240             :  * This function is used to initialize shared TLS functionality for EAP-TLS,
     241             :  * EAP-PEAP, EAP-TTLS, and EAP-FAST.
     242             :  */
     243         249 : int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
     244             :                           struct eap_peer_config *config, u8 eap_type)
     245             : {
     246             :         struct tls_connection_params params;
     247             : 
     248         249 :         if (config == NULL)
     249           0 :                 return -1;
     250             : 
     251         249 :         data->eap = sm;
     252         249 :         data->eap_type = eap_type;
     253         249 :         data->phase2 = sm->init_phase2;
     254         249 :         data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
     255             :                 sm->ssl_ctx;
     256         249 :         if (eap_tls_params_from_conf(sm, data, &params, config, data->phase2) <
     257             :             0)
     258           0 :                 return -1;
     259             : 
     260         249 :         if (eap_tls_init_connection(sm, data, config, &params) < 0)
     261           4 :                 return -1;
     262             : 
     263         245 :         data->tls_out_limit = config->fragment_size;
     264         245 :         if (data->phase2) {
     265             :                 /* Limit the fragment size in the inner TLS authentication
     266             :                  * since the outer authentication with EAP-PEAP does not yet
     267             :                  * support fragmentation */
     268           1 :                 if (data->tls_out_limit > 100)
     269           1 :                         data->tls_out_limit -= 100;
     270             :         }
     271             : 
     272         282 :         if (config->phase1 &&
     273          37 :             os_strstr(config->phase1, "include_tls_length=1")) {
     274           0 :                 wpa_printf(MSG_DEBUG, "TLS: Include TLS Message Length in "
     275             :                            "unfragmented packets");
     276           0 :                 data->include_tls_length = 1;
     277             :         }
     278             : 
     279         245 :         return 0;
     280             : }
     281             : 
     282             : 
     283             : /**
     284             :  * eap_peer_tls_ssl_deinit - Deinitialize shared TLS functionality
     285             :  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
     286             :  * @data: Data for TLS processing
     287             :  *
     288             :  * This function deinitializes shared TLS functionality that was initialized
     289             :  * with eap_peer_tls_ssl_init().
     290             :  */
     291         249 : void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
     292             : {
     293         249 :         tls_connection_deinit(data->ssl_ctx, data->conn);
     294         249 :         eap_peer_tls_reset_input(data);
     295         249 :         eap_peer_tls_reset_output(data);
     296         249 : }
     297             : 
     298             : 
     299             : /**
     300             :  * eap_peer_tls_derive_key - Derive a key based on TLS session data
     301             :  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
     302             :  * @data: Data for TLS processing
     303             :  * @label: Label string for deriving the keys, e.g., "client EAP encryption"
     304             :  * @len: Length of the key material to generate (usually 64 for MSK)
     305             :  * Returns: Pointer to allocated key on success or %NULL on failure
     306             :  *
     307             :  * This function uses TLS-PRF to generate pseudo-random data based on the TLS
     308             :  * session data (client/server random and master key). Each key type may use a
     309             :  * different label to bind the key usage into the generated material.
     310             :  *
     311             :  * The caller is responsible for freeing the returned buffer.
     312             :  */
     313         316 : u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
     314             :                              const char *label, size_t len)
     315             : {
     316             : #ifndef CONFIG_FIPS
     317             :         struct tls_keys keys;
     318             : #endif /* CONFIG_FIPS */
     319         316 :         u8 *rnd = NULL, *out;
     320             : 
     321         316 :         out = os_malloc(len);
     322         316 :         if (out == NULL)
     323           0 :                 return NULL;
     324             : 
     325             :         /* First, try to use TLS library function for PRF, if available. */
     326         316 :         if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, out, len)
     327             :             == 0)
     328         316 :                 return out;
     329             : 
     330             : #ifndef CONFIG_FIPS
     331             :         /*
     332             :          * TLS library did not support key generation, so get the needed TLS
     333             :          * session parameters and use an internal implementation of TLS PRF to
     334             :          * derive the key.
     335             :          */
     336           0 :         if (tls_connection_get_keys(data->ssl_ctx, data->conn, &keys))
     337           0 :                 goto fail;
     338             : 
     339           0 :         if (keys.client_random == NULL || keys.server_random == NULL ||
     340           0 :             keys.master_key == NULL)
     341             :                 goto fail;
     342             : 
     343           0 :         rnd = os_malloc(keys.client_random_len + keys.server_random_len);
     344           0 :         if (rnd == NULL)
     345           0 :                 goto fail;
     346           0 :         os_memcpy(rnd, keys.client_random, keys.client_random_len);
     347           0 :         os_memcpy(rnd + keys.client_random_len, keys.server_random,
     348             :                   keys.server_random_len);
     349             : 
     350           0 :         if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
     351           0 :                              label, rnd, keys.client_random_len +
     352           0 :                              keys.server_random_len, out, len))
     353           0 :                 goto fail;
     354             : 
     355           0 :         os_free(rnd);
     356           0 :         return out;
     357             : 
     358             : fail:
     359             : #endif /* CONFIG_FIPS */
     360           0 :         os_free(out);
     361           0 :         os_free(rnd);
     362           0 :         return NULL;
     363             : }
     364             : 
     365             : 
     366             : /**
     367             :  * eap_peer_tls_derive_session_id - Derive a Session-Id based on TLS data
     368             :  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
     369             :  * @data: Data for TLS processing
     370             :  * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
     371             :  * @len: Pointer to length of the session ID generated
     372             :  * Returns: Pointer to allocated Session-Id on success or %NULL on failure
     373             :  *
     374             :  * This function derive the Session-Id based on the TLS session data
     375             :  * (client/server random and method type).
     376             :  *
     377             :  * The caller is responsible for freeing the returned buffer.
     378             :  */
     379         228 : u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
     380             :                                     struct eap_ssl_data *data, u8 eap_type,
     381             :                                     size_t *len)
     382             : {
     383             :         struct tls_keys keys;
     384             :         u8 *out;
     385             : 
     386         228 :         if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
     387           0 :                 return NULL;
     388             : 
     389         228 :         if (keys.client_random == NULL || keys.server_random == NULL)
     390           0 :                 return NULL;
     391             : 
     392         228 :         *len = 1 + keys.client_random_len + keys.server_random_len;
     393         228 :         out = os_malloc(*len);
     394         228 :         if (out == NULL)
     395           0 :                 return NULL;
     396             : 
     397             :         /* Session-Id = EAP type || client.random || server.random */
     398         228 :         out[0] = eap_type;
     399         228 :         os_memcpy(out + 1, keys.client_random, keys.client_random_len);
     400         228 :         os_memcpy(out + 1 + keys.client_random_len, keys.server_random,
     401             :                   keys.server_random_len);
     402             : 
     403         228 :         return out;
     404             : }
     405             : 
     406             : 
     407             : /**
     408             :  * eap_peer_tls_reassemble_fragment - Reassemble a received fragment
     409             :  * @data: Data for TLS processing
     410             :  * @in_data: Next incoming TLS segment
     411             :  * Returns: 0 on success, 1 if more data is needed for the full message, or
     412             :  * -1 on error
     413             :  */
     414         441 : static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data,
     415             :                                             const struct wpabuf *in_data)
     416             : {
     417             :         size_t tls_in_len, in_len;
     418             : 
     419         441 :         tls_in_len = data->tls_in ? wpabuf_len(data->tls_in) : 0;
     420         441 :         in_len = in_data ? wpabuf_len(in_data) : 0;
     421             : 
     422         441 :         if (tls_in_len + in_len == 0) {
     423             :                 /* No message data received?! */
     424           0 :                 wpa_printf(MSG_WARNING, "SSL: Invalid reassembly state: "
     425             :                            "tls_in_left=%lu tls_in_len=%lu in_len=%lu",
     426             :                            (unsigned long) data->tls_in_left,
     427             :                            (unsigned long) tls_in_len,
     428             :                            (unsigned long) in_len);
     429           0 :                 eap_peer_tls_reset_input(data);
     430           0 :                 return -1;
     431             :         }
     432             : 
     433         441 :         if (tls_in_len + in_len > 65536) {
     434             :                 /*
     435             :                  * Limit length to avoid rogue servers from causing large
     436             :                  * memory allocations.
     437             :                  */
     438           0 :                 wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size over "
     439             :                            "64 kB)");
     440           0 :                 eap_peer_tls_reset_input(data);
     441           0 :                 return -1;
     442             :         }
     443             : 
     444         441 :         if (in_len > data->tls_in_left) {
     445             :                 /* Sender is doing something odd - reject message */
     446           0 :                 wpa_printf(MSG_INFO, "SSL: more data than TLS message length "
     447             :                            "indicated");
     448           0 :                 eap_peer_tls_reset_input(data);
     449           0 :                 return -1;
     450             :         }
     451             : 
     452         441 :         if (wpabuf_resize(&data->tls_in, in_len) < 0) {
     453           0 :                 wpa_printf(MSG_INFO, "SSL: Could not allocate memory for TLS "
     454             :                            "data");
     455           0 :                 eap_peer_tls_reset_input(data);
     456           0 :                 return -1;
     457             :         }
     458         441 :         if (in_data)
     459         441 :                 wpabuf_put_buf(data->tls_in, in_data);
     460         441 :         data->tls_in_left -= in_len;
     461             : 
     462         441 :         if (data->tls_in_left > 0) {
     463         226 :                 wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input "
     464             :                            "data", (unsigned long) data->tls_in_left);
     465         226 :                 return 1;
     466             :         }
     467             : 
     468         215 :         return 0;
     469             : }
     470             : 
     471             : 
     472             : /**
     473             :  * eap_peer_tls_data_reassemble - Reassemble TLS data
     474             :  * @data: Data for TLS processing
     475             :  * @in_data: Next incoming TLS segment
     476             :  * @need_more_input: Variable for returning whether more input data is needed
     477             :  * to reassemble this TLS packet
     478             :  * Returns: Pointer to output data, %NULL on error or when more data is needed
     479             :  * for the full message (in which case, *need_more_input is also set to 1).
     480             :  *
     481             :  * This function reassembles TLS fragments. Caller must not free the returned
     482             :  * data buffer since an internal pointer to it is maintained.
     483             :  */
     484        1342 : static const struct wpabuf * eap_peer_tls_data_reassemble(
     485             :         struct eap_ssl_data *data, const struct wpabuf *in_data,
     486             :         int *need_more_input)
     487             : {
     488        1342 :         *need_more_input = 0;
     489             : 
     490        1557 :         if (data->tls_in_left > wpabuf_len(in_data) || data->tls_in) {
     491             :                 /* Message has fragments */
     492         441 :                 int res = eap_peer_tls_reassemble_fragment(data, in_data);
     493         441 :                 if (res) {
     494         226 :                         if (res == 1)
     495         226 :                                 *need_more_input = 1;
     496         226 :                         return NULL;
     497             :                 }
     498             : 
     499             :                 /* Message is now fully reassembled. */
     500             :         } else {
     501             :                 /* No fragments in this message, so just make a copy of it. */
     502         901 :                 data->tls_in_left = 0;
     503         901 :                 data->tls_in = wpabuf_dup(in_data);
     504         901 :                 if (data->tls_in == NULL)
     505           0 :                         return NULL;
     506             :         }
     507             : 
     508        1116 :         return data->tls_in;
     509             : }
     510             : 
     511             : 
     512             : /**
     513             :  * eap_tls_process_input - Process incoming TLS message
     514             :  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
     515             :  * @data: Data for TLS processing
     516             :  * @in_data: Message received from the server
     517             :  * @in_len: Length of in_data
     518             :  * @out_data: Buffer for returning a pointer to application data (if available)
     519             :  * Returns: 0 on success, 1 if more input data is needed, 2 if application data
     520             :  * is available, -1 on failure
     521             :  */
     522         968 : static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data,
     523             :                                  const u8 *in_data, size_t in_len,
     524             :                                  struct wpabuf **out_data)
     525             : {
     526             :         const struct wpabuf *msg;
     527             :         int need_more_input;
     528             :         struct wpabuf *appl_data;
     529             :         struct wpabuf buf;
     530             : 
     531         968 :         wpabuf_set(&buf, in_data, in_len);
     532         968 :         msg = eap_peer_tls_data_reassemble(data, &buf, &need_more_input);
     533         968 :         if (msg == NULL)
     534         226 :                 return need_more_input ? 1 : -1;
     535             : 
     536             :         /* Full TLS message reassembled - continue handshake processing */
     537         742 :         if (data->tls_out) {
     538             :                 /* This should not happen.. */
     539           0 :                 wpa_printf(MSG_INFO, "SSL: eap_tls_process_input - pending "
     540             :                            "tls_out data even though tls_out_len = 0");
     541           0 :                 wpabuf_free(data->tls_out);
     542             :                 WPA_ASSERT(data->tls_out == NULL);
     543             :         }
     544         742 :         appl_data = NULL;
     545         742 :         data->tls_out = tls_connection_handshake(data->ssl_ctx, data->conn,
     546             :                                                  msg, &appl_data);
     547             : 
     548         742 :         eap_peer_tls_reset_input(data);
     549             : 
     550         753 :         if (appl_data &&
     551          22 :             tls_connection_established(data->ssl_ctx, data->conn) &&
     552          11 :             !tls_connection_get_failed(data->ssl_ctx, data->conn)) {
     553          11 :                 wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application data",
     554             :                                     appl_data);
     555          11 :                 *out_data = appl_data;
     556          11 :                 return 2;
     557             :         }
     558             : 
     559         731 :         wpabuf_free(appl_data);
     560             : 
     561         731 :         return 0;
     562             : }
     563             : 
     564             : 
     565             : /**
     566             :  * eap_tls_process_output - Process outgoing TLS message
     567             :  * @data: Data for TLS processing
     568             :  * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
     569             :  * @peap_version: Version number for EAP-PEAP/TTLS
     570             :  * @id: EAP identifier for the response
     571             :  * @ret: Return value to use on success
     572             :  * @out_data: Buffer for returning the allocated output buffer
     573             :  * Returns: ret (0 or 1) on success, -1 on failure
     574             :  */
     575        1026 : static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type,
     576             :                                   int peap_version, u8 id, int ret,
     577             :                                   struct wpabuf **out_data)
     578             : {
     579             :         size_t len;
     580             :         u8 *flags;
     581             :         int more_fragments, length_included;
     582             : 
     583        1026 :         if (data->tls_out == NULL)
     584           0 :                 return -1;
     585        1026 :         len = wpabuf_len(data->tls_out) - data->tls_out_pos;
     586        1026 :         wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total "
     587             :                    "%lu bytes)",
     588             :                    (unsigned long) len,
     589        1026 :                    (unsigned long) wpabuf_len(data->tls_out));
     590             : 
     591             :         /*
     592             :          * Limit outgoing message to the configured maximum size. Fragment
     593             :          * message if needed.
     594             :          */
     595        1026 :         if (len > data->tls_out_limit) {
     596          73 :                 more_fragments = 1;
     597          73 :                 len = data->tls_out_limit;
     598          73 :                 wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments "
     599             :                            "will follow", (unsigned long) len);
     600             :         } else
     601         953 :                 more_fragments = 0;
     602             : 
     603        2003 :         length_included = data->tls_out_pos == 0 &&
     604        1885 :                 (wpabuf_len(data->tls_out) > data->tls_out_limit ||
     605         931 :                  data->include_tls_length);
     606        1026 :         if (!length_included &&
     607         252 :             eap_type == EAP_TYPE_PEAP && peap_version == 0 &&
     608          56 :             !tls_connection_established(data->eap->ssl_ctx, data->conn)) {
     609             :                 /*
     610             :                  * Windows Server 2008 NPS really wants to have the TLS Message
     611             :                  * length included in phase 0 even for unfragmented frames or
     612             :                  * it will get very confused with Compound MAC calculation and
     613             :                  * Outer TLVs.
     614             :                  */
     615          18 :                 length_included = 1;
     616             :         }
     617             : 
     618        1026 :         *out_data = eap_tls_msg_alloc(eap_type, 1 + length_included * 4 + len,
     619             :                                       EAP_CODE_RESPONSE, id);
     620        1026 :         if (*out_data == NULL)
     621           0 :                 return -1;
     622             : 
     623        1026 :         flags = wpabuf_put(*out_data, 1);
     624        1026 :         *flags = peap_version;
     625        1026 :         if (more_fragments)
     626          73 :                 *flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
     627        1026 :         if (length_included) {
     628          41 :                 *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
     629          41 :                 wpabuf_put_be32(*out_data, wpabuf_len(data->tls_out));
     630             :         }
     631             : 
     632        1026 :         wpabuf_put_data(*out_data,
     633        1026 :                         wpabuf_head_u8(data->tls_out) + data->tls_out_pos,
     634             :                         len);
     635        1026 :         data->tls_out_pos += len;
     636             : 
     637        1026 :         if (!more_fragments)
     638         953 :                 eap_peer_tls_reset_output(data);
     639             : 
     640        1026 :         return ret;
     641             : }
     642             : 
     643             : 
     644             : /**
     645             :  * eap_peer_tls_process_helper - Process TLS handshake message
     646             :  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
     647             :  * @data: Data for TLS processing
     648             :  * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
     649             :  * @peap_version: Version number for EAP-PEAP/TTLS
     650             :  * @id: EAP identifier for the response
     651             :  * @in_data: Message received from the server
     652             :  * @in_len: Length of in_data
     653             :  * @out_data: Buffer for returning a pointer to the response message
     654             :  * Returns: 0 on success, 1 if more input data is needed, 2 if application data
     655             :  * is available, or -1 on failure
     656             :  *
     657             :  * This function can be used to process TLS handshake messages. It reassembles
     658             :  * the received fragments and uses a TLS library to process the messages. The
     659             :  * response data from the TLS library is fragmented to suitable output messages
     660             :  * that the caller can send out.
     661             :  *
     662             :  * out_data is used to return the response message if the return value of this
     663             :  * function is 0, 2, or -1. In case of failure, the message is likely a TLS
     664             :  * alarm message. The caller is responsible for freeing the allocated buffer if
     665             :  * *out_data is not %NULL.
     666             :  *
     667             :  * This function is called for each received TLS message during the TLS
     668             :  * handshake after eap_peer_tls_process_init() call and possible processing of
     669             :  * TLS Flags field. Once the handshake has been completed, i.e., when
     670             :  * tls_connection_established() returns 1, EAP method specific decrypting of
     671             :  * the tunneled data is used.
     672             :  */
     673        1034 : int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
     674             :                                 EapType eap_type, int peap_version,
     675             :                                 u8 id, const u8 *in_data, size_t in_len,
     676             :                                 struct wpabuf **out_data)
     677             : {
     678        1034 :         int ret = 0;
     679             : 
     680        1034 :         *out_data = NULL;
     681             : 
     682        1034 :         if (data->tls_out && wpabuf_len(data->tls_out) > 0 && in_len > 0) {
     683           0 :                 wpa_printf(MSG_DEBUG, "SSL: Received non-ACK when output "
     684             :                            "fragments are waiting to be sent out");
     685           0 :                 return -1;
     686             :         }
     687             : 
     688        1034 :         if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) {
     689             :                 /*
     690             :                  * No more data to send out - expect to receive more data from
     691             :                  * the AS.
     692             :                  */
     693         968 :                 int res = eap_tls_process_input(sm, data, in_data, in_len,
     694             :                                                 out_data);
     695         968 :                 if (res) {
     696             :                         /*
     697             :                          * Input processing failed (res = -1) or more data is
     698             :                          * needed (res = 1).
     699             :                          */
     700         237 :                         return res;
     701             :                 }
     702             : 
     703             :                 /*
     704             :                  * The incoming message has been reassembled and processed. The
     705             :                  * response was allocated into data->tls_out buffer.
     706             :                  */
     707             :         }
     708             : 
     709         797 :         if (data->tls_out == NULL) {
     710             :                 /*
     711             :                  * No outgoing fragments remaining from the previous message
     712             :                  * and no new message generated. This indicates an error in TLS
     713             :                  * processing.
     714             :                  */
     715           0 :                 eap_peer_tls_reset_output(data);
     716           0 :                 return -1;
     717             :         }
     718             : 
     719         797 :         if (tls_connection_get_failed(data->ssl_ctx, data->conn)) {
     720             :                 /* TLS processing has failed - return error */
     721          25 :                 wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
     722             :                            "report error");
     723          25 :                 ret = -1;
     724             :                 /* TODO: clean pin if engine used? */
     725             :         }
     726             : 
     727         797 :         if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) {
     728             :                 /*
     729             :                  * TLS negotiation should now be complete since all other cases
     730             :                  * needing more data should have been caught above based on
     731             :                  * the TLS Message Length field.
     732             :                  */
     733         211 :                 wpa_printf(MSG_DEBUG, "SSL: No data to be sent out");
     734         211 :                 wpabuf_free(data->tls_out);
     735         211 :                 data->tls_out = NULL;
     736         211 :                 return 1;
     737             :         }
     738             : 
     739             :         /* Send the pending message (in fragments, if needed). */
     740         586 :         return eap_tls_process_output(data, eap_type, peap_version, id, ret,
     741             :                                       out_data);
     742             : }
     743             : 
     744             : 
     745             : /**
     746             :  * eap_peer_tls_build_ack - Build a TLS ACK frame
     747             :  * @id: EAP identifier for the response
     748             :  * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
     749             :  * @peap_version: Version number for EAP-PEAP/TTLS
     750             :  * Returns: Pointer to the allocated ACK frame or %NULL on failure
     751             :  */
     752         387 : struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type,
     753             :                                        int peap_version)
     754             : {
     755             :         struct wpabuf *resp;
     756             : 
     757         387 :         resp = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_RESPONSE, id);
     758         387 :         if (resp == NULL)
     759           0 :                 return NULL;
     760         387 :         wpa_printf(MSG_DEBUG, "SSL: Building ACK (type=%d id=%d ver=%d)",
     761             :                    (int) eap_type, id, peap_version);
     762         387 :         wpabuf_put_u8(resp, peap_version); /* Flags */
     763         387 :         return resp;
     764             : }
     765             : 
     766             : 
     767             : /**
     768             :  * eap_peer_tls_reauth_init - Re-initialize shared TLS for session resumption
     769             :  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
     770             :  * @data: Data for TLS processing
     771             :  * Returns: 0 on success, -1 on failure
     772             :  */
     773          19 : int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data)
     774             : {
     775          19 :         eap_peer_tls_reset_input(data);
     776          19 :         eap_peer_tls_reset_output(data);
     777          19 :         return tls_connection_shutdown(data->ssl_ctx, data->conn);
     778             : }
     779             : 
     780             : 
     781             : /**
     782             :  * eap_peer_tls_status - Get TLS status
     783             :  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
     784             :  * @data: Data for TLS processing
     785             :  * @buf: Buffer for status information
     786             :  * @buflen: Maximum buffer length
     787             :  * @verbose: Whether to include verbose status information
     788             :  * Returns: Number of bytes written to buf.
     789             :  */
     790         133 : int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data,
     791             :                         char *buf, size_t buflen, int verbose)
     792             : {
     793             :         char name[128];
     794         133 :         int len = 0, ret;
     795             : 
     796         133 :         if (tls_get_cipher(data->ssl_ctx, data->conn, name, sizeof(name)) == 0)
     797             :         {
     798         133 :                 ret = os_snprintf(buf + len, buflen - len,
     799             :                                   "EAP TLS cipher=%s\n"
     800             :                                   "tls_session_reused=%d\n",
     801             :                                   name, tls_connection_resumed(data->ssl_ctx,
     802             :                                                                data->conn));
     803         133 :                 if (os_snprintf_error(buflen - len, ret))
     804           0 :                         return len;
     805         133 :                 len += ret;
     806             :         }
     807             : 
     808         133 :         return len;
     809             : }
     810             : 
     811             : 
     812             : /**
     813             :  * eap_peer_tls_process_init - Initial validation/processing of EAP requests
     814             :  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
     815             :  * @data: Data for TLS processing
     816             :  * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
     817             :  * @ret: Return values from EAP request validation and processing
     818             :  * @reqData: EAP request to be processed (eapReqData)
     819             :  * @len: Buffer for returning length of the remaining payload
     820             :  * @flags: Buffer for returning TLS flags
     821             :  * Returns: Pointer to payload after TLS flags and length or %NULL on failure
     822             :  *
     823             :  * This function validates the EAP header and processes the optional TLS
     824             :  * Message Length field. If this is the first fragment of a TLS message, the
     825             :  * TLS reassembly code is initialized to receive the indicated number of bytes.
     826             :  *
     827             :  * EAP-TLS, EAP-PEAP, EAP-TTLS, and EAP-FAST methods are expected to use this
     828             :  * function as the first step in processing received messages. They will need
     829             :  * to process the flags (apart from Message Length Included) that are returned
     830             :  * through the flags pointer and the message payload that will be returned (and
     831             :  * the length is returned through the len pointer). Return values (ret) are set
     832             :  * for continuation of EAP method processing. The caller is responsible for
     833             :  * setting these to indicate completion (either success or failure) based on
     834             :  * the authentication result.
     835             :  */
     836        1422 : const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
     837             :                                      struct eap_ssl_data *data,
     838             :                                      EapType eap_type,
     839             :                                      struct eap_method_ret *ret,
     840             :                                      const struct wpabuf *reqData,
     841             :                                      size_t *len, u8 *flags)
     842             : {
     843             :         const u8 *pos;
     844             :         size_t left;
     845             :         unsigned int tls_msg_len;
     846             : 
     847        1422 :         if (tls_get_errors(data->ssl_ctx)) {
     848           0 :                 wpa_printf(MSG_INFO, "SSL: TLS errors detected");
     849           0 :                 ret->ignore = TRUE;
     850           0 :                 return NULL;
     851             :         }
     852             : 
     853        1422 :         if (eap_type == EAP_UNAUTH_TLS_TYPE)
     854           8 :                 pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
     855             :                                        EAP_VENDOR_TYPE_UNAUTH_TLS, reqData,
     856             :                                        &left);
     857        1414 :         else if (eap_type == EAP_WFA_UNAUTH_TLS_TYPE)
     858           8 :                 pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW,
     859             :                                        EAP_VENDOR_WFA_UNAUTH_TLS, reqData,
     860             :                                        &left);
     861             :         else
     862        1406 :                 pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData,
     863             :                                        &left);
     864        1422 :         if (pos == NULL) {
     865           0 :                 ret->ignore = TRUE;
     866           0 :                 return NULL;
     867             :         }
     868        1422 :         if (left == 0) {
     869           0 :                 wpa_printf(MSG_DEBUG, "SSL: Invalid TLS message: no Flags "
     870             :                            "octet included");
     871           0 :                 if (!sm->workaround) {
     872           0 :                         ret->ignore = TRUE;
     873           0 :                         return NULL;
     874             :                 }
     875             : 
     876           0 :                 wpa_printf(MSG_DEBUG, "SSL: Workaround - assume no Flags "
     877             :                            "indicates ACK frame");
     878           0 :                 *flags = 0;
     879             :         } else {
     880        1422 :                 *flags = *pos++;
     881        1422 :                 left--;
     882             :         }
     883        1422 :         wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - "
     884             :                    "Flags 0x%02x", (unsigned long) wpabuf_len(reqData),
     885        1422 :                    *flags);
     886        1422 :         if (*flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
     887         217 :                 if (left < 4) {
     888           0 :                         wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
     889             :                                    "length");
     890           0 :                         ret->ignore = TRUE;
     891           0 :                         return NULL;
     892             :                 }
     893         217 :                 tls_msg_len = WPA_GET_BE32(pos);
     894         217 :                 wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d",
     895             :                            tls_msg_len);
     896         217 :                 if (data->tls_in_left == 0) {
     897         217 :                         data->tls_in_total = tls_msg_len;
     898         217 :                         data->tls_in_left = tls_msg_len;
     899         217 :                         wpabuf_free(data->tls_in);
     900         217 :                         data->tls_in = NULL;
     901             :                 }
     902         217 :                 pos += 4;
     903         217 :                 left -= 4;
     904             : 
     905         217 :                 if (left > tls_msg_len) {
     906           0 :                         wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d "
     907             :                                    "bytes) smaller than this fragment (%d "
     908             :                                    "bytes)", (int) tls_msg_len, (int) left);
     909           0 :                         ret->ignore = TRUE;
     910           0 :                         return NULL;
     911             :                 }
     912             :         }
     913             : 
     914        1422 :         ret->ignore = FALSE;
     915        1422 :         ret->methodState = METHOD_MAY_CONT;
     916        1422 :         ret->decision = DECISION_FAIL;
     917        1422 :         ret->allowNotifications = TRUE;
     918             : 
     919        1422 :         *len = left;
     920        1422 :         return pos;
     921             : }
     922             : 
     923             : 
     924             : /**
     925             :  * eap_peer_tls_reset_input - Reset input buffers
     926             :  * @data: Data for TLS processing
     927             :  *
     928             :  * This function frees any allocated memory for input buffers and resets input
     929             :  * state.
     930             :  */
     931        1403 : void eap_peer_tls_reset_input(struct eap_ssl_data *data)
     932             : {
     933        1403 :         data->tls_in_left = data->tls_in_total = 0;
     934        1403 :         wpabuf_free(data->tls_in);
     935        1403 :         data->tls_in = NULL;
     936        1403 : }
     937             : 
     938             : 
     939             : /**
     940             :  * eap_peer_tls_reset_output - Reset output buffers
     941             :  * @data: Data for TLS processing
     942             :  *
     943             :  * This function frees any allocated memory for output buffers and resets
     944             :  * output state.
     945             :  */
     946        1655 : void eap_peer_tls_reset_output(struct eap_ssl_data *data)
     947             : {
     948        1655 :         data->tls_out_pos = 0;
     949        1655 :         wpabuf_free(data->tls_out);
     950        1655 :         data->tls_out = NULL;
     951        1655 : }
     952             : 
     953             : 
     954             : /**
     955             :  * eap_peer_tls_decrypt - Decrypt received phase 2 TLS message
     956             :  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
     957             :  * @data: Data for TLS processing
     958             :  * @in_data: Message received from the server
     959             :  * @in_decrypted: Buffer for returning a pointer to the decrypted message
     960             :  * Returns: 0 on success, 1 if more input data is needed, or -1 on failure
     961             :  */
     962         374 : int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data,
     963             :                          const struct wpabuf *in_data,
     964             :                          struct wpabuf **in_decrypted)
     965             : {
     966             :         const struct wpabuf *msg;
     967             :         int need_more_input;
     968             : 
     969         374 :         msg = eap_peer_tls_data_reassemble(data, in_data, &need_more_input);
     970         374 :         if (msg == NULL)
     971           0 :                 return need_more_input ? 1 : -1;
     972             : 
     973         374 :         *in_decrypted = tls_connection_decrypt(data->ssl_ctx, data->conn, msg);
     974         374 :         eap_peer_tls_reset_input(data);
     975         374 :         if (*in_decrypted == NULL) {
     976           0 :                 wpa_printf(MSG_INFO, "SSL: Failed to decrypt Phase 2 data");
     977           0 :                 return -1;
     978             :         }
     979         374 :         return 0;
     980             : }
     981             : 
     982             : 
     983             : /**
     984             :  * eap_peer_tls_encrypt - Encrypt phase 2 TLS message
     985             :  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
     986             :  * @data: Data for TLS processing
     987             :  * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
     988             :  * @peap_version: Version number for EAP-PEAP/TTLS
     989             :  * @id: EAP identifier for the response
     990             :  * @in_data: Plaintext phase 2 data to encrypt or %NULL to continue fragments
     991             :  * @out_data: Buffer for returning a pointer to the encrypted response message
     992             :  * Returns: 0 on success, -1 on failure
     993             :  */
     994         440 : int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data,
     995             :                          EapType eap_type, int peap_version, u8 id,
     996             :                          const struct wpabuf *in_data,
     997             :                          struct wpabuf **out_data)
     998             : {
     999         440 :         if (in_data) {
    1000         434 :                 eap_peer_tls_reset_output(data);
    1001         434 :                 data->tls_out = tls_connection_encrypt(data->ssl_ctx,
    1002             :                                                        data->conn, in_data);
    1003         434 :                 if (data->tls_out == NULL) {
    1004           0 :                         wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 "
    1005             :                                    "data (in_len=%lu)",
    1006             :                                    (unsigned long) wpabuf_len(in_data));
    1007           0 :                         eap_peer_tls_reset_output(data);
    1008           0 :                         return -1;
    1009             :                 }
    1010             :         }
    1011             : 
    1012         440 :         return eap_tls_process_output(data, eap_type, peap_version, id, 0,
    1013             :                                       out_data);
    1014             : }
    1015             : 
    1016             : 
    1017             : /**
    1018             :  * eap_peer_select_phase2_methods - Select phase 2 EAP method
    1019             :  * @config: Pointer to the network configuration
    1020             :  * @prefix: 'phase2' configuration prefix, e.g., "auth="
    1021             :  * @types: Buffer for returning allocated list of allowed EAP methods
    1022             :  * @num_types: Buffer for returning number of allocated EAP methods
    1023             :  * Returns: 0 on success, -1 on failure
    1024             :  *
    1025             :  * This function is used to parse EAP method list and select allowed methods
    1026             :  * for Phase2 authentication.
    1027             :  */
    1028          83 : int eap_peer_select_phase2_methods(struct eap_peer_config *config,
    1029             :                                    const char *prefix,
    1030             :                                    struct eap_method_type **types,
    1031             :                                    size_t *num_types)
    1032             : {
    1033             :         char *start, *pos, *buf;
    1034          83 :         struct eap_method_type *methods = NULL, *_methods;
    1035             :         u8 method;
    1036          83 :         size_t num_methods = 0, prefix_len;
    1037             : 
    1038          83 :         if (config == NULL || config->phase2 == NULL)
    1039             :                 goto get_defaults;
    1040             : 
    1041          74 :         start = buf = os_strdup(config->phase2);
    1042          74 :         if (buf == NULL)
    1043           0 :                 return -1;
    1044             : 
    1045          74 :         prefix_len = os_strlen(prefix);
    1046             : 
    1047         222 :         while (start && *start != '\0') {
    1048             :                 int vendor;
    1049          74 :                 pos = os_strstr(start, prefix);
    1050          74 :                 if (pos == NULL)
    1051           0 :                         break;
    1052          74 :                 if (start != pos && *(pos - 1) != ' ') {
    1053           0 :                         start = pos + prefix_len;
    1054           0 :                         continue;
    1055             :                 }
    1056             : 
    1057          74 :                 start = pos + prefix_len;
    1058          74 :                 pos = os_strchr(start, ' ');
    1059          74 :                 if (pos)
    1060           0 :                         *pos++ = '\0';
    1061          74 :                 method = eap_get_phase2_type(start, &vendor);
    1062          74 :                 if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE) {
    1063           0 :                         wpa_printf(MSG_ERROR, "TLS: Unsupported Phase2 EAP "
    1064             :                                    "method '%s'", start);
    1065             :                 } else {
    1066          74 :                         num_methods++;
    1067          74 :                         _methods = os_realloc_array(methods, num_methods,
    1068             :                                                     sizeof(*methods));
    1069          74 :                         if (_methods == NULL) {
    1070           0 :                                 os_free(methods);
    1071           0 :                                 os_free(buf);
    1072           0 :                                 return -1;
    1073             :                         }
    1074          74 :                         methods = _methods;
    1075          74 :                         methods[num_methods - 1].vendor = vendor;
    1076          74 :                         methods[num_methods - 1].method = method;
    1077             :                 }
    1078             : 
    1079          74 :                 start = pos;
    1080             :         }
    1081             : 
    1082          74 :         os_free(buf);
    1083             : 
    1084             : get_defaults:
    1085          83 :         if (methods == NULL)
    1086           9 :                 methods = eap_get_phase2_types(config, &num_methods);
    1087             : 
    1088          83 :         if (methods == NULL) {
    1089           0 :                 wpa_printf(MSG_ERROR, "TLS: No Phase2 EAP methods available");
    1090           0 :                 return -1;
    1091             :         }
    1092          83 :         wpa_hexdump(MSG_DEBUG, "TLS: Phase2 EAP types",
    1093             :                     (u8 *) methods,
    1094             :                     num_methods * sizeof(struct eap_method_type));
    1095             : 
    1096          83 :         *types = methods;
    1097          83 :         *num_types = num_methods;
    1098             : 
    1099          83 :         return 0;
    1100             : }
    1101             : 
    1102             : 
    1103             : /**
    1104             :  * eap_peer_tls_phase2_nak - Generate EAP-Nak for Phase 2
    1105             :  * @types: Buffer for returning allocated list of allowed EAP methods
    1106             :  * @num_types: Buffer for returning number of allocated EAP methods
    1107             :  * @hdr: EAP-Request header (and the following EAP type octet)
    1108             :  * @resp: Buffer for returning the EAP-Nak message
    1109             :  * Returns: 0 on success, -1 on failure
    1110             :  */
    1111          21 : int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types,
    1112             :                             struct eap_hdr *hdr, struct wpabuf **resp)
    1113             : {
    1114          21 :         u8 *pos = (u8 *) (hdr + 1);
    1115             :         size_t i;
    1116             : 
    1117             :         /* TODO: add support for expanded Nak */
    1118          21 :         wpa_printf(MSG_DEBUG, "TLS: Phase 2 Request: Nak type=%d", *pos);
    1119          21 :         wpa_hexdump(MSG_DEBUG, "TLS: Allowed Phase2 EAP types",
    1120             :                     (u8 *) types, num_types * sizeof(struct eap_method_type));
    1121          21 :         *resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK, num_types,
    1122          21 :                               EAP_CODE_RESPONSE, hdr->identifier);
    1123          21 :         if (*resp == NULL)
    1124           0 :                 return -1;
    1125             : 
    1126          42 :         for (i = 0; i < num_types; i++) {
    1127          42 :                 if (types[i].vendor == EAP_VENDOR_IETF &&
    1128          21 :                     types[i].method < 256)
    1129          21 :                         wpabuf_put_u8(*resp, types[i].method);
    1130             :         }
    1131             : 
    1132          21 :         eap_update_len(*resp);
    1133             : 
    1134          21 :         return 0;
    1135             : }

Generated by: LCOV version 1.10