]> 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 c2bb8c5ffd67d019547e3d4e81e095f8eb6d7517..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 <openssl/dh.h>
 #endif
 
-#ifdef OPENSSL_IS_BORINGSSL
-#include <openssl/asn1.h>
-#include <openssl/asn1t.h>
-#endif /* OPENSSL_IS_BORINGSSL */
-
 #include "common.h"
 #include "crypto.h"
 #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)
@@ -62,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>
@@ -76,6 +117,66 @@ 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;
@@ -130,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
 };
 
 
@@ -531,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");
@@ -629,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();
 
@@ -669,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) {
@@ -813,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
@@ -834,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)
@@ -854,6 +962,7 @@ void * tls_init(const struct tls_config *conf)
                        os_free(tls_global);
                        tls_global = NULL;
                }
+               os_free(data);
                return NULL;
        }
        data->ssl = ssl;
@@ -863,6 +972,14 @@ void * tls_init(const struct tls_config *conf)
        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) {
@@ -934,6 +1051,7 @@ void tls_deinit(void *ssl_ctx)
 
        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 */
@@ -941,6 +1059,7 @@ 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);
@@ -1332,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;
 }
 
@@ -1444,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");
@@ -1523,949 +1646,138 @@ static enum tls_fail_reason openssl_tls_fail_reason(int err)
 }
 
 
-static struct wpabuf * get_x509_cert(X509 *cert)
-{
-       struct wpabuf *buf;
-       u8 *tmp;
-
-       int cert_len = i2d_X509(cert, NULL);
-       if (cert_len <= 0)
-               return NULL;
-
-       buf = wpabuf_alloc(cert_len);
-       if (buf == NULL)
-               return NULL;
-
-       tmp = wpabuf_put(buf, cert_len);
-       i2d_X509(cert, &tmp);
-       return buf;
-}
-
-
-static void openssl_tls_fail_event(struct tls_connection *conn,
-                                  X509 *err_cert, int err, int depth,
-                                  const char *subject, const char *err_str,
-                                  enum tls_fail_reason reason)
-{
-       union tls_event_data ev;
-       struct wpabuf *cert = NULL;
-       struct tls_context *context = conn->context;
-
-       if (context->event_cb == NULL)
-               return;
-
-       cert = get_x509_cert(err_cert);
-       os_memset(&ev, 0, sizeof(ev));
-       ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ?
-               reason : openssl_tls_fail_reason(err);
-       ev.cert_fail.depth = depth;
-       ev.cert_fail.subject = subject;
-       ev.cert_fail.reason_txt = err_str;
-       ev.cert_fail.cert = cert;
-       context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
-       wpabuf_free(cert);
-}
-
-
-static void openssl_tls_cert_event(struct tls_connection *conn,
-                                  X509 *err_cert, int depth,
-                                  const char *subject)
-{
-       struct wpabuf *cert = NULL;
-       union tls_event_data ev;
-       struct tls_context *context = conn->context;
-       char *altsubject[TLS_MAX_ALT_SUBJECT];
-       int alt, num_altsubject = 0;
-       GENERAL_NAME *gen;
-       void *ext;
-       stack_index_t i;
-#ifdef CONFIG_SHA256
-       u8 hash[32];
-#endif /* CONFIG_SHA256 */
-
-       if (context->event_cb == NULL)
-               return;
-
-       os_memset(&ev, 0, sizeof(ev));
-       if (conn->cert_probe || context->cert_in_cb) {
-               cert = get_x509_cert(err_cert);
-               ev.peer_cert.cert = cert;
-       }
-#ifdef CONFIG_SHA256
-       if (cert) {
-               const u8 *addr[1];
-               size_t len[1];
-               addr[0] = wpabuf_head(cert);
-               len[0] = wpabuf_len(cert);
-               if (sha256_vector(1, addr, len, hash) == 0) {
-                       ev.peer_cert.hash = hash;
-                       ev.peer_cert.hash_len = sizeof(hash);
-               }
-       }
-#endif /* CONFIG_SHA256 */
-       ev.peer_cert.depth = depth;
-       ev.peer_cert.subject = subject;
-
-       ext = X509_get_ext_d2i(err_cert, NID_subject_alt_name, NULL, NULL);
-       for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
-               char *pos;
-
-               if (num_altsubject == TLS_MAX_ALT_SUBJECT)
-                       break;
-               gen = sk_GENERAL_NAME_value(ext, i);
-               if (gen->type != GEN_EMAIL &&
-                   gen->type != GEN_DNS &&
-                   gen->type != GEN_URI)
-                       continue;
-
-               pos = os_malloc(10 + gen->d.ia5->length + 1);
-               if (pos == NULL)
-                       break;
-               altsubject[num_altsubject++] = pos;
-
-               switch (gen->type) {
-               case GEN_EMAIL:
-                       os_memcpy(pos, "EMAIL:", 6);
-                       pos += 6;
-                       break;
-               case GEN_DNS:
-                       os_memcpy(pos, "DNS:", 4);
-                       pos += 4;
-                       break;
-               case GEN_URI:
-                       os_memcpy(pos, "URI:", 4);
-                       pos += 4;
-                       break;
-               }
-
-               os_memcpy(pos, gen->d.ia5->data, gen->d.ia5->length);
-               pos += gen->d.ia5->length;
-               *pos = '\0';
-       }
-
-       for (alt = 0; alt < num_altsubject; alt++)
-               ev.peer_cert.altsubject[alt] = altsubject[alt];
-       ev.peer_cert.num_altsubject = num_altsubject;
-
-       context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
-       wpabuf_free(cert);
-       for (alt = 0; alt < num_altsubject; alt++)
-               os_free(altsubject[alt]);
-}
-
-
-#ifdef OPENSSL_IS_BORINGSSL
-
-/*
- * CertID ::= SEQUENCE {
- *     hashAlgorithm      AlgorithmIdentifier,
- *     issuerNameHash     OCTET STRING, -- Hash of Issuer's DN
- *     issuerKeyHash      OCTET STRING, -- Hash of Issuer's public key
- *     serialNumber       CertificateSerialNumber }
- */
-typedef struct {
-       X509_ALGOR *hashAlgorithm;
-       ASN1_OCTET_STRING *issuerNameHash;
-       ASN1_OCTET_STRING *issuerKeyHash;
-       ASN1_INTEGER *serialNumber;
-} CertID;
-
-/*
- * ResponseBytes ::=       SEQUENCE {
- *     responseType   OBJECT IDENTIFIER,
- *     response       OCTET STRING }
- */
-typedef struct {
-       ASN1_OBJECT *responseType;
-       ASN1_OCTET_STRING *response;
-} ResponseBytes;
-
-/*
- * OCSPResponse ::= SEQUENCE {
- *    responseStatus         OCSPResponseStatus,
- *    responseBytes          [0] EXPLICIT ResponseBytes OPTIONAL }
- */
-typedef struct {
-       ASN1_ENUMERATED *responseStatus;
-       ResponseBytes *responseBytes;
-} OCSPResponse;
-
-ASN1_SEQUENCE(ResponseBytes) = {
-       ASN1_SIMPLE(ResponseBytes, responseType, ASN1_OBJECT),
-       ASN1_SIMPLE(ResponseBytes, response, ASN1_OCTET_STRING)
-} ASN1_SEQUENCE_END(ResponseBytes);
-
-ASN1_SEQUENCE(OCSPResponse) = {
-       ASN1_SIMPLE(OCSPResponse, responseStatus, ASN1_ENUMERATED),
-       ASN1_EXP_OPT(OCSPResponse, responseBytes, ResponseBytes, 0)
-} ASN1_SEQUENCE_END(OCSPResponse);
-
-IMPLEMENT_ASN1_FUNCTIONS(OCSPResponse);
-
-/*
- * ResponderID ::= CHOICE {
- *    byName               [1] Name,
- *    byKey                [2] KeyHash }
- */
-typedef struct {
-       int type;
-       union {
-               X509_NAME *byName;
-               ASN1_OCTET_STRING *byKey;
-       } value;
-} ResponderID;
-
-/*
- * RevokedInfo ::= SEQUENCE {
- *     revocationTime              GeneralizedTime,
- *     revocationReason    [0]     EXPLICIT CRLReason OPTIONAL }
- */
-typedef struct {
-       ASN1_GENERALIZEDTIME *revocationTime;
-       ASN1_ENUMERATED *revocationReason;
-} RevokedInfo;
-
-/*
- * CertStatus ::= CHOICE {
- *     good        [0]     IMPLICIT NULL,
- *     revoked     [1]     IMPLICIT RevokedInfo,
- *     unknown     [2]     IMPLICIT UnknownInfo }
- */
-typedef struct {
-       int type;
-       union {
-               ASN1_NULL *good;
-               RevokedInfo *revoked;
-               ASN1_NULL *unknown;
-       } value;
-} CertStatus;
-
-/*
- * SingleResponse ::= SEQUENCE {
- *    certID                       CertID,
- *    certStatus                   CertStatus,
- *    thisUpdate                   GeneralizedTime,
- *    nextUpdate         [0]       EXPLICIT GeneralizedTime OPTIONAL,
- *    singleExtensions   [1]       EXPLICIT Extensions OPTIONAL }
- */
-typedef struct {
-       CertID *certID;
-       CertStatus *certStatus;
-       ASN1_GENERALIZEDTIME *thisUpdate;
-       ASN1_GENERALIZEDTIME *nextUpdate;
-       STACK_OF(X509_EXTENSION) *singleExtensions;
-} SingleResponse;
-
-/*
- * ResponseData ::= SEQUENCE {
- *   version              [0] EXPLICIT Version DEFAULT v1,
- *   responderID              ResponderID,
- *   producedAt               GeneralizedTime,
- *   responses                SEQUENCE OF SingleResponse,
- *   responseExtensions   [1] EXPLICIT Extensions OPTIONAL }
- */
-typedef struct {
-       ASN1_INTEGER *version;
-       ResponderID *responderID;
-       ASN1_GENERALIZEDTIME *producedAt;
-       STACK_OF(SingleResponse) *responses;
-       STACK_OF(X509_EXTENSION) *responseExtensions;
-} ResponseData;
-
-/*
- * BasicOCSPResponse       ::= SEQUENCE {
- *   tbsResponseData      ResponseData,
- *   signatureAlgorithm   AlgorithmIdentifier,
- *   signature            BIT STRING,
- *   certs                [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
- */
-typedef struct {
-       ResponseData *tbsResponseData;
-       X509_ALGOR *signatureAlgorithm;
-       ASN1_BIT_STRING *signature;
-       STACK_OF(X509) *certs;
-} BasicOCSPResponse;
-
-ASN1_SEQUENCE(CertID) = {
-       ASN1_SIMPLE(CertID, hashAlgorithm, X509_ALGOR),
-       ASN1_SIMPLE(CertID, issuerNameHash, ASN1_OCTET_STRING),
-       ASN1_SIMPLE(CertID, issuerKeyHash, ASN1_OCTET_STRING),
-       ASN1_SIMPLE(CertID, serialNumber, ASN1_INTEGER)
-} ASN1_SEQUENCE_END(CertID);
-
-ASN1_CHOICE(ResponderID) = {
-       ASN1_EXP(ResponderID, value.byName, X509_NAME, 1),
-       ASN1_EXP(ResponderID, value.byKey, ASN1_OCTET_STRING, 2)
-} ASN1_CHOICE_END(ResponderID);
-
-ASN1_SEQUENCE(RevokedInfo) = {
-       ASN1_SIMPLE(RevokedInfo, revocationTime, ASN1_GENERALIZEDTIME),
-       ASN1_EXP_OPT(RevokedInfo, revocationReason, ASN1_ENUMERATED, 0)
-} ASN1_SEQUENCE_END(RevokedInfo);
-
-ASN1_CHOICE(CertStatus) = {
-       ASN1_IMP(CertStatus, value.good, ASN1_NULL, 0),
-       ASN1_IMP(CertStatus, value.revoked, RevokedInfo, 1),
-       ASN1_IMP(CertStatus, value.unknown, ASN1_NULL, 2)
-} ASN1_CHOICE_END(CertStatus);
-
-ASN1_SEQUENCE(SingleResponse) = {
-       ASN1_SIMPLE(SingleResponse, certID, CertID),
-       ASN1_SIMPLE(SingleResponse, certStatus, CertStatus),
-       ASN1_SIMPLE(SingleResponse, thisUpdate, ASN1_GENERALIZEDTIME),
-       ASN1_EXP_OPT(SingleResponse, nextUpdate, ASN1_GENERALIZEDTIME, 0),
-       ASN1_EXP_SEQUENCE_OF_OPT(SingleResponse, singleExtensions,
-                                X509_EXTENSION, 1)
-} ASN1_SEQUENCE_END(SingleResponse);
-
-ASN1_SEQUENCE(ResponseData) = {
-       ASN1_EXP_OPT(ResponseData, version, ASN1_INTEGER, 0),
-       ASN1_SIMPLE(ResponseData, responderID, ResponderID),
-       ASN1_SIMPLE(ResponseData, producedAt, ASN1_GENERALIZEDTIME),
-       ASN1_SEQUENCE_OF(ResponseData, responses, SingleResponse),
-       ASN1_EXP_SEQUENCE_OF_OPT(ResponseData, responseExtensions,
-                                X509_EXTENSION, 1)
-} ASN1_SEQUENCE_END(ResponseData);
-
-ASN1_SEQUENCE(BasicOCSPResponse) = {
-       ASN1_SIMPLE(BasicOCSPResponse, tbsResponseData, ResponseData),
-       ASN1_SIMPLE(BasicOCSPResponse, signatureAlgorithm, X509_ALGOR),
-       ASN1_SIMPLE(BasicOCSPResponse, signature, ASN1_BIT_STRING),
-       ASN1_EXP_SEQUENCE_OF_OPT(BasicOCSPResponse, certs, X509, 0)
-} ASN1_SEQUENCE_END(BasicOCSPResponse);
-
-IMPLEMENT_ASN1_FUNCTIONS(BasicOCSPResponse);
-
-#define sk_SingleResponse_num(sk) \
-sk_num(CHECKED_CAST(_STACK *, STACK_OF(SingleResponse) *, sk))
-
-#define sk_SingleResponse_value(sk, i) \
-       ((SingleResponse *)                                             \
-        sk_value(CHECKED_CAST(_STACK *, STACK_OF(SingleResponse) *, sk), (i)))
-
-
-static char * mem_bio_to_str(BIO *out)
-{
-       char *txt;
-       size_t rlen;
-       int res;
-
-       rlen = BIO_ctrl_pending(out);
-       txt = os_malloc(rlen + 1);
-       if (!txt) {
-               BIO_free(out);
-               return NULL;
-       }
-
-       res = BIO_read(out, txt, rlen);
-       BIO_free(out);
-       if (res < 0) {
-               os_free(txt);
-               return NULL;
-       }
-
-       txt[res] = '\0';
-       return txt;
-}
-
-
-static char * generalizedtime_str(ASN1_GENERALIZEDTIME *t)
-{
-       BIO *out;
-
-       out = BIO_new(BIO_s_mem());
-       if (!out)
-               return NULL;
-
-       if (!ASN1_GENERALIZEDTIME_print(out, t)) {
-               BIO_free(out);
-               return NULL;
-       }
-
-       return mem_bio_to_str(out);
-}
-
-
-static char * responderid_str(ResponderID *rid)
-{
-       BIO *out;
-
-       out = BIO_new(BIO_s_mem());
-       if (!out)
-               return NULL;
-
-       switch (rid->type) {
-       case 0:
-               X509_NAME_print_ex(out, rid->value.byName, 0, XN_FLAG_ONELINE);
-               break;
-       case 1:
-               i2a_ASN1_STRING(out, rid->value.byKey, V_ASN1_OCTET_STRING);
-               break;
-       default:
-               BIO_free(out);
-               return NULL;
-       }
-
-       return mem_bio_to_str(out);
-}
-
-
-static char * octet_string_str(ASN1_OCTET_STRING *o)
-{
-       BIO *out;
-
-       out = BIO_new(BIO_s_mem());
-       if (!out)
-               return NULL;
-
-       i2a_ASN1_STRING(out, o, V_ASN1_OCTET_STRING);
-       return mem_bio_to_str(out);
-}
-
-
-static char * integer_str(ASN1_INTEGER *i)
-{
-       BIO *out;
-
-       out = BIO_new(BIO_s_mem());
-       if (!out)
-               return NULL;
-
-       i2a_ASN1_INTEGER(out, i);
-       return mem_bio_to_str(out);
-}
-
-
-static char * algor_str(X509_ALGOR *alg)
-{
-       BIO *out;
-
-       out = BIO_new(BIO_s_mem());
-       if (!out)
-               return NULL;
-
-       i2a_ASN1_OBJECT(out, alg->algorithm);
-       return mem_bio_to_str(out);
-}
-
-
-static char * extensions_str(const char *title, STACK_OF(X509_EXTENSION) *ext)
-{
-       BIO *out;
-
-       if (!ext)
-               return NULL;
-
-       out = BIO_new(BIO_s_mem());
-       if (!out)
-               return NULL;
-
-       if (!X509V3_extensions_print(out, title, ext, 0, 0)) {
-               BIO_free(out);
-               return NULL;
-       }
-       return mem_bio_to_str(out);
-}
-
-
-static int ocsp_resp_valid(ASN1_GENERALIZEDTIME *thisupd,
-                          ASN1_GENERALIZEDTIME *nextupd)
-{
-       time_t now, tmp;
-
-       if (!ASN1_GENERALIZEDTIME_check(thisupd)) {
-               wpa_printf(MSG_DEBUG,
-                          "OpenSSL: Invalid OCSP response thisUpdate");
-               return 0;
-       }
-
-       time(&now);
-       tmp = now + 5 * 60; /* allow five minute clock difference */
-       if (X509_cmp_time(thisupd, &tmp) > 0) {
-               wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response not yet valid");
-               return 0;
-       }
-
-       if (!nextupd)
-               return 1; /* OK - no limit on response age */
-
-       if (!ASN1_GENERALIZEDTIME_check(nextupd)) {
-               wpa_printf(MSG_DEBUG,
-                          "OpenSSL: Invalid OCSP response nextUpdate");
-               return 0;
-       }
-
-       tmp = now - 5 * 60; /* allow five minute clock difference */
-       if (X509_cmp_time(nextupd, &tmp) < 0) {
-               wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response expired");
-               return 0;
-       }
-
-       if (ASN1_STRING_cmp(nextupd, thisupd) < 0) {
-               wpa_printf(MSG_DEBUG,
-                          "OpenSSL: OCSP response nextUpdate before thisUpdate");
-               return 0;
-       }
-
-       /* Both thisUpdate and nextUpdate are valid */
-       return -1;
-}
-
-
-static int issuer_match(X509 *cert, X509 *issuer, CertID *certid)
-{
-       X509_NAME *iname;
-       ASN1_BIT_STRING *ikey;
-       const EVP_MD *dgst;
-       unsigned int len;
-       unsigned char md[EVP_MAX_MD_SIZE];
-       ASN1_OCTET_STRING *hash;
-       char *txt;
-
-       dgst = EVP_get_digestbyobj(certid->hashAlgorithm->algorithm);
-       if (!dgst) {
-               wpa_printf(MSG_DEBUG,
-                          "OpenSSL: Could not find matching hash algorithm for OCSP");
-               return -1;
-       }
-
-       iname = X509_get_issuer_name(cert);
-       if (!X509_NAME_digest(iname, dgst, md, &len))
-               return -1;
-       hash = ASN1_OCTET_STRING_new();
-       if (!hash)
-               return -1;
-       if (!ASN1_OCTET_STRING_set(hash, md, len)) {
-               ASN1_OCTET_STRING_free(hash);
-               return -1;
-       }
-
-       txt = octet_string_str(hash);
-       if (txt) {
-               wpa_printf(MSG_DEBUG, "OpenSSL: calculated issuerNameHash: %s",
-                          txt);
-               os_free(txt);
-       }
-
-       if (ASN1_OCTET_STRING_cmp(certid->issuerNameHash, hash)) {
-               ASN1_OCTET_STRING_free(hash);
-               return -1;
-       }
-
-       ikey = X509_get0_pubkey_bitstr(issuer);
-       if (!EVP_Digest(ikey->data, ikey->length, md, &len, dgst, NULL) ||
-           !ASN1_OCTET_STRING_set(hash, md, len)) {
-               ASN1_OCTET_STRING_free(hash);
-               return -1;
-       }
-
-       txt = octet_string_str(hash);
-       if (txt) {
-               wpa_printf(MSG_DEBUG, "OpenSSL: calculated issuerKeyHash: %s",
-                          txt);
-               os_free(txt);
-       }
-
-       if (ASN1_OCTET_STRING_cmp(certid->issuerKeyHash, hash)) {
-               ASN1_OCTET_STRING_free(hash);
-               return -1;
-       }
-
-       ASN1_OCTET_STRING_free(hash);
-       return 0;
-}
-
-
-static X509 * ocsp_find_signer(STACK_OF(X509) *certs, ResponderID *rid)
-{
-       unsigned int i;
-       unsigned char hash[SHA_DIGEST_LENGTH];
-
-       if (rid->type == 0) {
-               /* byName */
-               return X509_find_by_subject(certs, rid->value.byName);
-       }
-
-       /* byKey */
-       if (rid->value.byKey->length != SHA_DIGEST_LENGTH)
-               return NULL;
-       for (i = 0; i < sk_X509_num(certs); i++) {
-               X509 *x = sk_X509_value(certs, i);
-
-               X509_pubkey_digest(x, EVP_sha1(), hash, NULL);
-               if (os_memcmp(rid->value.byKey->data, hash,
-                             SHA_DIGEST_LENGTH) == 0)
-                       return x;
-       }
-
-       return NULL;
-}
-
-
-enum ocsp_result {
-       OCSP_GOOD, OCSP_REVOKED, OCSP_NO_RESPONSE, OCSP_INVALID
-};
-
-static enum ocsp_result check_ocsp_resp(struct tls_connection *conn,
-                                       X509 *cert, X509 *issuer)
-{
-       const uint8_t *resp_data;
-       size_t resp_len;
-       OCSPResponse *resp;
-       int status;
-       ResponseBytes *bytes;
-       const u8 *basic_data;
-       size_t basic_len;
-       BasicOCSPResponse *basic;
-       ResponseData *rd;
-       char *txt;
-       int i, num;
-       unsigned int j, num_resp;
-       SingleResponse *matching_resp = NULL, *cmp_sresp;
-       enum ocsp_result result = OCSP_INVALID;
-       X509_STORE *store;
-       STACK_OF(X509) *untrusted = NULL, *certs = NULL, *chain = NULL;
-       X509_STORE_CTX ctx;
-       X509 *signer, *tmp_cert;
-       int signer_trusted = 0;
-       EVP_PKEY *skey;
-       int ret;
-       char buf[256];
-
-       txt = integer_str(X509_get_serialNumber(cert));
-       if (txt) {
-               wpa_printf(MSG_DEBUG,
-                          "OpenSSL: Searching OCSP response for peer certificate serialNumber: %s", txt);
-               os_free(txt);
-       }
-
-       SSL_get0_ocsp_response(conn->ssl, &resp_data, &resp_len);
-       if (resp_data == NULL || resp_len == 0) {
-               wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received");
-               return OCSP_NO_RESPONSE;
-       }
-
-       wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", resp_data, resp_len);
-
-       resp = d2i_OCSPResponse(NULL, &resp_data, resp_len);
-       if (!resp) {
-               wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSPResponse");
-               return OCSP_INVALID;
-       }
-
-       status = ASN1_ENUMERATED_get(resp->responseStatus);
-       if (status != 0) {
-               wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d",
-                          status);
-               return OCSP_INVALID;
-       }
-
-       bytes = resp->responseBytes;
-
-       if (!bytes ||
-           OBJ_obj2nid(bytes->responseType) != NID_id_pkix_OCSP_basic) {
-               wpa_printf(MSG_INFO,
-                          "OpenSSL: Could not find BasicOCSPResponse");
-               return OCSP_INVALID;
-       }
-
-       basic_data = ASN1_STRING_data(bytes->response);
-       basic_len = ASN1_STRING_length(bytes->response);
-       wpa_hexdump(MSG_DEBUG, "OpenSSL: BasicOCSPResponse",
-                   basic_data, basic_len);
-
-       basic = d2i_BasicOCSPResponse(NULL, &basic_data, basic_len);
-       if (!basic) {
-               wpa_printf(MSG_INFO,
-                          "OpenSSL: Could not parse BasicOCSPResponse");
-               OCSPResponse_free(resp);
-               return OCSP_INVALID;
-       }
-
-       rd = basic->tbsResponseData;
-
-       if (basic->certs) {
-               untrusted = sk_X509_dup(basic->certs);
-
-               num = sk_X509_num(basic->certs);
-               for (i = 0; i < num; i++) {
-                       X509 *extra_cert;
-
-                       extra_cert = sk_X509_value(basic->certs, i);
-                       X509_NAME_oneline(X509_get_subject_name(extra_cert),
-                                         buf, sizeof(buf));
-                       wpa_printf(MSG_DEBUG,
-                                  "OpenSSL: BasicOCSPResponse cert %s", buf);
-
-                       if (!sk_X509_push(untrusted, extra_cert)) {
-                               wpa_printf(MSG_DEBUG,
-                                          "OpenSSL: Could not add certificate to the untrusted stack");
-                       }
-               }
-       }
-
-       store = SSL_CTX_get_cert_store(conn->ssl_ctx);
-       if (conn->peer_issuer) {
-               if (X509_STORE_add_cert(store, conn->peer_issuer) != 1) {
-                       tls_show_errors(MSG_INFO, __func__,
-                                       "OpenSSL: Could not add issuer to certificate store");
-               }
-               certs = sk_X509_new_null();
-               if (certs) {
-                       tmp_cert = X509_dup(conn->peer_issuer);
-                       if (tmp_cert && !sk_X509_push(certs, tmp_cert)) {
-                               tls_show_errors(
-                                       MSG_INFO, __func__,
-                                       "OpenSSL: Could not add issuer to OCSP responder trust store");
-                               X509_free(tmp_cert);
-                               sk_X509_free(certs);
-                               certs = NULL;
-                       }
-                       if (certs && conn->peer_issuer_issuer) {
-                               tmp_cert = X509_dup(conn->peer_issuer_issuer);
-                               if (tmp_cert &&
-                                   !sk_X509_push(certs, tmp_cert)) {
-                                       tls_show_errors(
-                                               MSG_INFO, __func__,
-                                               "OpenSSL: Could not add issuer's issuer to OCSP responder trust store");
-                                       X509_free(tmp_cert);
-                               }
-                       }
-               }
-       }
-
-       signer = ocsp_find_signer(certs, rd->responderID);
-       if (!signer)
-               signer = ocsp_find_signer(untrusted, rd->responderID);
-       else
-               signer_trusted = 1;
-       if (!signer) {
-               wpa_printf(MSG_DEBUG,
-                          "OpenSSL: Could not find OCSP signer certificate");
-               goto fail;
-       }
-
-       skey = X509_get_pubkey(signer);
-       if (!skey) {
-               wpa_printf(MSG_DEBUG,
-                          "OpenSSL: Could not get OCSP signer public key");
-               goto fail;
-       }
-       if (ASN1_item_verify(ASN1_ITEM_rptr(ResponseData),
-                            basic->signatureAlgorithm, basic->signature,
-                            basic->tbsResponseData, skey) <= 0) {
-               wpa_printf(MSG_DEBUG,
-                          "OpenSSL: BasicOCSPResponse signature is invalid");
-               goto fail;
-       }
-
-       X509_NAME_oneline(X509_get_subject_name(signer), buf, sizeof(buf));
-       wpa_printf(MSG_DEBUG,
-                  "OpenSSL: Found OCSP signer certificate %s and verified BasicOCSPResponse signature",
-                  buf);
-
-       if (!X509_STORE_CTX_init(&ctx, store, signer, untrusted))
-               goto fail;
-       X509_STORE_CTX_set_purpose(&ctx, X509_PURPOSE_OCSP_HELPER);
-       ret = X509_verify_cert(&ctx);
-       chain = X509_STORE_CTX_get1_chain(&ctx);
-       X509_STORE_CTX_cleanup(&ctx);
-       if (ret <= 0) {
-               wpa_printf(MSG_DEBUG,
-                          "OpenSSL: Could not validate OCSP signer certificate");
-               goto fail;
-       }
-
-       if (!chain || sk_X509_num(chain) <= 0) {
-               wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP signer chain found");
-               goto fail;
-       }
-
-       if (!signer_trusted) {
-               X509_check_purpose(signer, -1, 0);
-               if ((signer->ex_flags & EXFLAG_XKUSAGE) &&
-                   (signer->ex_xkusage & XKU_OCSP_SIGN)) {
-                       wpa_printf(MSG_DEBUG,
-                                  "OpenSSL: OCSP signer certificate delegation OK");
-               } else {
-                       tmp_cert = sk_X509_value(chain, sk_X509_num(chain) - 1);
-                       if (X509_check_trust(tmp_cert, NID_OCSP_sign, 0) !=
-                           X509_TRUST_TRUSTED) {
-                               wpa_printf(MSG_DEBUG,
-                                          "OpenSSL: OCSP signer certificate not trusted");
-                               result = OCSP_NO_RESPONSE;
-                               goto fail;
-                       }
-               }
-       }
-
-       wpa_printf(MSG_DEBUG, "OpenSSL: OCSP version: %lu",
-                  ASN1_INTEGER_get(rd->version));
-
-       txt = responderid_str(rd->responderID);
-       if (txt) {
-               wpa_printf(MSG_DEBUG, "OpenSSL: OCSP responderID: %s",
-                          txt);
-               os_free(txt);
-       }
-
-       txt = generalizedtime_str(rd->producedAt);
-       if (txt) {
-               wpa_printf(MSG_DEBUG, "OpenSSL: OCSP producedAt: %s",
-                          txt);
-               os_free(txt);
-       }
-
-       num_resp = sk_SingleResponse_num(rd->responses);
-       if (num_resp == 0) {
-               wpa_printf(MSG_DEBUG,
-                          "OpenSSL: No OCSP SingleResponse within BasicOCSPResponse");
-               result = OCSP_NO_RESPONSE;
-               goto fail;
-       }
-       cmp_sresp = sk_SingleResponse_value(rd->responses, 0);
-       for (j = 0; j < num_resp; j++) {
-               SingleResponse *sresp;
-               CertID *cid1, *cid2;
-
-               sresp = sk_SingleResponse_value(rd->responses, j);
-               wpa_printf(MSG_DEBUG, "OpenSSL: OCSP SingleResponse %u/%u",
-                          j + 1, num_resp);
-
-               txt = algor_str(sresp->certID->hashAlgorithm);
-               if (txt) {
-                       wpa_printf(MSG_DEBUG,
-                                  "OpenSSL: certID hashAlgorithm: %s", txt);
-                       os_free(txt);
-               }
+static struct wpabuf * get_x509_cert(X509 *cert)
+{
+       struct wpabuf *buf;
+       u8 *tmp;
 
-               txt = octet_string_str(sresp->certID->issuerNameHash);
-               if (txt) {
-                       wpa_printf(MSG_DEBUG,
-                                  "OpenSSL: certID issuerNameHash: %s", txt);
-                       os_free(txt);
-               }
+       int cert_len = i2d_X509(cert, NULL);
+       if (cert_len <= 0)
+               return NULL;
 
-               txt = octet_string_str(sresp->certID->issuerKeyHash);
-               if (txt) {
-                       wpa_printf(MSG_DEBUG,
-                                  "OpenSSL: certID issuerKeyHash: %s", txt);
-                       os_free(txt);
-               }
+       buf = wpabuf_alloc(cert_len);
+       if (buf == NULL)
+               return NULL;
 
-               txt = integer_str(sresp->certID->serialNumber);
-               if (txt) {
-                       wpa_printf(MSG_DEBUG,
-                                  "OpenSSL: certID serialNumber: %s", txt);
-                       os_free(txt);
-               }
+       tmp = wpabuf_put(buf, cert_len);
+       i2d_X509(cert, &tmp);
+       return buf;
+}
 
-               switch (sresp->certStatus->type) {
-               case 0:
-                       wpa_printf(MSG_DEBUG, "OpenSSL: certStatus: good");
-                       break;
-               case 1:
-                       wpa_printf(MSG_DEBUG, "OpenSSL: certStatus: revoked");
-                       break;
-               default:
-                       wpa_printf(MSG_DEBUG, "OpenSSL: certStatus: unknown");
-                       break;
-               }
 
-               txt = generalizedtime_str(sresp->thisUpdate);
-               if (txt) {
-                       wpa_printf(MSG_DEBUG, "OpenSSL: thisUpdate: %s", txt);
-                       os_free(txt);
-               }
+static void openssl_tls_fail_event(struct tls_connection *conn,
+                                  X509 *err_cert, int err, int depth,
+                                  const char *subject, const char *err_str,
+                                  enum tls_fail_reason reason)
+{
+       union tls_event_data ev;
+       struct wpabuf *cert = NULL;
+       struct tls_context *context = conn->context;
 
-               if (sresp->nextUpdate) {
-                       txt = generalizedtime_str(sresp->nextUpdate);
-                       if (txt) {
-                               wpa_printf(MSG_DEBUG, "OpenSSL: nextUpdate: %s",
-                                          txt);
-                               os_free(txt);
-                       }
-               }
+       if (context->event_cb == NULL)
+               return;
 
-               txt = extensions_str("singleExtensions",
-                                    sresp->singleExtensions);
-               if (txt) {
-                       wpa_printf(MSG_DEBUG, "OpenSSL: %s", txt);
-                       os_free(txt);
-               }
+       cert = get_x509_cert(err_cert);
+       os_memset(&ev, 0, sizeof(ev));
+       ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ?
+               reason : openssl_tls_fail_reason(err);
+       ev.cert_fail.depth = depth;
+       ev.cert_fail.subject = subject;
+       ev.cert_fail.reason_txt = err_str;
+       ev.cert_fail.cert = cert;
+       context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
+       wpabuf_free(cert);
+}
 
-               cid1 = cmp_sresp->certID;
-               cid2 = sresp->certID;
-               if (j > 0 &&
-                   (OBJ_cmp(cid1->hashAlgorithm->algorithm,
-                            cid2->hashAlgorithm->algorithm) != 0 ||
-                    ASN1_OCTET_STRING_cmp(cid1->issuerNameHash,
-                                          cid2->issuerNameHash) != 0 ||
-                    ASN1_OCTET_STRING_cmp(cid1->issuerKeyHash,
-                                          cid2->issuerKeyHash) != 0)) {
-                       wpa_printf(MSG_DEBUG,
-                                  "OpenSSL: Different OCSP response issuer information between SingleResponse values within BasicOCSPResponse");
-                       goto fail;
-               }
 
-               if (!matching_resp && issuer &&
-                   ASN1_INTEGER_cmp(sresp->certID->serialNumber,
-                                    X509_get_serialNumber(cert)) == 0 &&
-                   issuer_match(cert, issuer, sresp->certID) == 0) {
-                       wpa_printf(MSG_DEBUG,
-                                  "OpenSSL: This response matches peer certificate");
-                       matching_resp = sresp;
+static void openssl_tls_cert_event(struct tls_connection *conn,
+                                  X509 *err_cert, int depth,
+                                  const char *subject)
+{
+       struct wpabuf *cert = NULL;
+       union tls_event_data ev;
+       struct tls_context *context = conn->context;
+       char *altsubject[TLS_MAX_ALT_SUBJECT];
+       int alt, num_altsubject = 0;
+       GENERAL_NAME *gen;
+       void *ext;
+       stack_index_t i;
+#ifdef CONFIG_SHA256
+       u8 hash[32];
+#endif /* CONFIG_SHA256 */
+
+       if (context->event_cb == NULL)
+               return;
+
+       os_memset(&ev, 0, sizeof(ev));
+       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;
+       }
+#ifdef CONFIG_SHA256
+       if (cert) {
+               const u8 *addr[1];
+               size_t len[1];
+               addr[0] = wpabuf_head(cert);
+               len[0] = wpabuf_len(cert);
+               if (sha256_vector(1, addr, len, hash) == 0) {
+                       ev.peer_cert.hash = hash;
+                       ev.peer_cert.hash_len = sizeof(hash);
                }
        }
+#endif /* CONFIG_SHA256 */
+       ev.peer_cert.depth = depth;
+       ev.peer_cert.subject = subject;
 
-       txt = extensions_str("responseExtensions", rd->responseExtensions);
-       if (txt) {
-               wpa_printf(MSG_DEBUG, "OpenSSL: %s", txt);
-               os_free(txt);
-       }
+       ext = X509_get_ext_d2i(err_cert, NID_subject_alt_name, NULL, NULL);
+       for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
+               char *pos;
 
-       if (!matching_resp) {
-               wpa_printf(MSG_DEBUG,
-                          "OpenSSL: Could not find OCSP response that matches the peer certificate");
-               result = OCSP_NO_RESPONSE;
-               goto fail;
-       }
+               if (num_altsubject == TLS_MAX_ALT_SUBJECT)
+                       break;
+               gen = sk_GENERAL_NAME_value(ext, i);
+               if (gen->type != GEN_EMAIL &&
+                   gen->type != GEN_DNS &&
+                   gen->type != GEN_URI)
+                       continue;
 
-       if (!ocsp_resp_valid(matching_resp->thisUpdate,
-                            matching_resp->nextUpdate)) {
-               wpa_printf(MSG_DEBUG,
-                          "OpenSSL: OCSP response not valid at this time");
-               goto fail;
-       }
+               pos = os_malloc(10 + gen->d.ia5->length + 1);
+               if (pos == NULL)
+                       break;
+               altsubject[num_altsubject++] = pos;
 
-       if (matching_resp->certStatus->type == 1) {
-               wpa_printf(MSG_DEBUG,
-                          "OpenSSL: OCSP response indicated that the peer certificate has been revoked");
-               result = OCSP_REVOKED;
-               goto fail;
-       }
+               switch (gen->type) {
+               case GEN_EMAIL:
+                       os_memcpy(pos, "EMAIL:", 6);
+                       pos += 6;
+                       break;
+               case GEN_DNS:
+                       os_memcpy(pos, "DNS:", 4);
+                       pos += 4;
+                       break;
+               case GEN_URI:
+                       os_memcpy(pos, "URI:", 4);
+                       pos += 4;
+                       break;
+               }
 
-       if (matching_resp->certStatus->type != 0) {
-               wpa_printf(MSG_DEBUG,
-                          "OpenSSL: OCSP response did not indicate good status");
-               result = OCSP_NO_RESPONSE;
-               goto fail;
+               os_memcpy(pos, gen->d.ia5->data, gen->d.ia5->length);
+               pos += gen->d.ia5->length;
+               *pos = '\0';
        }
+       sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
 
-       /* OCSP response indicated the certificate is good. */
-       result = OCSP_GOOD;
-fail:
-       sk_X509_pop_free(chain, X509_free);
-       sk_X509_free(untrusted);
-       sk_X509_pop_free(certs, X509_free);
-       BasicOCSPResponse_free(basic);
-       OCSPResponse_free(resp);
+       for (alt = 0; alt < num_altsubject; alt++)
+               ev.peer_cert.altsubject[alt] = altsubject[alt];
+       ev.peer_cert.num_altsubject = num_altsubject;
 
-       return result;
+       context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
+       wpabuf_free(cert);
+       for (alt = 0; alt < num_altsubject; alt++)
+               os_free(altsubject[alt]);
 }
 
-#endif /* OPENSSL_IS_BORINGSSL */
-
 
 static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
 {
@@ -2613,10 +1925,13 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
        }
 
 #ifdef OPENSSL_IS_BORINGSSL
-       if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP)) {
+       if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP) &&
+           preverify_ok) {
                enum ocsp_result res;
 
-               res = check_ocsp_resp(conn, err_cert, conn->peer_issuer);
+               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,
@@ -2635,7 +1950,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);
 
@@ -2771,30 +2086,40 @@ static int tls_connection_ca_cert(struct tls_data *data,
        }
 
 #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;
        }
@@ -2937,10 +2262,8 @@ 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);
-#ifdef SSL_clear_options
        else
                SSL_clear_options(ssl, SSL_OP_NO_TICKET);
-#endif /* SSL_clear_options */
 #endif /* SSL_OP_NO_TICKET */
 
 #ifdef SSL_OP_NO_TLSv1
@@ -3016,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) {
@@ -3037,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 */
@@ -3163,28 +2508,42 @@ static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
        }
 
        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");
@@ -3199,9 +2558,7 @@ static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
                 */
                res = 0;
 #else /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
                SSL_CTX_clear_extra_chain_certs(data->ssl);
-#endif /* OPENSSL_VERSION_NUMBER >= 0x10001000L */
                while ((cert = sk_X509_pop(certs)) != NULL) {
                        X509_NAME_oneline(X509_get_subject_name(cert), buf,
                                          sizeof(buf));
@@ -3213,11 +2570,12 @@ static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
                         */
                        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 */
        }
 
@@ -3746,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;
 
@@ -3766,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;
@@ -3785,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;
 
@@ -3833,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(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)
+       if (!conn ||
+           SSL_export_keying_material(conn->ssl, out, out_len, label,
+                                      os_strlen(label), NULL, 0, 0) != 1)
                return -1;
-       ssl = conn->ssl;
-       if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL ||
-           ssl->session->master_key_length <= 0)
-               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;
-       }
-
-       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);
-       }
+       return 0;
+}
 
-       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;
@@ -3927,9 +3206,9 @@ static int openssl_tls_prf(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)
@@ -3942,15 +3221,13 @@ static int openssl_tls_prf(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) {
@@ -3963,59 +3240,31 @@ static int openssl_tls_prf(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(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(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 */
 }
 
 
@@ -4274,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;
 
@@ -4313,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);
@@ -4328,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-")) {
                /*
@@ -4621,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__,
@@ -4703,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
@@ -4734,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");
@@ -4878,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
@@ -4904,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)
@@ -4917,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;
 
@@ -4970,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;
@@ -5012,9 +4268,15 @@ 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
 }