]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
EAP peer: External server certificate chain validation
authorJouni Malinen <j@w1.fi>
Sat, 12 Dec 2015 16:16:54 +0000 (18:16 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 12 Dec 2015 16:24:27 +0000 (18:24 +0200)
This adds support for optional functionality to validate server
certificate chain in TLS-based EAP methods in an external program.
wpa_supplicant control interface is used to indicate when such
validation is needed and what the result of the external validation is.

This external validation can extend or replace the internal validation.
When ca_cert or ca_path parameter is set, the internal validation is
used. If these parameters are omitted, only the external validation is
used. It needs to be understood that leaving those parameters out will
disable most of the validation steps done with the TLS library and that
configuration is not really recommend.

By default, the external validation is not used. It can be enabled by
addingtls_ext_cert_check=1 into the network profile phase1 parameter.
When enabled, external validation is required through the CTRL-REQ/RSP
mechanism similarly to other EAP authentication parameters through the
control interface.

The request to perform external validation is indicated by the following
event:
CTRL-REQ-EXT_CERT_CHECK-<id>:External server certificate validation needed for SSID <ssid>

Before that event, the server certificate chain is provided with the
CTRL-EVENT-EAP-PEER-CERT events that include the cert=<hexdump>
parameter. depth=# indicates which certificate is in question (0 for the
server certificate, 1 for its issues, and so on).

The result of the external validation is provided with the following
command:
CTRL-RSP-EXT_CERT_CHECK-<id>:<good|bad>

It should be noted that this is currently enabled only for OpenSSL (and
BoringSSL/LibreSSL). Due to the constraints in the library API, the
validation result from external processing cannot be reported cleanly
with TLS alert. In other words, if the external validation reject the
server certificate chain, the pending TLS handshake is terminated
without sending more messages to the server.

Signed-off-by: Jouni Malinen <j@w1.fi>
16 files changed:
src/common/defs.h
src/crypto/tls.h
src/crypto/tls_gnutls.c
src/crypto/tls_internal.c
src/crypto/tls_openssl.c
src/eap_peer/eap.c
src/eap_peer/eap_config.h
src/eap_peer/eap_fast.c
src/eap_peer/eap_i.h
src/eap_peer/eap_peap.c
src/eap_peer/eap_tls.c
src/eap_peer/eap_tls_common.c
src/eap_peer/eap_ttls.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant.conf
wpa_supplicant/wpas_glue.c

index 6aea3751a2bc9529cc4909a0f16653184573e0f7..b3ac4e8632153c72821ef57039417f461011793c 100644 (file)
@@ -312,6 +312,7 @@ enum wpa_ctrl_req_type {
        WPA_CTRL_REQ_EAP_PASSPHRASE,
        WPA_CTRL_REQ_SIM,
        WPA_CTRL_REQ_PSK_PASSPHRASE,
+       WPA_CTRL_REQ_EXT_CERT_CHECK,
        NUM_WPA_CTRL_REQS
 };
 
index 2e562339cc5c04cfc8e62b2a5fe426e93ab8e3e6..bca94d67dd87910644d8fd4eb5824126e5a35cca 100644 (file)
@@ -95,6 +95,7 @@ struct tls_config {
 #define TLS_CONN_DISABLE_TLSv1_2 BIT(6)
 #define TLS_CONN_EAP_FAST BIT(7)
 #define TLS_CONN_DISABLE_TLSv1_0 BIT(8)
+#define TLS_CONN_EXT_CERT_CHECK BIT(9)
 
 /**
  * struct tls_connection_params - Parameters for TLS connection
index f994379b16b22a07596626ee65626711b4624d02..b1bec4a5388f19ebf2d676ef7093c73fa168e61f 100644 (file)
@@ -347,6 +347,12 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
        if (conn == NULL || params == NULL)
                return -1;
 
+       if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
+               wpa_printf(MSG_INFO,
+                          "GnuTLS: tls_ext_cert_check=1 not supported");
+               return -1;
+       }
+
        if (params->subject_match) {
                wpa_printf(MSG_INFO, "GnuTLS: subject_match not supported");
                return -1;
index dcbb31d76dec4e737fc2cb7484702c22c6a315ef..8b90d56526b24d0351b1adb3449a035bb2cd9628 100644 (file)
@@ -200,6 +200,12 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
        if (conn->client == NULL)
                return -1;
 
+       if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
+               wpa_printf(MSG_INFO,
+                          "TLS: tls_ext_cert_check=1 not supported");
+               return -1;
+       }
+
        cred = tlsv1_cred_alloc();
        if (cred == NULL)
                return -1;
index 471ae2b7c19d3f988431a492fdd9e8da174562bd..1d75ba7af97dc792d535abd31116f1f7b967e89d 100644 (file)
@@ -1583,7 +1583,8 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
                return;
 
        os_memset(&ev, 0, sizeof(ev));
-       if (conn->cert_probe || context->cert_in_cb) {
+       if (conn->cert_probe || (conn->flags & TLS_CONN_EXT_CERT_CHECK) ||
+           context->cert_in_cb) {
                cert = get_x509_cert(err_cert);
                ev.peer_cert.cert = cert;
        }
@@ -1821,7 +1822,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
        }
 #endif /* OPENSSL_IS_BORINGSSL */
 
-       if (preverify_ok && context->event_cb != NULL)
+       if (depth == 0 && preverify_ok && context->event_cb != NULL)
                context->event_cb(context->cb_ctx,
                                  TLS_CERT_CHAIN_SUCCESS, NULL);
 
index 28d5116fd511844a6c95949c41725ba181152337..5c1897862fb467ebdf433fc20c6604daa00d8d4c 100644 (file)
@@ -48,6 +48,8 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req);
 static const char * eap_sm_method_state_txt(EapMethodState state);
 static const char * eap_sm_decision_txt(EapDecision decision);
 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
+                          const char *msg, size_t msglen);
 
 
 
@@ -320,11 +322,14 @@ SM_STATE(EAP, GET_METHOD)
        wpa_printf(MSG_DEBUG, "EAP: Initialize selected EAP method: "
                   "vendor %u method %u (%s)",
                   sm->reqVendor, method, sm->m->name);
-       if (reinit)
+       if (reinit) {
                sm->eap_method_priv = sm->m->init_for_reauth(
                        sm, sm->eap_method_priv);
-       else
+       } else {
+               sm->waiting_ext_cert_check = 0;
+               sm->ext_cert_check = 0;
                sm->eap_method_priv = sm->m->init(sm);
+       }
 
        if (sm->eap_method_priv == NULL) {
                struct eap_peer_config *config = eap_get_config(sm);
@@ -1858,6 +1863,11 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
        case TLS_CERT_CHAIN_SUCCESS:
                eap_notify_status(sm, "remote certificate verification",
                                  "success");
+               if (sm->ext_cert_check) {
+                       sm->waiting_ext_cert_check = 1;
+                       eap_sm_request(sm, WPA_CTRL_REQ_EXT_CERT_CHECK,
+                                      NULL, 0);
+               }
                break;
        case TLS_CERT_CHAIN_FAILURE:
                wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TLS_CERT_ERROR
@@ -2180,10 +2190,10 @@ int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
 #endif /* CONFIG_CTRL_IFACE */
 
 
-#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
 static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
                           const char *msg, size_t msglen)
 {
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
        struct eap_peer_config *config;
        const char *txt = NULL;
        char *tmp;
@@ -2232,16 +2242,17 @@ static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
        case WPA_CTRL_REQ_SIM:
                txt = msg;
                break;
+       case WPA_CTRL_REQ_EXT_CERT_CHECK:
+               break;
        default:
                return;
        }
 
        if (sm->eapol_cb->eap_param_needed)
                sm->eapol_cb->eap_param_needed(sm->eapol_ctx, field, txt);
-}
-#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
-#define eap_sm_request(sm, type, msg, msglen) do { } while (0)
 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+}
+
 
 const char * eap_sm_get_method_name(struct eap_sm *sm)
 {
index 2b1a1d5e4b2541e74b5b51eb2e1469177c9cf24f..39ddcff679a05a13dffef6cc1b9ab3bfbccd7f24 100644 (file)
@@ -739,6 +739,20 @@ struct eap_peer_config {
         * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
         */
        int erp;
+
+       /**
+        * pending_ext_cert_check - External server certificate check status
+        *
+        * This field should not be set in configuration step. It is only used
+        * internally when control interface is used to request external
+        * validation of server certificate chain.
+        */
+       enum {
+               NO_CHECK = 0,
+               PENDING_CHECK,
+               EXT_CERT_CHECK_GOOD,
+               EXT_CERT_CHECK_BAD,
+       } pending_ext_cert_check;
 };
 
 
index 8b6b7fd929a9a22b6f7130a7b36b5e1f47bcab18..a7f6befa0f656781c49e920b0dae7f00b1c9d3a3 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * EAP peer method: EAP-FAST (RFC 4851)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -67,6 +67,7 @@ struct eap_fast_data {
        int simck_idx;
 
        struct wpabuf *pending_phase2_req;
+       struct wpabuf *pending_resp;
 };
 
 
@@ -254,6 +255,7 @@ static void eap_fast_deinit(struct eap_sm *sm, void *priv)
        os_memset(data->emsk, 0, EAP_EMSK_LEN);
        os_free(data->session_id);
        wpabuf_free(data->pending_phase2_req);
+       wpabuf_free(data->pending_resp);
        os_free(data);
 }
 
@@ -1568,6 +1570,34 @@ static struct wpabuf * eap_fast_process(struct eap_sm *sm, void *priv,
                        res = 1;
                }
        } else {
+               if (sm->waiting_ext_cert_check && data->pending_resp) {
+                       struct eap_peer_config *config = eap_get_config(sm);
+
+                       if (config->pending_ext_cert_check ==
+                           EXT_CERT_CHECK_GOOD) {
+                               wpa_printf(MSG_DEBUG,
+                                          "EAP-FAST: External certificate check succeeded - continue handshake");
+                               resp = data->pending_resp;
+                               data->pending_resp = NULL;
+                               sm->waiting_ext_cert_check = 0;
+                               return resp;
+                       }
+
+                       if (config->pending_ext_cert_check ==
+                           EXT_CERT_CHECK_BAD) {
+                               wpa_printf(MSG_DEBUG,
+                                          "EAP-FAST: External certificate check failed - force authentication failure");
+                               ret->methodState = METHOD_DONE;
+                               ret->decision = DECISION_FAIL;
+                               sm->waiting_ext_cert_check = 0;
+                               return NULL;
+                       }
+
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-FAST: Continuing to wait external server certificate validation");
+                       return NULL;
+               }
+
                /* Continue processing TLS handshake (phase 1). */
                res = eap_peer_tls_process_helper(sm, &data->ssl,
                                                  EAP_TYPE_FAST,
@@ -1581,6 +1611,14 @@ static struct wpabuf * eap_fast_process(struct eap_sm *sm, void *priv,
                        return resp;
                }
 
+               if (sm->waiting_ext_cert_check) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-FAST: Waiting external server certificate validation");
+                       wpabuf_free(data->pending_resp);
+                       data->pending_resp = resp;
+                       return NULL;
+               }
+
                if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
                        char cipher[80];
                        wpa_printf(MSG_DEBUG,
@@ -1645,6 +1683,8 @@ static void eap_fast_deinit_for_reauth(struct eap_sm *sm, void *priv)
        data->key_block_p = NULL;
        wpabuf_free(data->pending_phase2_req);
        data->pending_phase2_req = NULL;
+       wpabuf_free(data->pending_resp);
+       data->pending_resp = NULL;
 }
 
 
index 99b44dae4e34ea9a2e41c0a968dc8972d5d31dc3..6ab24834d654ab9a5c69effd56aa0ed9b53a3c69 100644 (file)
@@ -366,6 +366,8 @@ struct eap_sm {
        int external_sim;
 
        unsigned int expected_failure:1;
+       unsigned int ext_cert_check:1;
+       unsigned int waiting_ext_cert_check:1;
 
        struct dl_list erp_keys; /* struct eap_erp_key */
 };
index 98a48a6cf5d315bef8c8e65e09a6264fab057810..0596098996e52abdd8798c5502557dc3fec21ac1 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -59,6 +59,7 @@ struct eap_peap_data {
        size_t id_len;
 
        struct wpabuf *pending_phase2_req;
+       struct wpabuf *pending_resp;
        enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
        int crypto_binding_used;
        u8 binding_nonce[32];
@@ -191,6 +192,7 @@ static void eap_peap_deinit(struct eap_sm *sm, void *priv)
        eap_peap_free_key(data);
        os_free(data->session_id);
        wpabuf_free(data->pending_phase2_req);
+       wpabuf_free(data->pending_resp);
        os_free(data);
 }
 
@@ -1006,6 +1008,34 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
            !data->resuming) {
                res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp);
        } else {
+               if (sm->waiting_ext_cert_check && data->pending_resp) {
+                       struct eap_peer_config *config = eap_get_config(sm);
+
+                       if (config->pending_ext_cert_check ==
+                           EXT_CERT_CHECK_GOOD) {
+                               wpa_printf(MSG_DEBUG,
+                                          "EAP-PEAP: External certificate check succeeded - continue handshake");
+                               resp = data->pending_resp;
+                               data->pending_resp = NULL;
+                               sm->waiting_ext_cert_check = 0;
+                               return resp;
+                       }
+
+                       if (config->pending_ext_cert_check ==
+                           EXT_CERT_CHECK_BAD) {
+                               wpa_printf(MSG_DEBUG,
+                                          "EAP-PEAP: External certificate check failed - force authentication failure");
+                               ret->methodState = METHOD_DONE;
+                               ret->decision = DECISION_FAIL;
+                               sm->waiting_ext_cert_check = 0;
+                               return NULL;
+                       }
+
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-PEAP: Continuing to wait external server certificate validation");
+                       return NULL;
+               }
+
                res = eap_peer_tls_process_helper(sm, &data->ssl,
                                                  EAP_TYPE_PEAP,
                                                  data->peap_version, id, &msg,
@@ -1018,6 +1048,16 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
                        ret->decision = DECISION_FAIL;
                        return resp;
                }
+
+
+               if (sm->waiting_ext_cert_check) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-PEAP: Waiting external server certificate validation");
+                       wpabuf_free(data->pending_resp);
+                       data->pending_resp = resp;
+                       return NULL;
+               }
+
                if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
                        char *label;
                        wpa_printf(MSG_DEBUG,
@@ -1123,6 +1163,8 @@ static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
        struct eap_peap_data *data = priv;
        wpabuf_free(data->pending_phase2_req);
        data->pending_phase2_req = NULL;
+       wpabuf_free(data->pending_resp);
+       data->pending_resp = NULL;
        data->crypto_binding_used = 0;
 }
 
index 66a027a626e0dba5cac6f1673689ccca25d58c69..ba8e74b55f26f9da1db4cb0105f7ddb89511e747 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * EAP peer method: EAP-TLS (RFC 2716)
- * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -25,6 +25,7 @@ struct eap_tls_data {
        size_t id_len;
        void *ssl_ctx;
        u8 eap_type;
+       struct wpabuf *pending_resp;
 };
 
 
@@ -142,6 +143,7 @@ static void eap_tls_deinit(struct eap_sm *sm, void *priv)
        eap_peer_tls_ssl_deinit(sm, &data->ssl);
        eap_tls_free_key(data);
        os_free(data->session_id);
+       wpabuf_free(data->pending_resp);
        os_free(data);
 }
 
@@ -216,6 +218,32 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
        struct eap_tls_data *data = priv;
        struct wpabuf msg;
 
+       if (sm->waiting_ext_cert_check && data->pending_resp) {
+               struct eap_peer_config *config = eap_get_config(sm);
+
+               if (config->pending_ext_cert_check == EXT_CERT_CHECK_GOOD) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-TLS: External certificate check succeeded - continue handshake");
+                       resp = data->pending_resp;
+                       data->pending_resp = NULL;
+                       sm->waiting_ext_cert_check = 0;
+                       return resp;
+               }
+
+               if (config->pending_ext_cert_check == EXT_CERT_CHECK_BAD) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-TLS: External certificate check failed - force authentication failure");
+                       ret->methodState = METHOD_DONE;
+                       ret->decision = DECISION_FAIL;
+                       sm->waiting_ext_cert_check = 0;
+                       return NULL;
+               }
+
+               wpa_printf(MSG_DEBUG,
+                          "EAP-TLS: Continuing to wait external server certificate validation");
+               return NULL;
+       }
+
        pos = eap_peer_tls_process_init(sm, &data->ssl, data->eap_type, ret,
                                        reqData, &left, &flags);
        if (pos == NULL)
@@ -237,6 +265,14 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
                return eap_tls_failure(sm, data, ret, res, resp, id);
        }
 
+       if (sm->waiting_ext_cert_check) {
+               wpa_printf(MSG_DEBUG,
+                          "EAP-TLS: Waiting external server certificate validation");
+               wpabuf_free(data->pending_resp);
+               data->pending_resp = resp;
+               return NULL;
+       }
+
        if (tls_connection_established(data->ssl_ctx, data->ssl.conn))
                eap_tls_success(sm, data, ret);
 
@@ -258,6 +294,10 @@ static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv)
 
 static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv)
 {
+       struct eap_tls_data *data = priv;
+
+       wpabuf_free(data->pending_resp);
+       data->pending_resp = NULL;
 }
 
 
index af2b7541d70168d909cc43b654fde4d3fd6d2a77..4b994fd3a479a779cc4307e5e89d6265346db47d 100644 (file)
@@ -80,6 +80,10 @@ static void eap_tls_params_flags(struct tls_connection_params *params,
                params->flags |= TLS_CONN_DISABLE_TLSv1_2;
        if (os_strstr(txt, "tls_disable_tlsv1_2=0"))
                params->flags &= ~TLS_CONN_DISABLE_TLSv1_2;
+       if (os_strstr(txt, "tls_ext_cert_check=1"))
+               params->flags |= TLS_CONN_EXT_CERT_CHECK;
+       if (os_strstr(txt, "tls_ext_cert_check=0"))
+               params->flags &= ~TLS_CONN_EXT_CERT_CHECK;
 }
 
 
@@ -177,6 +181,8 @@ static int eap_tls_params_from_conf(struct eap_sm *sm,
 
        params->openssl_ciphers = config->openssl_ciphers;
 
+       sm->ext_cert_check = !!(params->flags & TLS_CONN_EXT_CERT_CHECK);
+
        return 0;
 }
 
index b186c9156a741a03f3641c15c42903259bc6fc92..9741dedefb84af22c8f94fec1bb19e9c0f352bf4 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * EAP peer method: EAP-TTLS (RFC 5281)
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -58,6 +58,7 @@ struct eap_ttls_data {
        size_t id_len;
 
        struct wpabuf *pending_phase2_req;
+       struct wpabuf *pending_resp;
 
 #ifdef EAP_TNC
        int ready_for_tnc;
@@ -153,6 +154,7 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
        eap_ttls_free_key(data);
        os_free(data->session_id);
        wpabuf_free(data->pending_phase2_req);
+       wpabuf_free(data->pending_resp);
        os_free(data);
 }
 
@@ -1408,6 +1410,32 @@ static int eap_ttls_process_handshake(struct eap_sm *sm,
 {
        int res;
 
+       if (sm->waiting_ext_cert_check && data->pending_resp) {
+               struct eap_peer_config *config = eap_get_config(sm);
+
+               if (config->pending_ext_cert_check == EXT_CERT_CHECK_GOOD) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-TTLS: External certificate check succeeded - continue handshake");
+                       *out_data = data->pending_resp;
+                       data->pending_resp = NULL;
+                       sm->waiting_ext_cert_check = 0;
+                       return 0;
+               }
+
+               if (config->pending_ext_cert_check == EXT_CERT_CHECK_BAD) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-TTLS: External certificate check failed - force authentication failure");
+                       ret->methodState = METHOD_DONE;
+                       ret->decision = DECISION_FAIL;
+                       sm->waiting_ext_cert_check = 0;
+                       return 0;
+               }
+
+               wpa_printf(MSG_DEBUG,
+                          "EAP-TTLS: Continuing to wait external server certificate validation");
+               return 0;
+       }
+
        res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS,
                                          data->ttls_version, identifier,
                                          in_data, out_data);
@@ -1418,6 +1446,15 @@ static int eap_ttls_process_handshake(struct eap_sm *sm,
                return -1;
        }
 
+       if (sm->waiting_ext_cert_check) {
+               wpa_printf(MSG_DEBUG,
+                          "EAP-TTLS: Waiting external server certificate validation");
+               wpabuf_free(data->pending_resp);
+               data->pending_resp = *out_data;
+               *out_data = NULL;
+               return 0;
+       }
+
        if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
                wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS done, proceed to "
                           "Phase 2");
@@ -1557,6 +1594,8 @@ static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv)
        struct eap_ttls_data *data = priv;
        wpabuf_free(data->pending_phase2_req);
        data->pending_phase2_req = NULL;
+       wpabuf_free(data->pending_resp);
+       data->pending_resp = NULL;
 #ifdef EAP_TNC
        data->ready_for_tnc = 0;
        data->tnc_started = 0;
index 580fbe8a115b6e3ef1fe1cc8db51d036bae15f2b..6e2d18073642995b02dec9a90125b64566bc321b 100644 (file)
@@ -5556,6 +5556,16 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
                if (wpa_s->wpa_state == WPA_SCANNING && !wpa_s->scanning)
                        wpa_supplicant_req_scan(wpa_s, 0, 0);
                break;
+       case WPA_CTRL_REQ_EXT_CERT_CHECK:
+               if (eap->pending_ext_cert_check != PENDING_CHECK)
+                       return -1;
+               if (os_strcmp(value, "good") == 0)
+                       eap->pending_ext_cert_check = EXT_CERT_CHECK_GOOD;
+               else if (os_strcmp(value, "bad") == 0)
+                       eap->pending_ext_cert_check = EXT_CERT_CHECK_BAD;
+               else
+                       return -1;
+               break;
        default:
                wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
                return -1;
index 2ce1cc4e376c45351de36337bf4ee25a03ab6873..e33b720aa7c0543dfbd532c97e7cb49cd0f8ac90 100644 (file)
@@ -1037,6 +1037,12 @@ fast_reauth=1
 #      that have issues interoperating with updated TLS version)
 # tls_disable_tlsv1_2=1 - disable use of TLSv1.2 (a workaround for AAA servers
 #      that have issues interoperating with updated TLS version)
+# tls_ext_cert_check=0 - No external server certificate validation (default)
+# tls_ext_cert_check=1 - External server certificate validation enabled; this
+#      requires an external program doing validation of server certificate
+#      chain when receiving CTRL-RSP-EXT_CERT_CHECK event from the control
+#      interface and report the result of the validation with
+#      CTRL-RSP_EXT_CERT_CHECK.
 #
 # Following certificate/private key fields are used in inner Phase2
 # authentication when using EAP-TTLS or EAP-PEAP.
index 7986695aad21b0534a3f1cb65f5f88355bade019..f84c8b90ac2fc1fe772db932a5bdddc85ef616ec 100644 (file)
@@ -739,6 +739,8 @@ enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field)
                return WPA_CTRL_REQ_SIM;
        else if (os_strcmp(field, "PSK_PASSPHRASE") == 0)
                return WPA_CTRL_REQ_PSK_PASSPHRASE;
+       else if (os_strcmp(field, "EXT_CERT_CHECK") == 0)
+               return WPA_CTRL_REQ_EXT_CERT_CHECK;
        return WPA_CTRL_REQ_UNKNOWN;
 }
 
@@ -782,6 +784,10 @@ const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field,
                *txt = "PSK or passphrase";
                ret = "PSK_PASSPHRASE";
                break;
+       case WPA_CTRL_REQ_EXT_CERT_CHECK:
+               *txt = "External server certificate validation";
+               ret = "EXT_CERT_CHECK";
+               break;
        default:
                break;
        }
@@ -837,6 +843,8 @@ static void wpa_supplicant_eap_param_needed(void *ctx,
        if (ssid == NULL)
                return;
 
+       if (field == WPA_CTRL_REQ_EXT_CERT_CHECK)
+               ssid->eap.pending_ext_cert_check = PENDING_CHECK;
        wpas_notify_network_request(wpa_s, ssid, field, default_txt);
 
        field_name = wpa_supplicant_ctrl_req_to_string(field, default_txt,