]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - src/crypto/tls_openssl.c
Use os_memdup()
[thirdparty/hostap.git] / src / crypto / tls_openssl.c
index de1b2c76b77a4c2ec1b135bc26589fd70db1af69..fc169e71e1e9c82533f13b13159d9ffa2484ee43 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <openssl/ssl.h>
 #include <openssl/err.h>
+#include <openssl/opensslv.h>
 #include <openssl/pkcs12.h>
 #include <openssl/x509v3.h>
 #ifndef OPENSSL_NO_ENGINE
 #include "sha1.h"
 #include "sha256.h"
 #include "tls.h"
+#include "tls_openssl.h"
 
-#if OPENSSL_VERSION_NUMBER < 0x10000000L
-/* ERR_remove_thread_state replaces ERR_remove_state and the latter is
- * deprecated. However, OpenSSL 0.9.8 doesn't include
- * ERR_remove_thread_state. */
-#define ERR_remove_thread_state(tid) ERR_remove_state(0)
+#if !defined(CONFIG_FIPS) &&                             \
+    (defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) ||   \
+     defined(EAP_SERVER_FAST))
+#define OPENSSL_NEED_EAP_FAST_PRF
 #endif
 
 #if defined(OPENSSL_IS_BORINGSSL)
@@ -57,6 +58,51 @@ typedef int stack_index_t;
 #endif /* OPENSSL_NO_TLSEXT */
 #endif /* SSL_set_tlsext_status_type */
 
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L || \
+     defined(LIBRESSL_VERSION_NUMBER)) &&    \
+    !defined(BORINGSSL_API_VERSION)
+/*
+ * SSL_get_client_random() and SSL_get_server_random() were added in OpenSSL
+ * 1.1.0 and newer BoringSSL revisions. Provide compatibility wrappers for
+ * older versions.
+ */
+
+static size_t SSL_get_client_random(const SSL *ssl, unsigned char *out,
+                                   size_t outlen)
+{
+       if (!ssl->s3 || outlen < SSL3_RANDOM_SIZE)
+               return 0;
+       os_memcpy(out, ssl->s3->client_random, SSL3_RANDOM_SIZE);
+       return SSL3_RANDOM_SIZE;
+}
+
+
+static size_t SSL_get_server_random(const SSL *ssl, unsigned char *out,
+                                   size_t outlen)
+{
+       if (!ssl->s3 || outlen < SSL3_RANDOM_SIZE)
+               return 0;
+       os_memcpy(out, ssl->s3->server_random, SSL3_RANDOM_SIZE);
+       return SSL3_RANDOM_SIZE;
+}
+
+
+#ifdef OPENSSL_NEED_EAP_FAST_PRF
+static size_t SSL_SESSION_get_master_key(const SSL_SESSION *session,
+                                        unsigned char *out, size_t outlen)
+{
+       if (!session || session->master_key_length < 0 ||
+           (size_t) session->master_key_length > outlen)
+               return 0;
+       if ((size_t) session->master_key_length < outlen)
+               outlen = session->master_key_length;
+       os_memcpy(out, session->master_key, outlen);
+       return outlen;
+}
+#endif /* OPENSSL_NEED_EAP_FAST_PRF */
+
+#endif
+
 #ifdef ANDROID
 #include <openssl/pem.h>
 #include <keystore/keystore_get.h>
@@ -71,9 +117,70 @@ static BIO * BIO_from_keystore(const char *key)
        free(value);
        return bio;
 }
+
+
+static int tls_add_ca_from_keystore(X509_STORE *ctx, const char *key_alias)
+{
+       BIO *bio = BIO_from_keystore(key_alias);
+       STACK_OF(X509_INFO) *stack = NULL;
+       stack_index_t i;
+
+       if (bio) {
+               stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
+               BIO_free(bio);
+       }
+
+       if (!stack) {
+               wpa_printf(MSG_WARNING, "TLS: Failed to parse certificate: %s",
+                          key_alias);
+               return -1;
+       }
+
+       for (i = 0; i < sk_X509_INFO_num(stack); ++i) {
+               X509_INFO *info = sk_X509_INFO_value(stack, i);
+
+               if (info->x509)
+                       X509_STORE_add_cert(ctx, info->x509);
+               if (info->crl)
+                       X509_STORE_add_crl(ctx, info->crl);
+       }
+
+       sk_X509_INFO_pop_free(stack, X509_INFO_free);
+
+       return 0;
+}
+
+
+static int tls_add_ca_from_keystore_encoded(X509_STORE *ctx,
+                                           const char *encoded_key_alias)
+{
+       int rc = -1;
+       int len = os_strlen(encoded_key_alias);
+       unsigned char *decoded_alias;
+
+       if (len & 1) {
+               wpa_printf(MSG_WARNING, "Invalid hex-encoded alias: %s",
+                          encoded_key_alias);
+               return rc;
+       }
+
+       decoded_alias = os_malloc(len / 2 + 1);
+       if (decoded_alias) {
+               if (!hexstr2bin(encoded_key_alias, decoded_alias, len / 2)) {
+                       decoded_alias[len / 2] = '\0';
+                       rc = tls_add_ca_from_keystore(
+                               ctx, (const char *) decoded_alias);
+               }
+               os_free(decoded_alias);
+       }
+
+       return rc;
+}
+
 #endif /* ANDROID */
 
 static int tls_openssl_ref_count = 0;
+static int tls_ex_idx_session = -1;
 
 struct tls_context {
        void (*event_cb)(void *ctx, enum tls_event ev,
@@ -86,12 +193,17 @@ struct tls_context {
 static struct tls_context *tls_global = NULL;
 
 
+struct tls_data {
+       SSL_CTX *ssl;
+       unsigned int tls_session_lifetime;
+};
+
 struct tls_connection {
        struct tls_context *context;
        SSL_CTX *ssl_ctx;
        SSL *ssl;
        BIO *ssl_in, *ssl_out;
-#ifndef OPENSSL_NO_ENGINE
+#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
        ENGINE *engine;        /* functional reference to the engine */
        EVP_PKEY *private_key; /* the private key if using engine */
 #endif /* OPENSSL_NO_ENGINE */
@@ -109,6 +221,7 @@ struct tls_connection {
        unsigned int cert_probe:1;
        unsigned int server_cert_only:1;
        unsigned int invalid_hb_used:1;
+       unsigned int success_data:1;
 
        u8 srv_cert_hash[32];
 
@@ -118,10 +231,8 @@ struct tls_connection {
        X509 *peer_issuer;
        X509 *peer_issuer_issuer;
 
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
        unsigned char client_random[SSL3_RANDOM_SIZE];
        unsigned char server_random[SSL3_RANDOM_SIZE];
-#endif
 };
 
 
@@ -519,7 +630,8 @@ static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name)
                wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for "
                           "system certificate store: subject='%s'", buf);
 
-               if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+               if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx),
+                                        cert)) {
                        tls_show_errors(MSG_WARNING, __func__,
                                        "Failed to add ca_cert to OpenSSL "
                                        "certificate store");
@@ -617,10 +729,16 @@ static int tls_engine_load_dynamic_generic(const char *pre[],
 
        engine = ENGINE_by_id(id);
        if (engine) {
-               ENGINE_free(engine);
                wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already "
                           "available", id);
-               return 0;
+               /*
+                * If it was auto-loaded by ENGINE_by_id() we might still
+                * need to tell it which PKCS#11 module to use in legacy
+                * (non-p11-kit) environments. Do so now; even if it was
+                * properly initialised before, setting it again will be
+                * harmless.
+                */
+               goto found;
        }
        ERR_clear_error();
 
@@ -657,7 +775,7 @@ static int tls_engine_load_dynamic_generic(const char *pre[],
                           id, ERR_error_string(ERR_get_error(), NULL));
                return -1;
        }
-
+ found:
        while (post && post[0]) {
                wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]);
                if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) {
@@ -744,8 +862,27 @@ static int tls_engine_load_dynamic_opensc(const char *opensc_so_path)
 #endif /* OPENSSL_NO_ENGINE */
 
 
+static void remove_session_cb(SSL_CTX *ctx, SSL_SESSION *sess)
+{
+       struct wpabuf *buf;
+
+       if (tls_ex_idx_session < 0)
+               return;
+       buf = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+       if (!buf)
+               return;
+       wpa_printf(MSG_DEBUG,
+                  "OpenSSL: Free application session data %p (sess %p)",
+                  buf, sess);
+       wpabuf_free(buf);
+
+       SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL);
+}
+
+
 void * tls_init(const struct tls_config *conf)
 {
+       struct tls_data *data;
        SSL_CTX *ssl;
        struct tls_context *context;
        const char *ciphers;
@@ -782,6 +919,7 @@ void * tls_init(const struct tls_config *conf)
                }
 #endif /* OPENSSL_FIPS */
 #endif /* CONFIG_FIPS */
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
                SSL_load_error_strings();
                SSL_library_init();
 #ifndef OPENSSL_NO_SHA256
@@ -803,6 +941,7 @@ void * tls_init(const struct tls_config *conf)
 #endif /* OPENSSL_NO_RC2 */
                PKCS12_PBE_add();
 #endif  /* PKCS12_FUNCS */
+#endif /* < 1.1.0 */
        } else {
                context = tls_context_new(conf);
                if (context == NULL)
@@ -810,7 +949,11 @@ void * tls_init(const struct tls_config *conf)
        }
        tls_openssl_ref_count++;
 
-       ssl = SSL_CTX_new(SSLv23_method());
+       data = os_zalloc(sizeof(*data));
+       if (data)
+               ssl = SSL_CTX_new(SSLv23_method());
+       else
+               ssl = NULL;
        if (ssl == NULL) {
                tls_openssl_ref_count--;
                if (context != tls_global)
@@ -819,14 +962,48 @@ void * tls_init(const struct tls_config *conf)
                        os_free(tls_global);
                        tls_global = NULL;
                }
+               os_free(data);
                return NULL;
        }
+       data->ssl = ssl;
+       if (conf)
+               data->tls_session_lifetime = conf->tls_session_lifetime;
 
        SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
        SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
 
+#ifdef SSL_MODE_NO_AUTO_CHAIN
+       /* Number of deployed use cases assume the default OpenSSL behavior of
+        * auto chaining the local certificate is in use. BoringSSL removed this
+        * functionality by default, so we need to restore it here to avoid
+        * breaking existing use cases. */
+       SSL_CTX_clear_mode(ssl, SSL_MODE_NO_AUTO_CHAIN);
+#endif /* SSL_MODE_NO_AUTO_CHAIN */
+
        SSL_CTX_set_info_callback(ssl, ssl_info_cb);
        SSL_CTX_set_app_data(ssl, context);
+       if (data->tls_session_lifetime > 0) {
+               SSL_CTX_set_quiet_shutdown(ssl, 1);
+               /*
+                * Set default context here. In practice, this will be replaced
+                * by the per-EAP method context in tls_connection_set_verify().
+                */
+               SSL_CTX_set_session_id_context(ssl, (u8 *) "hostapd", 7);
+               SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_SERVER);
+               SSL_CTX_set_timeout(ssl, data->tls_session_lifetime);
+               SSL_CTX_sess_set_remove_cb(ssl, remove_session_cb);
+       } else {
+               SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_OFF);
+       }
+
+       if (tls_ex_idx_session < 0) {
+               tls_ex_idx_session = SSL_SESSION_get_ex_new_index(
+                       0, NULL, NULL, NULL, NULL);
+               if (tls_ex_idx_session < 0) {
+                       tls_deinit(data);
+                       return NULL;
+               }
+       }
 
 #ifndef OPENSSL_NO_ENGINE
        wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
@@ -839,7 +1016,7 @@ void * tls_init(const struct tls_config *conf)
                if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) ||
                    tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path,
                                                   conf->pkcs11_module_path)) {
-                       tls_deinit(ssl);
+                       tls_deinit(data);
                        return NULL;
                }
        }
@@ -853,24 +1030,28 @@ void * tls_init(const struct tls_config *conf)
                wpa_printf(MSG_ERROR,
                           "OpenSSL: Failed to set cipher string '%s'",
                           ciphers);
-               tls_deinit(ssl);
+               tls_deinit(data);
                return NULL;
        }
 
-       return ssl;
+       return data;
 }
 
 
 void tls_deinit(void *ssl_ctx)
 {
-       SSL_CTX *ssl = ssl_ctx;
+       struct tls_data *data = ssl_ctx;
+       SSL_CTX *ssl = data->ssl;
        struct tls_context *context = SSL_CTX_get_app_data(ssl);
        if (context != tls_global)
                os_free(context);
+       if (data->tls_session_lifetime > 0)
+               SSL_CTX_flush_sessions(ssl, 0);
        SSL_CTX_free(ssl);
 
        tls_openssl_ref_count--;
        if (tls_openssl_ref_count == 0) {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
 #ifndef OPENSSL_NO_ENGINE
                ENGINE_cleanup();
 #endif /* OPENSSL_NO_ENGINE */
@@ -878,11 +1059,14 @@ void tls_deinit(void *ssl_ctx)
                ERR_remove_thread_state(NULL);
                ERR_free_strings();
                EVP_cleanup();
+#endif /* < 1.1.0 */
                os_free(tls_global->ocsp_stapling_response);
                tls_global->ocsp_stapling_response = NULL;
                os_free(tls_global);
                tls_global = NULL;
        }
+
+       os_free(data);
 }
 
 
@@ -907,10 +1091,32 @@ static int tls_is_pin_error(unsigned int err)
 #endif /* OPENSSL_NO_ENGINE */
 
 
+#ifdef ANDROID
+/* EVP_PKEY_from_keystore comes from system/security/keystore-engine. */
+EVP_PKEY * EVP_PKEY_from_keystore(const char *key_id);
+#endif /* ANDROID */
+
 static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
                           const char *pin, const char *key_id,
                           const char *cert_id, const char *ca_cert_id)
 {
+#if defined(ANDROID) && defined(OPENSSL_IS_BORINGSSL)
+#if !defined(OPENSSL_NO_ENGINE)
+#error "This code depends on OPENSSL_NO_ENGINE being defined by BoringSSL."
+#endif
+       if (!key_id)
+               return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+       conn->engine = NULL;
+       conn->private_key = EVP_PKEY_from_keystore(key_id);
+       if (!conn->private_key) {
+               wpa_printf(MSG_ERROR,
+                          "ENGINE: cannot load private key with id '%s' [%s]",
+                          key_id,
+                          ERR_error_string(ERR_get_error(), NULL));
+               return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+       }
+#endif /* ANDROID && OPENSSL_IS_BORINGSSL */
+
 #ifndef OPENSSL_NO_ENGINE
        int ret = -1;
        if (engine_id == NULL) {
@@ -1008,17 +1214,19 @@ err:
 
 static void tls_engine_deinit(struct tls_connection *conn)
 {
-#ifndef OPENSSL_NO_ENGINE
+#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
        wpa_printf(MSG_DEBUG, "ENGINE: engine deinit");
        if (conn->private_key) {
                EVP_PKEY_free(conn->private_key);
                conn->private_key = NULL;
        }
        if (conn->engine) {
+#if !defined(OPENSSL_IS_BORINGSSL)
                ENGINE_finish(conn->engine);
+#endif /* !OPENSSL_IS_BORINGSSL */
                conn->engine = NULL;
        }
-#endif /* OPENSSL_NO_ENGINE */
+#endif /* ANDROID || !OPENSSL_NO_ENGINE */
 }
 
 
@@ -1037,14 +1245,83 @@ int tls_get_errors(void *ssl_ctx)
 }
 
 
+static const char * openssl_content_type(int content_type)
+{
+       switch (content_type) {
+       case 20:
+               return "change cipher spec";
+       case 21:
+               return "alert";
+       case 22:
+               return "handshake";
+       case 23:
+               return "application data";
+       case 24:
+               return "heartbeat";
+       case 256:
+               return "TLS header info"; /* pseudo content type */
+       default:
+               return "?";
+       }
+}
+
+
+static const char * openssl_handshake_type(int content_type, const u8 *buf,
+                                          size_t len)
+{
+       if (content_type != 22 || !buf || len == 0)
+               return "";
+       switch (buf[0]) {
+       case 0:
+               return "hello request";
+       case 1:
+               return "client hello";
+       case 2:
+               return "server hello";
+       case 4:
+               return "new session ticket";
+       case 11:
+               return "certificate";
+       case 12:
+               return "server key exchange";
+       case 13:
+               return "certificate request";
+       case 14:
+               return "server hello done";
+       case 15:
+               return "certificate verify";
+       case 16:
+               return "client key exchange";
+       case 20:
+               return "finished";
+       case 21:
+               return "certificate url";
+       case 22:
+               return "certificate status";
+       default:
+               return "?";
+       }
+}
+
+
 static void tls_msg_cb(int write_p, int version, int content_type,
                       const void *buf, size_t len, SSL *ssl, void *arg)
 {
        struct tls_connection *conn = arg;
        const u8 *pos = buf;
 
-       wpa_printf(MSG_DEBUG, "OpenSSL: %s ver=0x%x content_type=%d",
-                  write_p ? "TX" : "RX", version, content_type);
+       if (write_p == 2) {
+               wpa_printf(MSG_DEBUG,
+                          "OpenSSL: session ver=0x%x content_type=%d",
+                          version, content_type);
+               wpa_hexdump_key(MSG_MSGDUMP, "OpenSSL: Data", buf, len);
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "OpenSSL: %s ver=0x%x content_type=%d (%s/%s)",
+                  write_p ? "TX" : "RX", version, content_type,
+                  openssl_content_type(content_type),
+                  openssl_handshake_type(content_type, buf, len));
        wpa_hexdump_key(MSG_MSGDUMP, "OpenSSL: Message", buf, len);
        if (content_type == 24 && len >= 3 && pos[0] == 1) {
                size_t payload_len = WPA_GET_BE16(pos + 1);
@@ -1058,7 +1335,8 @@ static void tls_msg_cb(int write_p, int version, int content_type,
 
 struct tls_connection * tls_connection_init(void *ssl_ctx)
 {
-       SSL_CTX *ssl = ssl_ctx;
+       struct tls_data *data = ssl_ctx;
+       SSL_CTX *ssl = data->ssl;
        struct tls_connection *conn;
        long options;
        struct tls_context *context = SSL_CTX_get_app_data(ssl);
@@ -1066,7 +1344,7 @@ struct tls_connection * tls_connection_init(void *ssl_ctx)
        conn = os_zalloc(sizeof(*conn));
        if (conn == NULL)
                return NULL;
-       conn->ssl_ctx = ssl_ctx;
+       conn->ssl_ctx = ssl;
        conn->ssl = SSL_new(ssl);
        if (conn->ssl == NULL) {
                tls_show_errors(MSG_INFO, __func__,
@@ -1115,6 +1393,14 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
 {
        if (conn == NULL)
                return;
+       if (conn->success_data) {
+               /*
+                * Make sure ssl_clear_bad_session() does not remove this
+                * session.
+                */
+               SSL_set_quiet_shutdown(conn->ssl, 1);
+               SSL_shutdown(conn->ssl);
+       }
        SSL_free(conn->ssl);
        tls_engine_deinit(conn);
        os_free(conn->subject_match);
@@ -1165,6 +1451,8 @@ static int tls_match_altsubject_component(X509 *cert, int type,
                        found++;
        }
 
+       sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
+
        return found;
 }
 
@@ -1277,9 +1565,11 @@ static int tls_match_suffix(X509 *cert, const char *match, int full)
                    1) {
                        wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
                                   full ? "Match" : "Suffix match");
+                       sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
                        return 1;
                }
        }
+       sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
 
        if (dns_name) {
                wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched");
@@ -1420,7 +1710,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;
        }
@@ -1475,6 +1766,7 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
                pos += gen->d.ia5->length;
                *pos = '\0';
        }
+       sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
 
        for (alt = 0; alt < num_altsubject; alt++)
                ev.peer_cert.altsubject[alt] = altsubject[alt];
@@ -1632,7 +1924,33 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
                                       TLS_FAIL_SERVER_CHAIN_PROBE);
        }
 
-       if (preverify_ok && context->event_cb != NULL)
+#ifdef OPENSSL_IS_BORINGSSL
+       if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP) &&
+           preverify_ok) {
+               enum ocsp_result res;
+
+               res = check_ocsp_resp(conn->ssl_ctx, conn->ssl, err_cert,
+                                     conn->peer_issuer,
+                                     conn->peer_issuer_issuer);
+               if (res == OCSP_REVOKED) {
+                       preverify_ok = 0;
+                       openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+                                              "certificate revoked",
+                                              TLS_FAIL_REVOKED);
+                       if (err == X509_V_OK)
+                               X509_STORE_CTX_set_error(
+                                       x509_ctx, X509_V_ERR_CERT_REVOKED);
+               } else if (res != OCSP_GOOD &&
+                          (conn->flags & TLS_CONN_REQUIRE_OCSP)) {
+                       preverify_ok = 0;
+                       openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+                                              "bad certificate status response",
+                                              TLS_FAIL_UNSPECIFIED);
+               }
+       }
+#endif /* OPENSSL_IS_BORINGSSL */
+
+       if (depth == 0 && preverify_ok && context->event_cb != NULL)
                context->event_cb(context->cb_ctx,
                                  TLS_CERT_CHAIN_SUCCESS, NULL);
 
@@ -1641,9 +1959,9 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
 
 
 #ifndef OPENSSL_NO_STDIO
-static int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert)
+static int tls_load_ca_der(struct tls_data *data, const char *ca_cert)
 {
-       SSL_CTX *ssl_ctx = _ssl_ctx;
+       SSL_CTX *ssl_ctx = data->ssl;
        X509_LOOKUP *lookup;
        int ret = 0;
 
@@ -1673,11 +1991,12 @@ static int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert)
 #endif /* OPENSSL_NO_STDIO */
 
 
-static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
+static int tls_connection_ca_cert(struct tls_data *data,
+                                 struct tls_connection *conn,
                                  const char *ca_cert, const u8 *ca_cert_blob,
                                  size_t ca_cert_blob_len, const char *ca_path)
 {
-       SSL_CTX *ssl_ctx = _ssl_ctx;
+       SSL_CTX *ssl_ctx = data->ssl;
        X509_STORE *store;
 
        /*
@@ -1767,30 +2086,40 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
        }
 
 #ifdef ANDROID
+       /* Single alias */
        if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) {
-               BIO *bio = BIO_from_keystore(&ca_cert[11]);
-               STACK_OF(X509_INFO) *stack = NULL;
-               stack_index_t i;
-
-               if (bio) {
-                       stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
-                       BIO_free(bio);
-               }
-               if (!stack)
+               if (tls_add_ca_from_keystore(SSL_CTX_get_cert_store(ssl_ctx),
+                                            &ca_cert[11]) < 0)
                        return -1;
+               SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+               return 0;
+       }
 
-               for (i = 0; i < sk_X509_INFO_num(stack); ++i) {
-                       X509_INFO *info = sk_X509_INFO_value(stack, i);
-                       if (info->x509) {
-                               X509_STORE_add_cert(ssl_ctx->cert_store,
-                                                   info->x509);
-                       }
-                       if (info->crl) {
-                               X509_STORE_add_crl(ssl_ctx->cert_store,
-                                                  info->crl);
+       /* Multiple aliases separated by space */
+       if (ca_cert && os_strncmp("keystores://", ca_cert, 12) == 0) {
+               char *aliases = os_strdup(&ca_cert[12]);
+               const char *delim = " ";
+               int rc = 0;
+               char *savedptr;
+               char *alias;
+
+               if (!aliases)
+                       return -1;
+               alias = strtok_r(aliases, delim, &savedptr);
+               for (; alias; alias = strtok_r(NULL, delim, &savedptr)) {
+                       if (tls_add_ca_from_keystore_encoded(
+                                   SSL_CTX_get_cert_store(ssl_ctx), alias)) {
+                               wpa_printf(MSG_WARNING,
+                                          "OpenSSL: %s - Failed to add ca_cert %s from keystore",
+                                          __func__, alias);
+                               rc = -1;
+                               break;
                        }
                }
-               sk_X509_INFO_pop_free(stack, X509_INFO_free);
+               os_free(aliases);
+               if (rc)
+                       return rc;
+
                SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
                return 0;
        }
@@ -1812,7 +2141,7 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
                        tls_show_errors(MSG_WARNING, __func__,
                                        "Failed to load root certificates");
                        if (ca_cert &&
-                           tls_load_ca_der(ssl_ctx, ca_cert) == 0) {
+                           tls_load_ca_der(data, ca_cert) == 0) {
                                wpa_printf(MSG_DEBUG, "OpenSSL: %s - loaded "
                                           "DER format CA certificate",
                                           __func__);
@@ -1821,7 +2150,7 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
                } else {
                        wpa_printf(MSG_DEBUG, "TLS: Trusted root "
                                   "certificate(s) loaded");
-                       tls_get_errors(ssl_ctx);
+                       tls_get_errors(data);
                }
 #else /* OPENSSL_NO_STDIO */
                wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
@@ -1838,8 +2167,10 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
 }
 
 
-static int tls_global_ca_cert(SSL_CTX *ssl_ctx, const char *ca_cert)
+static int tls_global_ca_cert(struct tls_data *data, const char *ca_cert)
 {
+       SSL_CTX *ssl_ctx = data->ssl;
+
        if (ca_cert) {
                if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1)
                {
@@ -1867,7 +2198,8 @@ int tls_global_set_verify(void *ssl_ctx, int check_crl)
        int flags;
 
        if (check_crl) {
-               X509_STORE *cs = SSL_CTX_get_cert_store(ssl_ctx);
+               struct tls_data *data = ssl_ctx;
+               X509_STORE *cs = SSL_CTX_get_cert_store(data->ssl);
                if (cs == NULL) {
                        tls_show_errors(MSG_INFO, __func__, "Failed to get "
                                        "certificate store when enabling "
@@ -1925,10 +2257,42 @@ static int tls_connection_set_subject_match(struct tls_connection *conn,
 }
 
 
+static void tls_set_conn_flags(SSL *ssl, unsigned int flags)
+{
+#ifdef SSL_OP_NO_TICKET
+       if (flags & TLS_CONN_DISABLE_SESSION_TICKET)
+               SSL_set_options(ssl, SSL_OP_NO_TICKET);
+       else
+               SSL_clear_options(ssl, SSL_OP_NO_TICKET);
+#endif /* SSL_OP_NO_TICKET */
+
+#ifdef SSL_OP_NO_TLSv1
+       if (flags & TLS_CONN_DISABLE_TLSv1_0)
+               SSL_set_options(ssl, SSL_OP_NO_TLSv1);
+       else
+               SSL_clear_options(ssl, SSL_OP_NO_TLSv1);
+#endif /* SSL_OP_NO_TLSv1 */
+#ifdef SSL_OP_NO_TLSv1_1
+       if (flags & TLS_CONN_DISABLE_TLSv1_1)
+               SSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
+       else
+               SSL_clear_options(ssl, SSL_OP_NO_TLSv1_1);
+#endif /* SSL_OP_NO_TLSv1_1 */
+#ifdef SSL_OP_NO_TLSv1_2
+       if (flags & TLS_CONN_DISABLE_TLSv1_2)
+               SSL_set_options(ssl, SSL_OP_NO_TLSv1_2);
+       else
+               SSL_clear_options(ssl, SSL_OP_NO_TLSv1_2);
+#endif /* SSL_OP_NO_TLSv1_2 */
+}
+
+
 int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
-                             int verify_peer)
+                             int verify_peer, unsigned int flags,
+                             const u8 *session_ctx, size_t session_ctx_len)
 {
        static int counter = 0;
+       struct tls_data *data = ssl_ctx;
 
        if (conn == NULL)
                return -1;
@@ -1943,20 +2307,25 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
                SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
        }
 
+       tls_set_conn_flags(conn->ssl, flags);
+       conn->flags = flags;
+
        SSL_set_accept_state(conn->ssl);
 
-       /*
-        * Set session id context in order to avoid fatal errors when client
-        * tries to resume a session. However, set the context to a unique
-        * value in order to effectively disable session resumption for now
-        * since not all areas of the server code are ready for it (e.g.,
-        * EAP-TTLS needs special handling for Phase 2 after abbreviated TLS
-        * handshake).
-        */
-       counter++;
-       SSL_set_session_id_context(conn->ssl,
-                                  (const unsigned char *) &counter,
-                                  sizeof(counter));
+       if (data->tls_session_lifetime == 0) {
+               /*
+                * Set session id context to a unique value to make sure
+                * session resumption cannot be used either through session
+                * caching or TLS ticket extension.
+                */
+               counter++;
+               SSL_set_session_id_context(conn->ssl,
+                                          (const unsigned char *) &counter,
+                                          sizeof(counter));
+       } else if (session_ctx) {
+               SSL_set_session_id_context(conn->ssl, session_ctx,
+                                          session_ctx_len);
+       }
 
        return 0;
 }
@@ -1970,6 +2339,17 @@ static int tls_connection_client_cert(struct tls_connection *conn,
        if (client_cert == NULL && client_cert_blob == NULL)
                return 0;
 
+#ifdef PKCS12_FUNCS
+#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER)
+       /*
+        * Clear previously set extra chain certificates, if any, from PKCS#12
+        * processing in tls_parse_pkcs12() to allow OpenSSL to build a new
+        * chain properly.
+        */
+       SSL_CTX_clear_extra_chain_certs(conn->ssl_ctx);
+#endif /* OPENSSL_VERSION_NUMBER < 0x10002000L */
+#endif /* PKCS12_FUNCS */
+
        if (client_cert_blob &&
            SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob,
                                     client_cert_blob_len) == 1) {
@@ -1991,13 +2371,24 @@ static int tls_connection_client_cert(struct tls_connection *conn,
                int ret = -1;
                if (bio) {
                        x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
-                       BIO_free(bio);
                }
                if (x509) {
                        if (SSL_use_certificate(conn->ssl, x509) == 1)
                                ret = 0;
                        X509_free(x509);
                }
+
+               /* Read additional certificates into the chain. */
+               while (bio) {
+                       x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+                       if (x509) {
+                               /* Takes ownership of x509 */
+                               SSL_add0_chain_cert(conn->ssl, x509);
+                       } else {
+                               BIO_free(bio);
+                               bio = NULL;
+                       }
+               }
                return ret;
        }
 #endif /* ANDROID */
@@ -2028,9 +2419,12 @@ static int tls_connection_client_cert(struct tls_connection *conn,
 }
 
 
-static int tls_global_client_cert(SSL_CTX *ssl_ctx, const char *client_cert)
+static int tls_global_client_cert(struct tls_data *data,
+                                 const char *client_cert)
 {
 #ifndef OPENSSL_NO_STDIO
+       SSL_CTX *ssl_ctx = data->ssl;
+
        if (client_cert == NULL)
                return 0;
 
@@ -2064,7 +2458,7 @@ static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
 
 
 #ifdef PKCS12_FUNCS
-static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12,
+static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
                            const char *passwd)
 {
        EVP_PKEY *pkey;
@@ -2095,7 +2489,7 @@ static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12,
                        if (SSL_use_certificate(ssl, cert) != 1)
                                res = -1;
                } else {
-                       if (SSL_CTX_use_certificate(ssl_ctx, cert) != 1)
+                       if (SSL_CTX_use_certificate(data->ssl, cert) != 1)
                                res = -1;
                }
                X509_free(cert);
@@ -2107,30 +2501,49 @@ static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12,
                        if (SSL_use_PrivateKey(ssl, pkey) != 1)
                                res = -1;
                } else {
-                       if (SSL_CTX_use_PrivateKey(ssl_ctx, pkey) != 1)
+                       if (SSL_CTX_use_PrivateKey(data->ssl, pkey) != 1)
                                res = -1;
                }
                EVP_PKEY_free(pkey);
        }
 
        if (certs) {
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L
-               SSL_clear_chain_certs(ssl);
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
+               if (ssl)
+                       SSL_clear_chain_certs(ssl);
+               else
+                       SSL_CTX_clear_chain_certs(data->ssl);
                while ((cert = sk_X509_pop(certs)) != NULL) {
                        X509_NAME_oneline(X509_get_subject_name(cert), buf,
                                          sizeof(buf));
                        wpa_printf(MSG_DEBUG, "TLS: additional certificate"
                                   " from PKCS12: subject='%s'", buf);
-                       if (SSL_add1_chain_cert(ssl, cert) != 1) {
+                       if ((ssl && SSL_add1_chain_cert(ssl, cert) != 1) ||
+                           (!ssl && SSL_CTX_add1_chain_cert(data->ssl,
+                                                            cert) != 1)) {
+                               tls_show_errors(MSG_DEBUG, __func__,
+                                               "Failed to add additional certificate");
                                res = -1;
+                               X509_free(cert);
                                break;
                        }
+                       X509_free(cert);
+               }
+               if (!res) {
+                       /* Try to continue anyway */
                }
-               sk_X509_free(certs);
+               sk_X509_pop_free(certs, X509_free);
 #ifndef OPENSSL_IS_BORINGSSL
-               res = SSL_build_cert_chain(ssl,
-                                          SSL_BUILD_CHAIN_FLAG_CHECK |
-                                          SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
+               if (ssl)
+                       res = SSL_build_cert_chain(
+                               ssl,
+                               SSL_BUILD_CHAIN_FLAG_CHECK |
+                               SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
+               else
+                       res = SSL_CTX_build_cert_chain(
+                               data->ssl,
+                               SSL_BUILD_CHAIN_FLAG_CHECK |
+                               SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
                if (!res) {
                        tls_show_errors(MSG_DEBUG, __func__,
                                        "Failed to build certificate chain");
@@ -2145,9 +2558,7 @@ static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12,
                 */
                res = 0;
 #else /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
-               SSL_CTX_clear_extra_chain_certs(ssl_ctx);
-#endif /* OPENSSL_VERSION_NUMBER >= 0x10001000L */
+               SSL_CTX_clear_extra_chain_certs(data->ssl);
                while ((cert = sk_X509_pop(certs)) != NULL) {
                        X509_NAME_oneline(X509_get_subject_name(cert), buf,
                                          sizeof(buf));
@@ -2157,27 +2568,29 @@ static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12,
                         * There is no SSL equivalent for the chain cert - so
                         * always add it to the context...
                         */
-                       if (SSL_CTX_add_extra_chain_cert(ssl_ctx, cert) != 1) {
+                       if (SSL_CTX_add_extra_chain_cert(data->ssl, cert) != 1)
+                       {
+                               X509_free(cert);
                                res = -1;
                                break;
                        }
                }
-               sk_X509_free(certs);
+               sk_X509_pop_free(certs, X509_free);
 #endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
        }
 
        PKCS12_free(p12);
 
        if (res < 0)
-               tls_get_errors(ssl_ctx);
+               tls_get_errors(data);
 
        return res;
 }
 #endif  /* PKCS12_FUNCS */
 
 
-static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key,
-                          const char *passwd)
+static int tls_read_pkcs12(struct tls_data *data, SSL *ssl,
+                          const char *private_key, const char *passwd)
 {
 #ifdef PKCS12_FUNCS
        FILE *f;
@@ -2196,7 +2609,7 @@ static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key,
                return -1;
        }
 
-       return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd);
+       return tls_parse_pkcs12(data, ssl, p12, passwd);
 
 #else /* PKCS12_FUNCS */
        wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot read "
@@ -2206,7 +2619,7 @@ static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key,
 }
 
 
-static int tls_read_pkcs12_blob(SSL_CTX *ssl_ctx, SSL *ssl,
+static int tls_read_pkcs12_blob(struct tls_data *data, SSL *ssl,
                                const u8 *blob, size_t len, const char *passwd)
 {
 #ifdef PKCS12_FUNCS
@@ -2219,7 +2632,7 @@ static int tls_read_pkcs12_blob(SSL_CTX *ssl_ctx, SSL *ssl,
                return -1;
        }
 
-       return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd);
+       return tls_parse_pkcs12(data, ssl, p12, passwd);
 
 #else /* PKCS12_FUNCS */
        wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot parse "
@@ -2290,13 +2703,13 @@ static int tls_connection_engine_client_cert(struct tls_connection *conn,
 }
 
 
-static int tls_connection_engine_ca_cert(void *_ssl_ctx,
+static int tls_connection_engine_ca_cert(struct tls_data *data,
                                         struct tls_connection *conn,
                                         const char *ca_cert_id)
 {
 #ifndef OPENSSL_NO_ENGINE
        X509 *cert;
-       SSL_CTX *ssl_ctx = _ssl_ctx;
+       SSL_CTX *ssl_ctx = data->ssl;
        X509_STORE *store;
 
        if (tls_engine_get_cert(conn, ca_cert_id, &cert))
@@ -2342,7 +2755,7 @@ static int tls_connection_engine_ca_cert(void *_ssl_ctx,
 
 static int tls_connection_engine_private_key(struct tls_connection *conn)
 {
-#ifndef OPENSSL_NO_ENGINE
+#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
        if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) {
                tls_show_errors(MSG_ERROR, __func__,
                                "ENGINE: cannot use private key for TLS");
@@ -2362,14 +2775,14 @@ static int tls_connection_engine_private_key(struct tls_connection *conn)
 }
 
 
-static int tls_connection_private_key(void *_ssl_ctx,
+static int tls_connection_private_key(struct tls_data *data,
                                      struct tls_connection *conn,
                                      const char *private_key,
                                      const char *private_key_passwd,
                                      const u8 *private_key_blob,
                                      size_t private_key_blob_len)
 {
-       SSL_CTX *ssl_ctx = _ssl_ctx;
+       SSL_CTX *ssl_ctx = data->ssl;
        char *passwd;
        int ok;
 
@@ -2415,7 +2828,7 @@ static int tls_connection_private_key(void *_ssl_ctx,
                        break;
                }
 
-               if (tls_read_pkcs12_blob(ssl_ctx, conn->ssl, private_key_blob,
+               if (tls_read_pkcs12_blob(data, conn->ssl, private_key_blob,
                                         private_key_blob_len, passwd) == 0) {
                        wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> "
                                   "OK");
@@ -2448,7 +2861,7 @@ static int tls_connection_private_key(void *_ssl_ctx,
                           __func__);
 #endif /* OPENSSL_NO_STDIO */
 
-               if (tls_read_pkcs12(ssl_ctx, conn->ssl, private_key, passwd)
+               if (tls_read_pkcs12(data, conn->ssl, private_key, passwd)
                    == 0) {
                        wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file "
                                   "--> OK");
@@ -2487,9 +2900,11 @@ static int tls_connection_private_key(void *_ssl_ctx,
 }
 
 
-static int tls_global_private_key(SSL_CTX *ssl_ctx, const char *private_key,
+static int tls_global_private_key(struct tls_data *data,
+                                 const char *private_key,
                                  const char *private_key_passwd)
 {
+       SSL_CTX *ssl_ctx = data->ssl;
        char *passwd;
 
        if (private_key == NULL)
@@ -2511,7 +2926,7 @@ static int tls_global_private_key(SSL_CTX *ssl_ctx, const char *private_key,
            SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
                                        SSL_FILETYPE_PEM) != 1 &&
 #endif /* OPENSSL_NO_STDIO */
-           tls_read_pkcs12(ssl_ctx, NULL, private_key, passwd)) {
+           tls_read_pkcs12(data, NULL, private_key, passwd)) {
                tls_show_errors(MSG_INFO, __func__,
                                "Failed to load private key");
                os_free(passwd);
@@ -2606,7 +3021,7 @@ static int tls_connection_dh(struct tls_connection *conn, const char *dh_file)
 }
 
 
-static int tls_global_dh(SSL_CTX *ssl_ctx, const char *dh_file)
+static int tls_global_dh(struct tls_data *data, const char *dh_file)
 {
 #ifdef OPENSSL_NO_DH
        if (dh_file == NULL)
@@ -2615,6 +3030,7 @@ static int tls_global_dh(SSL_CTX *ssl_ctx, const char *dh_file)
                   "dh_file specified");
        return -1;
 #else /* OPENSSL_NO_DH */
+       SSL_CTX *ssl_ctx = data->ssl;
        DH *dh;
        BIO *bio;
 
@@ -2688,16 +3104,6 @@ int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
        if (conn == NULL || keys == NULL)
                return -1;
        ssl = conn->ssl;
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-       if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL)
-               return -1;
-
-       os_memset(keys, 0, sizeof(*keys));
-       keys->client_random = ssl->s3->client_random;
-       keys->client_random_len = SSL3_RANDOM_SIZE;
-       keys->server_random = ssl->s3->server_random;
-       keys->server_random_len = SSL3_RANDOM_SIZE;
-#else
        if (ssl == NULL)
                return -1;
 
@@ -2708,16 +3114,15 @@ int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
        keys->server_random = conn->server_random;
        keys->server_random_len = SSL_get_server_random(
                ssl, conn->server_random, sizeof(conn->server_random));
-#endif
 
        return 0;
 }
 
 
-#ifndef CONFIG_FIPS
+#ifdef OPENSSL_NEED_EAP_FAST_PRF
 static int openssl_get_keyblock_size(SSL *ssl)
 {
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
        const EVP_CIPHER *c;
        const EVP_MD *h;
        int md_size;
@@ -2727,17 +3132,11 @@ static int openssl_get_keyblock_size(SSL *ssl)
                return -1;
 
        c = ssl->enc_read_ctx->cipher;
-#if OPENSSL_VERSION_NUMBER >= 0x00909000L
        h = EVP_MD_CTX_md(ssl->read_hash);
-#else
-       h = ssl->read_hash;
-#endif
        if (h)
                md_size = EVP_MD_size(h);
-#if OPENSSL_VERSION_NUMBER >= 0x10000000L
        else if (ssl->s3)
                md_size = ssl->s3->tmp.new_mac_secret_size;
-#endif
        else
                return -1;
 
@@ -2775,86 +3174,24 @@ static int openssl_get_keyblock_size(SSL *ssl)
                    EVP_CIPHER_iv_length(c));
 #endif
 }
-#endif /* CONFIG_FIPS */
+#endif /* OPENSSL_NEED_EAP_FAST_PRF */
 
 
-static int openssl_tls_prf(void *tls_ctx, struct tls_connection *conn,
-                          const char *label, int server_random_first,
-                          int skip_keyblock, u8 *out, size_t out_len)
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+                             const char *label, u8 *out, size_t out_len)
 {
-#ifdef CONFIG_FIPS
-       wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS "
-                  "mode");
-       return -1;
-#else /* CONFIG_FIPS */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-       SSL *ssl;
-       u8 *rnd;
-       int ret = -1;
-       int skip = 0;
-       u8 *tmp_out = NULL;
-       u8 *_out = out;
-       const char *ver;
-
-       /*
-        * TLS library did not support key generation, so get the needed TLS
-        * session parameters and use an internal implementation of TLS PRF to
-        * derive the key.
-        */
-
-       if (conn == NULL)
-               return -1;
-       ssl = conn->ssl;
-       if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL ||
-           ssl->session->master_key_length <= 0)
+       if (!conn ||
+           SSL_export_keying_material(conn->ssl, out, out_len, label,
+                                      os_strlen(label), NULL, 0, 0) != 1)
                return -1;
-       ver = SSL_get_version(ssl);
-
-       if (skip_keyblock) {
-               skip = openssl_get_keyblock_size(ssl);
-               if (skip < 0)
-                       return -1;
-               tmp_out = os_malloc(skip + out_len);
-               if (!tmp_out)
-                       return -1;
-               _out = tmp_out;
-       }
-
-       rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
-       if (!rnd) {
-               os_free(tmp_out);
-               return -1;
-       }
+       return 0;
+}
 
-       if (server_random_first) {
-               os_memcpy(rnd, ssl->s3->server_random, SSL3_RANDOM_SIZE);
-               os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->client_random,
-                       SSL3_RANDOM_SIZE);
-       } else {
-               os_memcpy(rnd, ssl->s3->client_random, SSL3_RANDOM_SIZE);
-               os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->server_random,
-                       SSL3_RANDOM_SIZE);
-       }
 
-       if (os_strcmp(ver, "TLSv1.2") == 0) {
-               tls_prf_sha256(ssl->session->master_key,
-                              ssl->session->master_key_length,
-                              label, rnd, 2 * SSL3_RANDOM_SIZE,
-                              _out, skip + out_len);
-               ret = 0;
-       } else if (tls_prf_sha1_md5(ssl->session->master_key,
-                                   ssl->session->master_key_length,
-                                   label, rnd, 2 * SSL3_RANDOM_SIZE,
-                                   _out, skip + out_len) == 0) {
-               ret = 0;
-       }
-       os_free(rnd);
-       if (ret == 0 && skip_keyblock)
-               os_memcpy(out, _out + skip, out_len);
-       bin_clear_free(tmp_out, skip);
-
-       return ret;
-#else
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+                                   u8 *out, size_t out_len)
+{
+#ifdef OPENSSL_NEED_EAP_FAST_PRF
        SSL *ssl;
        SSL_SESSION *sess;
        u8 *rnd;
@@ -2869,9 +3206,9 @@ static int openssl_tls_prf(void *tls_ctx, struct tls_connection *conn,
        const char *ver;
 
        /*
-        * TLS library did not support key generation, so get the needed TLS
-        * session parameters and use an internal implementation of TLS PRF to
-        * derive the key.
+        * TLS library did not support EAP-FAST key generation, so get the
+        * needed TLS session parameters and use an internal implementation of
+        * TLS PRF to derive the key.
         */
 
        if (conn == NULL)
@@ -2884,15 +3221,13 @@ static int openssl_tls_prf(void *tls_ctx, struct tls_connection *conn,
        if (!ver || !sess)
                return -1;
 
-       if (skip_keyblock) {
-               skip = openssl_get_keyblock_size(ssl);
-               if (skip < 0)
-                       return -1;
-               tmp_out = os_malloc(skip + out_len);
-               if (!tmp_out)
-                       return -1;
-               _out = tmp_out;
-       }
+       skip = openssl_get_keyblock_size(ssl);
+       if (skip < 0)
+               return -1;
+       tmp_out = os_malloc(skip + out_len);
+       if (!tmp_out)
+               return -1;
+       _out = tmp_out;
 
        rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
        if (!rnd) {
@@ -2905,59 +3240,31 @@ static int openssl_tls_prf(void *tls_ctx, struct tls_connection *conn,
        master_key_len = SSL_SESSION_get_master_key(sess, master_key,
                                                    sizeof(master_key));
 
-       if (server_random_first) {
-               os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE);
-               os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random,
-                         SSL3_RANDOM_SIZE);
-       } else {
-               os_memcpy(rnd, client_random, SSL3_RANDOM_SIZE);
-               os_memcpy(rnd + SSL3_RANDOM_SIZE, server_random,
-                         SSL3_RANDOM_SIZE);
-       }
+       os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE);
+       os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random, SSL3_RANDOM_SIZE);
 
        if (os_strcmp(ver, "TLSv1.2") == 0) {
                tls_prf_sha256(master_key, master_key_len,
-                              label, rnd, 2 * SSL3_RANDOM_SIZE,
+                              "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
                               _out, skip + out_len);
                ret = 0;
        } else if (tls_prf_sha1_md5(master_key, master_key_len,
-                                   label, rnd, 2 * SSL3_RANDOM_SIZE,
+                                   "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
                                    _out, skip + out_len) == 0) {
                ret = 0;
        }
        os_memset(master_key, 0, sizeof(master_key));
        os_free(rnd);
-       if (ret == 0 && skip_keyblock)
+       if (ret == 0)
                os_memcpy(out, _out + skip, out_len);
        bin_clear_free(tmp_out, skip);
 
        return ret;
-#endif
-#endif /* CONFIG_FIPS */
-}
-
-
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
-                      const char *label, int server_random_first,
-                      int skip_keyblock, u8 *out, size_t out_len)
-{
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
-       SSL *ssl;
-       if (conn == NULL)
-               return -1;
-       if (server_random_first || skip_keyblock)
-               return openssl_tls_prf(tls_ctx, conn, label,
-                                      server_random_first, skip_keyblock,
-                                      out, out_len);
-       ssl = conn->ssl;
-       if (SSL_export_keying_material(ssl, out, out_len, label,
-                                      os_strlen(label), NULL, 0, 0) == 1) {
-               wpa_printf(MSG_DEBUG, "OpenSSL: Using internal PRF");
-               return 0;
-       }
-#endif
-       return openssl_tls_prf(tls_ctx, conn, label, server_random_first,
-                              skip_keyblock, out, out_len);
+#else /* OPENSSL_NEED_EAP_FAST_PRF */
+       wpa_printf(MSG_ERROR,
+                  "OpenSSL: EAP-FAST keys cannot be exported in FIPS mode");
+       return -1;
+#endif /* OPENSSL_NEED_EAP_FAST_PRF */
 }
 
 
@@ -3216,18 +3523,14 @@ struct wpabuf * tls_connection_decrypt(void *tls_ctx,
 
 int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
 {
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
        return conn ? SSL_cache_hit(conn->ssl) : 0;
-#else
-       return conn ? conn->ssl->hit : 0;
-#endif
 }
 
 
 int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
                                   u8 *ciphers)
 {
-       char buf[100], *pos, *end;
+       char buf[500], *pos, *end;
        u8 *c;
        int ret;
 
@@ -3255,6 +3558,12 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
                case TLS_CIPHER_ANON_DH_AES128_SHA:
                        suite = "ADH-AES128-SHA";
                        break;
+               case TLS_CIPHER_RSA_DHE_AES256_SHA:
+                       suite = "DHE-RSA-AES256-SHA";
+                       break;
+               case TLS_CIPHER_AES256_SHA:
+                       suite = "AES256-SHA";
+                       break;
                default:
                        wpa_printf(MSG_DEBUG, "TLS: Unsupported "
                                   "cipher selection: %d", *c);
@@ -3270,7 +3579,7 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
 
        wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
 
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
 #if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
        if (os_strstr(buf, ":ADH-")) {
                /*
@@ -3563,10 +3872,12 @@ static int ocsp_resp_cb(SSL *s, void *arg)
                wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s",
                           (conn->flags & TLS_CONN_REQUIRE_OCSP) ? "" :
                           " (OCSP not required)");
+               OCSP_CERTID_free(id);
                OCSP_BASICRESP_free(basic);
                OCSP_RESPONSE_free(rsp);
                return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
        }
+       OCSP_CERTID_free(id);
 
        if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) {
                tls_show_errors(MSG_INFO, __func__,
@@ -3633,6 +3944,7 @@ static int ocsp_status_cb(SSL *s, void *arg)
 int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
                              const struct tls_connection_params *params)
 {
+       struct tls_data *data = tls_ctx;
        int ret;
        unsigned long err;
        int can_pkcs11 = 0;
@@ -3644,6 +3956,12 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
        if (conn == NULL)
                return -1;
 
+       if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
+               wpa_printf(MSG_INFO,
+                          "OpenSSL: ocsp=3 not supported");
+               return -1;
+       }
+
        /*
         * If the engine isn't explicitly configured, and any of the
         * cert/key fields are actually PKCS#11 URIs, then automatically
@@ -3675,7 +3993,7 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
                engine_id = "pkcs11";
 
 #if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
        if (params->flags & TLS_CONN_EAP_FAST) {
                wpa_printf(MSG_DEBUG,
                           "OpenSSL: Use TLSv1_method() for EAP-FAST");
@@ -3708,10 +4026,9 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
                return -1;
 
        if (engine_id && ca_cert_id) {
-               if (tls_connection_engine_ca_cert(tls_ctx, conn,
-                                                 ca_cert_id))
+               if (tls_connection_engine_ca_cert(data, conn, ca_cert_id))
                        return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
-       } else if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
+       } else if (tls_connection_ca_cert(data, conn, params->ca_cert,
                                          params->ca_cert_blob,
                                          params->ca_cert_blob_len,
                                          params->ca_path))
@@ -3729,7 +4046,7 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
                wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
                if (tls_connection_engine_private_key(conn))
                        return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
-       } else if (tls_connection_private_key(tls_ctx, conn,
+       } else if (tls_connection_private_key(data, conn,
                                              params->private_key,
                                              params->private_key_passwd,
                                              params->private_key_blob,
@@ -3753,37 +4070,16 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
                return -1;
        }
 
-#ifdef SSL_OP_NO_TICKET
-       if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
-               SSL_set_options(conn->ssl, SSL_OP_NO_TICKET);
-#ifdef SSL_clear_options
-       else
-               SSL_clear_options(conn->ssl, SSL_OP_NO_TICKET);
-#endif /* SSL_clear_options */
-#endif /*  SSL_OP_NO_TICKET */
-
-#ifdef SSL_OP_NO_TLSv1
-       if (params->flags & TLS_CONN_DISABLE_TLSv1_0)
-               SSL_set_options(conn->ssl, SSL_OP_NO_TLSv1);
-       else
-               SSL_clear_options(conn->ssl, SSL_OP_NO_TLSv1);
-#endif /* SSL_OP_NO_TLSv1 */
-#ifdef SSL_OP_NO_TLSv1_1
-       if (params->flags & TLS_CONN_DISABLE_TLSv1_1)
-               SSL_set_options(conn->ssl, SSL_OP_NO_TLSv1_1);
-       else
-               SSL_clear_options(conn->ssl, SSL_OP_NO_TLSv1_1);
-#endif /* SSL_OP_NO_TLSv1_1 */
-#ifdef SSL_OP_NO_TLSv1_2
-       if (params->flags & TLS_CONN_DISABLE_TLSv1_2)
-               SSL_set_options(conn->ssl, SSL_OP_NO_TLSv1_2);
-       else
-               SSL_clear_options(conn->ssl, SSL_OP_NO_TLSv1_2);
-#endif /* SSL_OP_NO_TLSv1_2 */
+       tls_set_conn_flags(conn->ssl, params->flags);
 
+#ifdef OPENSSL_IS_BORINGSSL
+       if (params->flags & TLS_CONN_REQUEST_OCSP) {
+               SSL_enable_ocsp_stapling(conn->ssl);
+       }
+#else /* OPENSSL_IS_BORINGSSL */
 #ifdef HAVE_OCSP
        if (params->flags & TLS_CONN_REQUEST_OCSP) {
-               SSL_CTX *ssl_ctx = tls_ctx;
+               SSL_CTX *ssl_ctx = data->ssl;
                SSL_set_tlsext_status_type(conn->ssl, TLSEXT_STATUSTYPE_ocsp);
                SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_resp_cb);
                SSL_CTX_set_tlsext_status_arg(ssl_ctx, conn);
@@ -3799,10 +4095,11 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
                           "OpenSSL: No OCSP support included - allow optional OCSP case to continue");
        }
 #endif /* HAVE_OCSP */
+#endif /* OPENSSL_IS_BORINGSSL */
 
        conn->flags = params->flags;
 
-       tls_get_errors(tls_ctx);
+       tls_get_errors(data);
 
        return 0;
 }
@@ -3811,7 +4108,8 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
 int tls_global_set_params(void *tls_ctx,
                          const struct tls_connection_params *params)
 {
-       SSL_CTX *ssl_ctx = tls_ctx;
+       struct tls_data *data = tls_ctx;
+       SSL_CTX *ssl_ctx = data->ssl;
        unsigned long err;
 
        while ((err = ERR_get_error())) {
@@ -3819,11 +4117,11 @@ int tls_global_set_params(void *tls_ctx,
                           __func__, ERR_error_string(err, NULL));
        }
 
-       if (tls_global_ca_cert(ssl_ctx, params->ca_cert) ||
-           tls_global_client_cert(ssl_ctx, params->client_cert) ||
-           tls_global_private_key(ssl_ctx, params->private_key,
+       if (tls_global_ca_cert(data, params->ca_cert) ||
+           tls_global_client_cert(data, params->client_cert) ||
+           tls_global_private_key(data, params->private_key,
                                   params->private_key_passwd) ||
-           tls_global_dh(ssl_ctx, params->dh_file)) {
+           tls_global_dh(data, params->dh_file)) {
                wpa_printf(MSG_INFO, "TLS: Failed to set global parameters");
                return -1;
        }
@@ -3839,10 +4137,8 @@ int tls_global_set_params(void *tls_ctx,
 #ifdef SSL_OP_NO_TICKET
        if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
                SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
-#ifdef SSL_CTX_clear_options
        else
                SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET);
-#endif /* SSL_clear_options */
 #endif /*  SSL_OP_NO_TICKET */
 
 #ifdef HAVE_OCSP
@@ -3865,7 +4161,7 @@ int tls_global_set_params(void *tls_ctx,
  * commented out unless explicitly needed for EAP-FAST in order to be able to
  * build this file with unmodified openssl. */
 
-#ifdef OPENSSL_IS_BORINGSSL
+#if (defined(OPENSSL_IS_BORINGSSL) || OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
 static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
                           STACK_OF(SSL_CIPHER) *peer_ciphers,
                           const SSL_CIPHER **cipher, void *arg)
@@ -3878,7 +4174,7 @@ static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
        struct tls_connection *conn = arg;
        int ret;
 
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
        if (conn == NULL || conn->session_ticket_cb == NULL)
                return 0;
 
@@ -3931,11 +4227,10 @@ static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data,
        wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
                    "extension", data, len);
 
-       conn->session_ticket = os_malloc(len);
+       conn->session_ticket = os_memdup(data, len);
        if (conn->session_ticket == NULL)
                return 0;
 
-       os_memcpy(conn->session_ticket, data, len);
        conn->session_ticket_len = len;
 
        return 1;
@@ -3973,7 +4268,80 @@ int tls_connection_set_session_ticket_cb(void *tls_ctx,
 
 int tls_get_library_version(char *buf, size_t buf_len)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+       return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
+                          OPENSSL_VERSION_TEXT,
+                          OpenSSL_version(OPENSSL_VERSION));
+#else
        return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
                           OPENSSL_VERSION_TEXT,
                           SSLeay_version(SSLEAY_VERSION));
+#endif
+}
+
+
+void tls_connection_set_success_data(struct tls_connection *conn,
+                                    struct wpabuf *data)
+{
+       SSL_SESSION *sess;
+       struct wpabuf *old;
+
+       if (tls_ex_idx_session < 0)
+               goto fail;
+       sess = SSL_get_session(conn->ssl);
+       if (!sess)
+               goto fail;
+       old = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+       if (old) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: Replacing old success data %p",
+                          old);
+               wpabuf_free(old);
+       }
+       if (SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1)
+               goto fail;
+
+       wpa_printf(MSG_DEBUG, "OpenSSL: Stored success data %p", data);
+       conn->success_data = 1;
+       return;
+
+fail:
+       wpa_printf(MSG_INFO, "OpenSSL: Failed to store success data");
+       wpabuf_free(data);
+}
+
+
+void tls_connection_set_success_data_resumed(struct tls_connection *conn)
+{
+       wpa_printf(MSG_DEBUG,
+                  "OpenSSL: Success data accepted for resumed session");
+       conn->success_data = 1;
+}
+
+
+const struct wpabuf *
+tls_connection_get_success_data(struct tls_connection *conn)
+{
+       SSL_SESSION *sess;
+
+       if (tls_ex_idx_session < 0 ||
+           !(sess = SSL_get_session(conn->ssl)))
+               return NULL;
+       return SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+}
+
+
+void tls_connection_remove_session(struct tls_connection *conn)
+{
+       SSL_SESSION *sess;
+
+       sess = SSL_get_session(conn->ssl);
+       if (!sess)
+               return;
+
+       if (SSL_CTX_remove_session(conn->ssl_ctx, sess) != 1)
+               wpa_printf(MSG_DEBUG,
+                          "OpenSSL: Session was not cached");
+       else
+               wpa_printf(MSG_DEBUG,
+                          "OpenSSL: Removed cached session to disable session resumption");
 }