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

Generated by: LCOV version 1.10