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

Generated by: LCOV version 1.10