[wpa_supplicant] Cumulative patch from commit 27e828d72

Bug: 231272394
Test: connect/disconnect to WPA2, WPA3 networks
Test: SoftAp & p2p connection
Test: Regression test(b/231636895)

BYPASS_INCLUSIVE_LANGUAGE_REASON=Merged from Open source

27e828d72 ACS: Send EHT enabled info to driver
82066bd36 nl80211: Don't force VHT channel definition with EHT
43fe1ce35 EHT: Add [EHT] flag into AP mode STA command
696ad5c2d EHT: Indicate wifi_generation=7 in wpa_supplicant STATUS output
4994c41f2 EHT: Indicate ieee80211be configuration in hostapd STATUS output
50d883710 EHT: Fix invalid length checking for EHT Capability element
6c7b2be42 SAE: Send real status code to the driver when AP rejects external auth
2c78f11a9 Fix compilation due to forward declaration of macaddr_acl
c8e822801 OpenSSL: Fix build with old library versions that do not support TLS 1.3
c24e18e5c LibreSSL: Fix compilation issue with TLS 1.3 session ticket limit
eb5e63985 LibreSSL: Fix compilation issue with RSA-OAEP
5d56cf1c7 BoringSSL: Fix compilation error due to TLS 1.3 session tickets
a561d12d2 EAP peer status notification for server not supporting RFC 5746
566ce69a8 EAP peer: Workaround for servers that do not support safe TLS renegotiation
ccb3206b6 Fix tls_connection_set_success_data() in TLS library wrappers
decac7cd1 OpenSSL: Do not send out a TLS 1.3 session ticket if caching disabled
05406f7ae EAP-PEAP server: Fix TLS 1.3 move to Phase 2 without a new session ticket
10746875e OpenSSL: Allow no OCSP response when resuming a session with TLS 1.3
2be1bcaf7 EAP-TLS peer: Fix protected success indication check for resumed session
1c66276d9 EAP-TLS server: Send final TLS message for resumed session with TLS 1.3
81e249888 OpenSSL: Limit the number of TLS 1.3 session tickets to one
d26247c3d wpa_supplicant/README-WPS: Beautifications
a8d058c93 OpenSSL: SSLKEYLOGFILE capability to allow Wireshark TLS decoding
23f389068 wolfSSL: Fix OCSP stapling
a2971f8d8 wolfSSL: Allow TLS version 1.3 to be disabled
a40e48fbe wolfSSL: Fix TLS 1.3 session handling
0c3f68f2a wolfSSL: Check for the too-short-password error in pbkdf2_sha1()
ca2622481 Check the return of pbkdf2_sha1() for errors
013cd694d wolfSSL: Fixes for FIPS builds
9d5f8168f wolfSSL: Register a FIPS callback
8f36e6c0f wolfSSL: Implement crypto_ec_key wrappers
1f7e10177 wolfSSL: Add missing free calls for wolfSSL structs
ec1cd91e7 wolfSSL: Support both DER and PEM blobs
42871a5d2 EAP-SIM/AKA peer: IMSI privacy
21098e39f EAP-SIM/AKA server: IMSI privacy
36b11bbcf OpenSSL: RSA-OAEP-SHA-256 encryption/decryption
c3d389b72 EHT: Channel switch command support
dae7940a4 EHT: Additions to hostapd_set_freq_params()
e646b11fe EHT: Indicate EHT support in Neighbor Report element
f915d52de EHT: Provide EHT capabilities in STA addition path
a6d1b4c46 EHT: Process (Re)Association Request frame capabilities
340c0e212 EHT: Parse elements received in Management frames
d54e3d049 EHT: Add operation element in AP mode Management frames
9b7202d66 EHT: Add capabilities element in AP mode Management frames
a7ea72188 EHT: Add configuration options for beamforming capabilities
8db3881c7 EHT: Add operating channel width configuration
8dcc2139f EHT: AP mode configuration options to enable/disable the support
9f7da264b nl80211: Pass station's EHT capabilities to the driver in sta_add()
0c8a9aa5d nl80211: Parse EHT capabilities from the driver
c08b735fd EHT: Define EHT elements
1a716f86a defconfig: Document IEEE 802.11ax as a published amendment
86310c220 Set hostapd hw_mode automatically based on 6 GHz op_class
664fd83d5 nl80211: Increase the buffer length for debug printing channels
563162a5f QCA vendor attribute to allow eMLSR HW mode
1e34bc49c OpenSSL: Track SSL_SESSION ex data separately
734fa392f MBO: Check association disallowed in Beacon frames, if newer
284e3ad19 Determine whether Beacon frame information is newer in scan results
28c9f29a3 scan: Print SSID in scan results dump
5a0471579 Install wpa_passphrase when not disabled
f1686d776 hostapd: Allow enabling background radar
08d7738bb wolfSSL: Speed up crypto_ec_point_compute_y_sqr()
f50d5c9a8 wolfSSL: Fix crypto_ec_point_compute_y_sqr() error case processing
7302aa761 wolfSSL: Fix the memory leak of crypto_ec_point_compute_y_sqr()
e7dd0fff1 wolfSSL: Use wc_HmacInit() to avoid potential use of uninitialized values
f7be558d6 OpenSSL: Fix build with BoringSSL
6d33ef362 OpenSSL: Remove compatibility options for older versions than 1.0.2
78c2a4cd0 OpenSSL: Drop compatibility options for LibreSSL older than 2.7
b06250767 OpenSSL: Implement crypto_ecdh routines without EC_KEY for OpenSSL 3.0
fc96f6802 OpenSSL: Use new name for the EC_POINT set/get coordinate functions
0aae045af ctrl: Print the source address of the received commands
f94214968 wpa_ctrl: Wait for a total of 10 seconds, not 10 seconds per iteration
0d9be8855 wolfSSL: Fix certificate commonName checking
94e0f39d9 wolfSSL: Use wolfSSL_export_keying_material() when available
c31fc7a64 wolfSSL: Fix crypto_dh_init() and dh5_init()
d7b8c6eef wolfSSL: Fix crypto_ecdh_* with ECC_TIMING_RESISTANT
ae1fb6455 EAP-EKE server: Fix a memory leak on an error path
166acab4e wolfSSL: TLS session caching
12dee16d7 wolfSSL: Add a debug logging callback
a5d190650 wolfSSL: Implement tls_get_tls_unique()
a419fef36 wolfSSL: Implement tls_connection_get_cipher_suite()
364876b7d wolfSSL: Implement tls_connection_get_peer_subject()
d9c716400 wolfSSL: Implement tls_connection_get_own_cert_used()
d677b9dc6 wolfSSL: Conditional build for aes_wrap/aes_unwrap()
b0f016b87 eapol_test: Update with src/ap/ieee802_1x.c changes
747c5f228 Include MS_FUNCS=y for EAP-pwd peer build
c7f71fb86 Include HMAC-SHA384/512 KDF for SAE if SHA384/512 is included
3a759dcc8 ACS: Honor acs_exclude_dfs with hostapd's ACS implementation
3240cedd6 eapol_test: Print out names for additional known EAP types
f5c711c85 OpenSSL: Unload providers only at process exit
33c4dd26c BSS coloring: Handle the collision and CCA events coming from the kernel
27b4cc712 nl80211: Handle driver events for BSS coloring
399d6e64d nl80211: Add the switch_color() handler for BSS color changes
86bd90eb3 BSS coloring: Disable BSS color during CCA
f7d0b740e BSS coloring: BSS Color Change Announcement element generation
654d2395d BSS coloring: Handling of collision events and triggering CCA
52e2516f1 wpa_supplicant: Add the CONFIG_HE_OVERRIDES option to the defconfig
6a2a60f1d OpenSSL: Do not use the deprecated RSAPrivateKey function
ebb3055e1 OpenSSL: Generate DH parameters automatically if not set with dh_file
bcd299b32 OpenSSL: Convert DH/DSA parameter loading to new API
28c1c91d0 Remove unused dh_blob parameter
4a774cf31 Remove useless DH file configuration from TLS library wrappers
65652c67f Remove DH file configuration from TLS client functionality
b94371af8 RADIUS attributes for EAPOL-Key message details
24763e3cd RADIUS: Attributes with Extended Types (RFC 6929)
feed2f9e7 BoringSSL: Use accessor functions for X509 key usage flags
80be88a08 BoringSSL: Replace stack-allocated X509_STORE_CTX with heap one
b95ed17f6 OpenSSL: Fix build with BoringSSL and LibreSSL 3.3.x and older
ae0f6ee97 OpenSSL: CMAC using the OpenSSL library for non-FIPS cases as well
0c61f6234 OpenSSL: Implement CMAC using the EVP_MAC API
4fcd29660 OpenSSL: Extend CMAC to support 192-bit AES
117617843 OpenSSL: Remove now unused compatibility wrapper for RSA_bits()
a2dbb2558 Android: Compile hs20-osu-client to /vendor/bin in test builds
b0769ce61 DPP: Allow a list of supported curves to be used in bootstrapping URI
ef85328a6 QCA vendor command support to reset configuration for eLNA bypass
7008c50fa OpenSSL: Implement DH using the EVP API
e31500ade OpenSSL: Implement HMAC using the EVP_MAC API
097ca6bf0 OpenSSL: Unload providers on deinit
092efd45a OpenSSL: Implement AES keywrap using the EVP API
7e4984d9c OpenSSL: Use a correct EVP_CIPHER_CTX freeing function on an error path
8e0ac5366 RRM: Include passive channels in active beacon report scan
0adc67612 wpa_supplicant: Use unique IDs for networks and credentials
dacb6d278 Update IEEE P802.11ax draft references to published amendment
8128ea76a Add Transmit Power Envelope element in 6 GHz
bc3dc72a3 Extend 6 GHz Operation Info field in HE Operation element
0eb686637 hostapd: Add config option to specify 6 GHz regulatory AP type
ee06165e9 hostapd: Extend Country element to support 6 GHz band
f5ad97245 PASN: Fix build without CONFIG_TESTING_OPTIONS=y
3467a701c wpa_supplicant: Do not associate on 6 GHz with forbidden configurations
43c6eb5e4 SAE-PK: Add the option to the defconfigs
0482251a6 EAP-TLS: Allow TLSv1.3 support to be enabled with build config
7114e5606 EAP-TLS: Testing functionality to skip protected success indication
95fd54b86 Disconnect STA on continuous EAP reauth without 4-way handshake completion
9e11e746f EAP-TLS: Do not allow TLSv1.3 success without protected result indication
6135a8a6a Stop authentication attemps if AP does not disconnect us
88ab59d71 EAP-TLS: Replace the Commitment Message term with RFC 9190 language
63f311b10 EAP-TLS: Update specification references to RFC 5216 and 9190
5ab385321 Revert "Android: Compile hs20-osu-client to /vendor/bin in test builds"
b746cb28b Add support for not transmitting EAPOL-Key group msg 2/2
d27f7bd94 FILS: Fix config check to allow unsolicited broadcast Probe Response
65a3a273c OWE: Reuse own DH private key in AP if STA tries OWE association again
6ff8bda99 hostapd: Add the missing CONFIG_SAE option to the defconfig
1f5b6085c Fix SIGSEGV of eapol_test
576662d27 ieee802_11_auth: Coding style cleanup - NULL comparison
945acf3ef ieee802_11_auth: Coding style cleanup - no string constant splitting
1c3438fec RADIUS ACL/PSK check during 4-way handshake
5b5c954c0 Fix AP config check to recognize all PSK AKMs
c5d9f9064 QCA vendor attribute to indicate NDP interface managemtn using nl80211
a9c90475b FT: Update current_bss to target AP before check for SME-in-driver
0c88d1487 Debug print on CONFIG_NO_TKIP=y prevent RSNE with TKIP as group cipher
d5a9331f9 P2P: Copy only valid opclasses while filtering out 6 GHz channels
99c91beaa Sync with wireless-next.git include/uapi/linux/nl80211.h
d9121335a wpa_cli: Add ACL and BTM control commands
00622fcfe Extend ACL to install allow/deny list to the driver dynamically
077bce96f Set drv_max_acl_mac_addrs in wpa_supplicant AP mode
9828aba16 Support ACL operations in wpa_supplicant AP mode
fd0d738ff Add return value to ACL functions
f5ac42811 Move ACL control interface commands into shared files
930695662 Add BSS-TM-QUERY event to indicate reception of BSS TM Query
febcdf324 Support BTM operations in wpa_supplicant AP mode
0f8c6e995 Move BTM control interface commands into shared file
e059d8ece Update the Extended Capability element to struct sta_info
eb2e6b56b Enable BSS Transition Management in wpa_supplicant AP mode
30ecf0181 DPP: Update Controller parameters when it was already started
b93d1083e DPP: Fix msg_ctx for PKEX over TCP as Controller/Responder
3085e1a67 hs20-osu-client: dNSName values from OSU server certificate for PPS MO
ce86f2446 DFS: Remove unnecessary variable
760a5ae26 DFS: Switch to background radar channel if available
b63d953fe DFS: Enable CSA for background radar detection
25663241c DFS: Introduce hostapd_dfs_request_channel_switch()
316a9dc63 DFS: Configure background radar/CAC detection
bad12effe nl80211: Radar background flag setting
effd6111b DFS: Rely on channel_type in dfs_downgrade_bandwidth()
f9ba3d5c8 OpenSSL 3.0: Set SSL groups using SSL_set1_groups()
09c62aaf1 OpenSSL: Determine RSA key size without low-level routines
b700a56e1 OpenSSL 3.0: Determine the prime length for an EC key group using EVP_PKEY
3c61f4db4 OpenSSL: Replace EC_GROUP_get_curve_GFp() calls with EC_GROUP_get_curve()
e2cb0ca1a OpenSSL 3.0: Implement crypto_ec_key_group() with new API
f6a53f64a OpenSSL: Replace EVP_PKEY_cmp() with EVP_PKEY_eq() when available
5b093570d D-Bus: Add 'wep_disabled' capability
56a14cc72 DFS: Don't let cac_time_left_seconds overflow
ae512c30a DPP: Fix uninitialised variable on error path
3a157fe92 dbus: Set CurrentAuthMode to INACTIVE only if network is not selected
0ce8d55a2 hs20-osu-client: Allow EST server to use different host name
5eaf596e1 HTTP: Make URL available to the cert_cb
abed7978f HS 2.0 server: Event log entry on missing configuration for the realm
1192d5721 Android: Compile hs20-osu-client to /vendor/bin in test builds
1fee1c40c Enhance QCA vendor interface to indicate TWT required capability of AP
a192305a4 Add QCA vendor attributes for AFC support in external ACS
de5939ef5 DPP: Allow Configurator net_access_key_curve to be changed
9638452a6 DPP: Update Configurator to require same netAccessKey curve to be used
2b406eece DPP: Update Auth-I derivation operations
de64dfe98 DPP: Curve change for netAccessKey
fd2eb7a41 DPP: Fix a memory leak on error path
e9551efe0 DPP: Missing/invalid Protocol Version in Reconfig Auth Req
eeb72e7c9 DPP: Extend DPP_PKEX_ADD ver=<1/2> to cover Responder role
6c3c431bb Add QCA vendor attribute to enable Spectral FFT recapture
fcbdaae8a SAE: Add support for RADIUS passphrase as the SAE password
3d86fcee0 cleanup: Remove unreachable code
9683195ee qca-vendor: Fix typos
4c9ef9322 brcm_vendor: Fix typos
d65285ab8 src/drivers: Fix typos
203a027b2 nl80211: Report background radar/CAC detection capability
0a73649b6 DFS: Add capability to select radar-only channels
f39765369 DFS: Introduce dfs_set_valid_channel() utility routine
d001b301b Fix removal of wpa_passphrase on 'make clean'
cb41c214b build: Re-enable options for libwpa_client.so and wpa_passphrase
dec626109 HE: Fix invalid length checking for HE Capability element
53be64f7d HE: Fix calculation of the PPE Threshold field length
738fef2f0 Clear PSK explicitly from memory in couple more cases on deinit
567b9764f Clear PMK explicitly even without FT support in AP build
0bd29c176 Remove duplicated pointer check
007fd6111 Clear temporary results from stack in PBKDF2-SHA1
1364f322b Remove GTK/IGTK/BIGTK from memory explicitly in AP mode
af1f0694e Clear last set keys (for testing purposes) from memory explicitly
6c850a1c0 nl80211: Clear bss->freq when stopping AP mode
a44fa15cb Define a vendor specific NDP attribute for NAN service id
414ca953f DPP: Clear SCANNING state when starting network introduction
0b5f8e3d8 DPP: Clear netrole on starting chirping or reconfiguration
2fcc076d1 Clear wpa_s->last/current_ssid in more cases
7a7f803a9 DPP: Stop offchannel frame TX wait on DPP_STOP_LISTEN in a corner case
7e941e7a1 macsec_linux: Support cipher suite configuration
46c635910 MACsec: Support GCM-AES-256 cipher suite
42944de69 nl80211: Do not store no-wait TX frame cookies to be cancelled
340ec48cd DPP: Clear state on configuration failure in GAS server hander
7e6f59c70 nl80211: Clear the last saved TX frame cookie on wait expiration
9d5fd3328 Update QCA vendor attribute to indicate maximum PCL attributes
19169a53a atheros: Do not include p2p.h
f43d31dda nl80211: Debug print association comeback event data
a91072503 OCV: Don't start SA Query timer on CSA when SA Query is offloaded
f5c8697c0 Sync with mac80211-next.git include/uapi/linux/nl80211.h
632a9995c Clear ignore_old_scan_res on FLUSH command

Change-Id: I35fd1fb999d045ced8c153fe3d8284c9a71069b1
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index e6150b0..e4f3eb3 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -1275,4 +1275,46 @@
 				struct crypto_ec_key *key,
 				enum crypto_hash_alg algo);
 
+struct crypto_rsa_key;
+
+/**
+ * crypto_rsa_key_read - Read an RSA key
+ * @file: File from which to read (PEM encoded, can be X.509v3 certificate)
+ * @private_key: Whether to read the private key instead of public key
+ * Returns: RSA key or %NULL on failure
+ */
+struct crypto_rsa_key * crypto_rsa_key_read(const char *file, bool private_key);
+
+/**
+ * crypto_rsa_oaep_sha256_encrypt - RSA-OAEP-SHA-256 encryption
+ * @key: RSA key from crypto_rsa_key_read()
+ * @in: Plaintext input data
+ * Returns: Encrypted output data or %NULL on failure
+ */
+struct wpabuf * crypto_rsa_oaep_sha256_encrypt(struct crypto_rsa_key *key,
+					       const struct wpabuf *in);
+
+/**
+ * crypto_rsa_oaep_sha256_decrypt - RSA-OAEP-SHA-256 decryption
+ * @key: RSA key from crypto_rsa_key_read()
+ * @in: Encrypted input data
+ * Returns: Decrypted output data or %NULL on failure
+ */
+struct wpabuf * crypto_rsa_oaep_sha256_decrypt(struct crypto_rsa_key *key,
+					       const struct wpabuf *in);
+
+/**
+ * crypto_rsa_key_free - Free an RSA key
+ * @key: RSA key from crypto_rsa_key_read()
+ */
+void crypto_rsa_key_free(struct crypto_rsa_key *key);
+
+/**
+ * crypto_unload - Unload crypto resources
+ *
+ * This function is called just before the process exits to allow dynamic
+ * resource allocations to be freed.
+ */
+void crypto_unload(void);
+
 #endif /* CRYPTO_H */
diff --git a/src/crypto/crypto_gnutls.c b/src/crypto/crypto_gnutls.c
index 4ef1146..a7a163f 100644
--- a/src/crypto/crypto_gnutls.c
+++ b/src/crypto/crypto_gnutls.c
@@ -504,3 +504,8 @@
 	gcry_cipher_close(ctx->dec);
 	os_free(ctx);
 }
+
+
+void crypto_unload(void)
+{
+}
diff --git a/src/crypto/crypto_internal.c b/src/crypto/crypto_internal.c
index aad40af..d15c363 100644
--- a/src/crypto/crypto_internal.c
+++ b/src/crypto/crypto_internal.c
@@ -326,3 +326,8 @@
 void crypto_global_deinit(void)
 {
 }
+
+
+void crypto_unload(void)
+{
+}
diff --git a/src/crypto/crypto_libtomcrypt.c b/src/crypto/crypto_libtomcrypt.c
index ed30efa..fd79c1a 100644
--- a/src/crypto/crypto_libtomcrypt.c
+++ b/src/crypto/crypto_libtomcrypt.c
@@ -766,3 +766,8 @@
 }
 
 #endif /* CONFIG_MODEXP */
+
+
+void crypto_unload(void)
+{
+}
diff --git a/src/crypto/crypto_linux.c b/src/crypto/crypto_linux.c
index 1724456..9278e27 100644
--- a/src/crypto/crypto_linux.c
+++ b/src/crypto/crypto_linux.c
@@ -1007,3 +1007,8 @@
 void crypto_global_deinit(void)
 {
 }
+
+
+void crypto_unload(void)
+{
+}
diff --git a/src/crypto/crypto_nettle.c b/src/crypto/crypto_nettle.c
index f85d365..d745027 100644
--- a/src/crypto/crypto_nettle.c
+++ b/src/crypto/crypto_nettle.c
@@ -467,3 +467,8 @@
 {
 	bin_clear_free(ctx, sizeof(*ctx));
 }
+
+
+void crypto_unload(void)
+{
+}
diff --git a/src/crypto/crypto_none.c b/src/crypto/crypto_none.c
index 5479194..a0dc0f5 100644
--- a/src/crypto/crypto_none.c
+++ b/src/crypto/crypto_none.c
@@ -22,3 +22,8 @@
 {
 	return 0;
 }
+
+
+void crypto_unload(void)
+{
+}
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 82c8576..c6e065f 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -1,6 +1,6 @@
 /*
  * Wrapper functions for OpenSSL libcrypto
- * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2022, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -16,16 +16,17 @@
 #include <openssl/dh.h>
 #include <openssl/hmac.h>
 #include <openssl/rand.h>
-#ifdef CONFIG_OPENSSL_CMAC
-#include <openssl/cmac.h>
-#endif /* CONFIG_OPENSSL_CMAC */
+#include <openssl/pem.h>
 #ifdef CONFIG_ECC
 #include <openssl/ec.h>
 #include <openssl/x509.h>
-#include <openssl/pem.h>
 #endif /* CONFIG_ECC */
 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
 #include <openssl/provider.h>
+#include <openssl/core_names.h>
+#include <openssl/param_build.h>
+#else /* OpenSSL version >= 3.0 */
+#include <openssl/cmac.h>
 #endif /* OpenSSL version >= 3.0 */
 
 #include "common.h"
@@ -40,9 +41,7 @@
 #include "aes_wrap.h"
 #include "crypto.h"
 
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
-	(defined(LIBRESSL_VERSION_NUMBER) && \
-	 LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
 /* Compatibility wrappers for older versions. */
 
 static HMAC_CTX * HMAC_CTX_new(void)
@@ -121,30 +120,89 @@
 #endif /* OpenSSL version < 1.1.0 */
 
 
+#if OPENSSL_VERSION_NUMBER < 0x10101000L || \
+	(defined(LIBRESSL_VERSION_NUMBER) && \
+	 LIBRESSL_VERSION_NUMBER < 0x30400000L)
+
+static int EC_POINT_get_affine_coordinates(const EC_GROUP *group,
+					   const EC_POINT *point, BIGNUM *x,
+					   BIGNUM *y, BN_CTX *ctx)
+{
+	return EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx);
+}
+
+
+static int EC_POINT_set_affine_coordinates(const EC_GROUP *group,
+					   EC_POINT *point, const BIGNUM *x,
+					   const BIGNUM *y, BN_CTX *ctx)
+{
+	return EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx);
+}
+
+#endif /* OpenSSL version < 1.1.1 */
+
+
+#if OPENSSL_VERSION_NUMBER < 0x10101000L || \
+	defined(OPENSSL_IS_BORINGSSL) || \
+	(defined(LIBRESSL_VERSION_NUMBER) && \
+	 LIBRESSL_VERSION_NUMBER < 0x30400000L)
+
+static int EC_POINT_set_compressed_coordinates(const EC_GROUP *group,
+					       EC_POINT *point, const BIGNUM *x,
+					       int y_bit, BN_CTX *ctx)
+{
+	return EC_POINT_set_compressed_coordinates_GFp(group, point, x, y_bit,
+						       ctx);
+}
+
+
+static int EC_GROUP_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a,
+			      BIGNUM *b, BN_CTX *ctx)
+{
+	return EC_GROUP_get_curve_GFp(group, p, a, b, ctx);
+}
+
+#endif /* OpenSSL version < 1.1.1 */
+
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+static OSSL_PROVIDER *openssl_default_provider = NULL;
+static OSSL_PROVIDER *openssl_legacy_provider = NULL;
+#endif /* OpenSSL version >= 3.0 */
+
 void openssl_load_legacy_provider(void)
 {
 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
-	static bool loaded = false;
-	OSSL_PROVIDER *legacy;
-
-	if (loaded)
+	if (openssl_legacy_provider)
 		return;
 
-	legacy = OSSL_PROVIDER_load(NULL, "legacy");
+	openssl_legacy_provider = OSSL_PROVIDER_load(NULL, "legacy");
+	if (openssl_legacy_provider && !openssl_default_provider)
+		openssl_default_provider = OSSL_PROVIDER_load(NULL, "default");
+#endif /* OpenSSL version >= 3.0 */
+}
 
-	if (legacy) {
-		OSSL_PROVIDER_load(NULL, "default");
-		loaded = true;
+
+static void openssl_unload_legacy_provider(void)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	if (openssl_legacy_provider) {
+		OSSL_PROVIDER_unload(openssl_legacy_provider);
+		openssl_legacy_provider = NULL;
+	}
+	if (openssl_default_provider) {
+		OSSL_PROVIDER_unload(openssl_default_provider);
+		openssl_default_provider = NULL;
 	}
 #endif /* OpenSSL version >= 3.0 */
 }
 
 
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+
 static BIGNUM * get_group5_prime(void)
 {
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
-	!(defined(LIBRESSL_VERSION_NUMBER) && \
-	  LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
 	return BN_get_rfc3526_prime_1536(NULL);
 #elif !defined(OPENSSL_IS_BORINGSSL)
 	return get_rfc3526_prime_1536(NULL);
@@ -195,6 +253,8 @@
 	return BN_bin2bn(RFC3526_ORDER_1536, sizeof(RFC3526_ORDER_1536), NULL);
 }
 
+#endif /* OpenSSL version < 3.0 */
+
 
 #ifdef OPENSSL_NO_SHA256
 #define NO_SHA256_WRAPPER
@@ -403,7 +463,7 @@
 	if (ctx == NULL)
 		return NULL;
 	if (EVP_EncryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
-		os_free(ctx);
+		EVP_CIPHER_CTX_free(ctx);
 		return NULL;
 	}
 	EVP_CIPHER_CTX_set_padding(ctx, 0);
@@ -501,8 +561,52 @@
 #ifndef CONFIG_FIPS
 #ifndef CONFIG_OPENSSL_INTERNAL_AES_WRAP
 
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+static const EVP_CIPHER * aes_get_evp_wrap_cipher(size_t keylen)
+{
+	switch (keylen) {
+	case 16:
+		return EVP_aes_128_wrap();
+	case 24:
+		return EVP_aes_192_wrap();
+	case 32:
+		return EVP_aes_256_wrap();
+	default:
+		return NULL;
+	}
+}
+#endif /* OpenSSL version >= 3.0 */
+
+
 int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	EVP_CIPHER_CTX *ctx;
+	const EVP_CIPHER *type;
+	int ret = -1, len;
+	u8 buf[16];
+
+	if (TEST_FAIL())
+		return -1;
+
+	type = aes_get_evp_wrap_cipher(kek_len);
+	if (!type)
+		return -1;
+
+	ctx = EVP_CIPHER_CTX_new();
+	if (!ctx)
+		return -1;
+
+	if (EVP_EncryptInit_ex(ctx, type, NULL, kek, NULL) == 1 &&
+	    EVP_CIPHER_CTX_set_padding(ctx, 0) == 1 &&
+	    EVP_EncryptUpdate(ctx, cipher, &len, plain, n * 8) == 1 &&
+	    len == (n + 1) * 8 &&
+	    EVP_EncryptFinal_ex(ctx, buf, &len) == 1)
+		ret = 0;
+
+	EVP_CIPHER_CTX_free(ctx);
+	return ret;
+#else /* OpenSSL version >= 3.0 */
 	AES_KEY actx;
 	int res;
 
@@ -513,12 +617,40 @@
 	res = AES_wrap_key(&actx, NULL, cipher, plain, n * 8);
 	OPENSSL_cleanse(&actx, sizeof(actx));
 	return res <= 0 ? -1 : 0;
+#endif /* OpenSSL version >= 3.0 */
 }
 
 
 int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
 	       u8 *plain)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	EVP_CIPHER_CTX *ctx;
+	const EVP_CIPHER *type;
+	int ret = -1, len;
+	u8 buf[16];
+
+	if (TEST_FAIL())
+		return -1;
+
+	type = aes_get_evp_wrap_cipher(kek_len);
+	if (!type)
+		return -1;
+
+	ctx = EVP_CIPHER_CTX_new();
+	if (!ctx)
+		return -1;
+
+	if (EVP_DecryptInit_ex(ctx, type, NULL, kek, NULL) == 1 &&
+	    EVP_CIPHER_CTX_set_padding(ctx, 0) == 1 &&
+	    EVP_DecryptUpdate(ctx, plain, &len, cipher, (n + 1) * 8) == 1 &&
+	    len == n * 8 &&
+	    EVP_DecryptFinal_ex(ctx, buf, &len) == 1)
+		ret = 0;
+
+	EVP_CIPHER_CTX_free(ctx);
+	return ret;
+#else /* OpenSSL version >= 3.0 */
 	AES_KEY actx;
 	int res;
 
@@ -529,6 +661,7 @@
 	res = AES_unwrap_key(&actx, NULL, plain, cipher, (n + 1) * 8);
 	OPENSSL_cleanse(&actx, sizeof(actx));
 	return res <= 0 ? -1 : 0;
+#endif /* OpenSSL version >= 3.0 */
 }
 
 #endif /* CONFIG_OPENSSL_INTERNAL_AES_WRAP */
@@ -819,9 +952,7 @@
 
 void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
 {
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
-	(defined(LIBRESSL_VERSION_NUMBER) && \
-	 LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
 	DH *dh;
 	struct wpabuf *pubkey = NULL, *privkey = NULL;
 	size_t publen, privlen;
@@ -870,6 +1001,57 @@
 	wpabuf_clear_free(privkey);
 	DH_free(dh);
 	return NULL;
+#elif OPENSSL_VERSION_NUMBER >= 0x30000000L
+	EVP_PKEY *pkey = NULL;
+	OSSL_PARAM params[2];
+	size_t pub_len = OSSL_PARAM_UNMODIFIED;
+	size_t priv_len;
+	struct wpabuf *pubkey = NULL, *privkey = NULL;
+	BIGNUM *priv_bn = NULL;
+	EVP_PKEY_CTX *gctx;
+
+	*priv = NULL;
+	wpabuf_free(*publ);
+	*publ = NULL;
+
+	params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
+						     "modp_1536", 0);
+	params[1] = OSSL_PARAM_construct_end();
+
+	gctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL);
+	if (!gctx ||
+	    EVP_PKEY_keygen_init(gctx) != 1 ||
+	    EVP_PKEY_CTX_set_params(gctx, params) != 1 ||
+	    EVP_PKEY_generate(gctx, &pkey) != 1 ||
+	    EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY,
+				  &priv_bn) != 1 ||
+	    EVP_PKEY_get_octet_string_param(pkey,
+					    OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
+					    NULL, 0, &pub_len) < 0 ||
+	    pub_len == OSSL_PARAM_UNMODIFIED ||
+	    (priv_len = BN_num_bytes(priv_bn)) == 0 ||
+	    !(pubkey = wpabuf_alloc(pub_len)) ||
+	    !(privkey = wpabuf_alloc(priv_len)) ||
+	    EVP_PKEY_get_octet_string_param(pkey,
+					    OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
+					    wpabuf_put(pubkey, pub_len),
+					    pub_len, NULL) != 1) {
+		wpa_printf(MSG_INFO, "OpenSSL: failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+		wpabuf_free(pubkey);
+		wpabuf_clear_free(privkey);
+		EVP_PKEY_free(pkey);
+		pkey = NULL;
+	} else {
+		BN_bn2bin(priv_bn, wpabuf_put(privkey, priv_len));
+
+		*priv = privkey;
+		*publ = pubkey;
+	}
+
+	BN_clear_free(priv_bn);
+	EVP_PKEY_CTX_free(gctx);
+	return pkey;
 #else
 	DH *dh;
 	struct wpabuf *pubkey = NULL, *privkey = NULL;
@@ -929,9 +1111,7 @@
 
 void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
 {
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
-	(defined(LIBRESSL_VERSION_NUMBER) && \
-	 LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
 	DH *dh;
 
 	dh = DH_new();
@@ -962,6 +1142,39 @@
 err:
 	DH_free(dh);
 	return NULL;
+#elif OPENSSL_VERSION_NUMBER >= 0x30000000L
+	EVP_PKEY *pkey = NULL;
+	OSSL_PARAM_BLD *bld;
+	OSSL_PARAM *params = NULL;
+	BIGNUM *priv_key, *pub_key;
+	EVP_PKEY_CTX *fctx;
+
+	fctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL);
+	priv_key = BN_bin2bn(wpabuf_head(priv), wpabuf_len(priv), NULL);
+	pub_key = BN_bin2bn(wpabuf_head(publ), wpabuf_len(publ), NULL);
+	bld = OSSL_PARAM_BLD_new();
+	if (!fctx || !priv_key || !pub_key || !bld ||
+	    OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME,
+					    "modp_1536", 0) != 1 ||
+	    OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY,
+				   priv_key) != 1 ||
+	    OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PUB_KEY,
+				   pub_key) != 1 ||
+	    !(params = OSSL_PARAM_BLD_to_param(bld)) ||
+	    EVP_PKEY_fromdata_init(fctx) != 1 ||
+	    EVP_PKEY_fromdata(fctx, &pkey, EVP_PKEY_KEYPAIR, params) != 1) {
+		wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_fromdata failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+		EVP_PKEY_free(pkey);
+		pkey = NULL;
+	}
+
+	BN_clear_free(priv_key);
+	BN_free(pub_key);
+	EVP_PKEY_CTX_free(fctx);
+	OSSL_PARAM_BLD_free(bld);
+	OSSL_PARAM_free(params);
+	return pkey;
 #else
 	DH *dh;
 	BIGNUM *p = NULL, *g, *priv_key = NULL, *pub_key = NULL;
@@ -1004,6 +1217,36 @@
 struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
 				  const struct wpabuf *own_private)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	EVP_PKEY *pkey = ctx;
+	EVP_PKEY *peer_pub;
+	size_t len;
+	struct wpabuf *res = NULL;
+	EVP_PKEY_CTX *dctx = NULL;
+
+	peer_pub = EVP_PKEY_new();
+	if (!pkey || !peer_pub ||
+	    EVP_PKEY_copy_parameters(peer_pub, pkey) != 1 ||
+	    EVP_PKEY_set1_encoded_public_key(peer_pub, wpabuf_head(peer_public),
+					     wpabuf_len(peer_public)) != 1 ||
+	    !(dctx = EVP_PKEY_CTX_new(pkey, NULL)) ||
+	    EVP_PKEY_derive_init(dctx) != 1 ||
+	    EVP_PKEY_derive_set_peer(dctx, peer_pub) != 1 ||
+	    EVP_PKEY_derive(dctx, NULL, &len) != 1 ||
+	    !(res = wpabuf_alloc(len)) ||
+	    EVP_PKEY_derive(dctx, wpabuf_mhead(res), &len) != 1) {
+		wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_derive failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+		wpabuf_free(res);
+		res = NULL;
+	} else {
+		wpabuf_put(res, len);
+	}
+
+	EVP_PKEY_free(peer_pub);
+	EVP_PKEY_CTX_free(dctx);
+	return res;
+#else /* OpenSSL version >= 3.0 */
 	BIGNUM *pub_key;
 	struct wpabuf *res = NULL;
 	size_t rlen;
@@ -1035,27 +1278,93 @@
 	BN_clear_free(pub_key);
 	wpabuf_clear_free(res);
 	return NULL;
+#endif /* OpenSSL version >= 3.0 */
 }
 
 
 void dh5_free(void *ctx)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	EVP_PKEY *pkey = ctx;
+
+	EVP_PKEY_free(pkey);
+#else /* OpenSSL version >= 3.0 */
 	DH *dh;
 	if (ctx == NULL)
 		return;
 	dh = ctx;
 	DH_free(dh);
+#endif /* OpenSSL version >= 3.0 */
 }
 
 
 struct crypto_hash {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	EVP_MAC_CTX *ctx;
+#else /* OpenSSL version >= 3.0 */
 	HMAC_CTX *ctx;
+#endif /* OpenSSL version >= 3.0 */
 };
 
 
 struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
 				      size_t key_len)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	struct crypto_hash *ctx;
+	EVP_MAC *mac;
+	OSSL_PARAM params[2];
+	char *a = NULL;
+
+	switch (alg) {
+#ifndef OPENSSL_NO_MD5
+	case CRYPTO_HASH_ALG_HMAC_MD5:
+		a = "MD5";
+		break;
+#endif /* OPENSSL_NO_MD5 */
+#ifndef OPENSSL_NO_SHA
+	case CRYPTO_HASH_ALG_HMAC_SHA1:
+		a = "SHA1";
+		break;
+#endif /* OPENSSL_NO_SHA */
+#ifndef OPENSSL_NO_SHA256
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_HMAC_SHA256:
+		a = "SHA256";
+		break;
+#endif /* CONFIG_SHA256 */
+#endif /* OPENSSL_NO_SHA256 */
+	default:
+		return NULL;
+	}
+
+	mac = EVP_MAC_fetch(NULL, "HMAC", NULL);
+	if (!mac)
+		return NULL;
+
+	params[0] = OSSL_PARAM_construct_utf8_string("digest", a, 0);
+	params[1] = OSSL_PARAM_construct_end();
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (!ctx)
+		return NULL;
+	ctx->ctx = EVP_MAC_CTX_new(mac);
+	if (!ctx->ctx) {
+		EVP_MAC_free(mac);
+		os_free(ctx);
+		return NULL;
+	}
+
+	if (EVP_MAC_init(ctx->ctx, key, key_len, params) != 1) {
+		EVP_MAC_CTX_free(ctx->ctx);
+		bin_clear_free(ctx, sizeof(*ctx));
+		EVP_MAC_free(mac);
+		return NULL;
+	}
+
+	EVP_MAC_free(mac);
+	return ctx;
+#else /* OpenSSL version >= 3.0 */
 	struct crypto_hash *ctx;
 	const EVP_MD *md;
 
@@ -1097,6 +1406,7 @@
 	}
 
 	return ctx;
+#endif /* OpenSSL version >= 3.0 */
 }
 
 
@@ -1104,12 +1414,49 @@
 {
 	if (ctx == NULL)
 		return;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	EVP_MAC_update(ctx->ctx, data, len);
+#else /* OpenSSL version >= 3.0 */
 	HMAC_Update(ctx->ctx, data, len);
+#endif /* OpenSSL version >= 3.0 */
 }
 
 
 int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	size_t mdlen;
+	int res;
+
+	if (!ctx)
+		return -2;
+
+	if (!mac || !len) {
+		EVP_MAC_CTX_free(ctx->ctx);
+		bin_clear_free(ctx, sizeof(*ctx));
+		return 0;
+	}
+
+	res = EVP_MAC_final(ctx->ctx, NULL, &mdlen, 0);
+	if (res != 1) {
+		EVP_MAC_CTX_free(ctx->ctx);
+		bin_clear_free(ctx, sizeof(*ctx));
+		return -1;
+	}
+	res = EVP_MAC_final(ctx->ctx, mac, &mdlen, mdlen);
+	EVP_MAC_CTX_free(ctx->ctx);
+	bin_clear_free(ctx, sizeof(*ctx));
+
+	if (TEST_FAIL())
+		return -1;
+
+	if (res == 1) {
+		*len = mdlen;
+		return 0;
+	}
+
+	return -1;
+#else /* OpenSSL version >= 3.0 */
 	unsigned int mdlen;
 	int res;
 
@@ -1136,9 +1483,148 @@
 	}
 
 	return -1;
+#endif /* OpenSSL version >= 3.0 */
 }
 
 
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+
+static int openssl_hmac_vector(char *digest, const u8 *key,
+			       size_t key_len, size_t num_elem,
+			       const u8 *addr[], const size_t *len, u8 *mac,
+			       unsigned int mdlen)
+{
+	EVP_MAC *hmac;
+	OSSL_PARAM params[2];
+	EVP_MAC_CTX *ctx;
+	size_t i, mlen;
+	int res;
+
+	if (TEST_FAIL())
+		return -1;
+
+	hmac = EVP_MAC_fetch(NULL, "HMAC", NULL);
+	if (!hmac)
+		return -1;
+
+	params[0] = OSSL_PARAM_construct_utf8_string("digest", digest, 0);
+	params[1] = OSSL_PARAM_construct_end();
+
+	ctx = EVP_MAC_CTX_new(hmac);
+	EVP_MAC_free(hmac);
+	if (!ctx)
+		return -1;
+
+	if (EVP_MAC_init(ctx, key, key_len, params) != 1)
+		goto fail;
+
+	for (i = 0; i < num_elem; i++) {
+		if (EVP_MAC_update(ctx, addr[i], len[i]) != 1)
+			goto fail;
+	}
+
+	res = EVP_MAC_final(ctx, mac, &mlen, mdlen);
+	EVP_MAC_CTX_free(ctx);
+
+	return res == 1 ? 0 : -1;
+fail:
+	EVP_MAC_CTX_free(ctx);
+	return -1;
+}
+
+
+#ifndef CONFIG_FIPS
+
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+		    const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return openssl_hmac_vector("MD5", key ,key_len, num_elem, addr, len,
+				   mac, 16);
+}
+
+
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	     u8 *mac)
+{
+	return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_FIPS */
+
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+		     const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return openssl_hmac_vector("SHA1", key, key_len, num_elem, addr,
+				   len, mac, 20);
+}
+
+
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	       u8 *mac)
+{
+	return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+#ifdef CONFIG_SHA256
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return openssl_hmac_vector("SHA256", key, key_len, num_elem, addr,
+				   len, mac, 32);
+}
+
+
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac)
+{
+	return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA256 */
+
+
+#ifdef CONFIG_SHA384
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return openssl_hmac_vector("SHA384", key, key_len, num_elem, addr,
+				   len, mac, 48);
+}
+
+
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac)
+{
+	return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA384 */
+
+
+#ifdef CONFIG_SHA512
+
+int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return openssl_hmac_vector("SHA512", key, key_len, num_elem, addr,
+				   len, mac, 64);
+}
+
+
+int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac)
+{
+	return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA512 */
+
+#else /* OpenSSL version >= 3.0 */
+
 static int openssl_hmac_vector(const EVP_MD *type, const u8 *key,
 			       size_t key_len, size_t num_elem,
 			       const u8 *addr[], const size_t *len, u8 *mac,
@@ -1188,16 +1674,6 @@
 #endif /* CONFIG_FIPS */
 
 
-int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
-		int iterations, u8 *buf, size_t buflen)
-{
-	if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase), ssid,
-				   ssid_len, iterations, buflen, buf) != 1)
-		return -1;
-	return 0;
-}
-
-
 int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
 		     const u8 *addr[], const size_t *len, u8 *mac)
 {
@@ -1269,6 +1745,18 @@
 
 #endif /* CONFIG_SHA512 */
 
+#endif /* OpenSSL version >= 3.0 */
+
+
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
+		int iterations, u8 *buf, size_t buflen)
+{
+	if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase), ssid,
+				   ssid_len, iterations, buflen, buf) != 1)
+		return -1;
+	return 0;
+}
+
 
 int crypto_get_random(void *buf, size_t len)
 {
@@ -1278,10 +1766,49 @@
 }
 
 
-#ifdef CONFIG_OPENSSL_CMAC
 int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
 		     const u8 *addr[], const size_t *len, u8 *mac)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	EVP_MAC_CTX *ctx = NULL;
+	EVP_MAC *emac;
+	int ret = -1;
+	size_t outlen, i;
+	OSSL_PARAM params[2];
+	char *cipher = NULL;
+
+	if (TEST_FAIL())
+		return -1;
+
+	emac = EVP_MAC_fetch(NULL, "CMAC", NULL);
+
+	if (key_len == 32)
+		cipher = "aes-256-cbc";
+	else if (key_len == 24)
+		cipher = "aes-192-cbc";
+	else if (key_len == 16)
+		cipher = "aes-128-cbc";
+
+	params[0] = OSSL_PARAM_construct_utf8_string("cipher", cipher, 0);
+	params[1] = OSSL_PARAM_construct_end();
+
+	if (!emac || !cipher ||
+	    !(ctx = EVP_MAC_CTX_new(emac)) ||
+	    EVP_MAC_init(ctx, key, key_len, params) != 1)
+		goto fail;
+
+	for (i = 0; i < num_elem; i++) {
+		if (!EVP_MAC_update(ctx, addr[i], len[i]))
+			goto fail;
+	}
+	if (EVP_MAC_final(ctx, mac, &outlen, 16) != 1 || outlen != 16)
+		goto fail;
+
+	ret = 0;
+fail:
+	EVP_MAC_CTX_free(ctx);
+	return ret;
+#else /* OpenSSL version >= 3.0 */
 	CMAC_CTX *ctx;
 	int ret = -1;
 	size_t outlen, i;
@@ -1296,6 +1823,9 @@
 	if (key_len == 32) {
 		if (!CMAC_Init(ctx, key, 32, EVP_aes_256_cbc(), NULL))
 			goto fail;
+	} else if (key_len == 24) {
+		if (!CMAC_Init(ctx, key, 24, EVP_aes_192_cbc(), NULL))
+			goto fail;
 	} else if (key_len == 16) {
 		if (!CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL))
 			goto fail;
@@ -1313,6 +1843,7 @@
 fail:
 	CMAC_CTX_free(ctx);
 	return ret;
+#endif /* OpenSSL version >= 3.0 */
 }
 
 
@@ -1333,7 +1864,6 @@
 {
 	return omac1_aes_vector(key, 32, 1, &data, &data_len, mac);
 }
-#endif /* CONFIG_OPENSSL_CMAC */
 
 
 struct crypto_bignum * crypto_bignum_init(void)
@@ -1752,7 +2282,7 @@
 	e->b = BN_new();
 	if (e->group == NULL || e->bnctx == NULL || e->prime == NULL ||
 	    e->order == NULL || e->a == NULL || e->b == NULL ||
-	    !EC_GROUP_get_curve_GFp(e->group, e->prime, e->a, e->b, e->bnctx) ||
+	    !EC_GROUP_get_curve(e->group, e->prime, e->a, e->b, e->bnctx) ||
 	    !EC_GROUP_get_order(e->group, e->order, e->bnctx)) {
 		crypto_ec_deinit(e);
 		e = NULL;
@@ -1847,10 +2377,10 @@
 int crypto_ec_point_x(struct crypto_ec *e, const struct crypto_ec_point *p,
 		      struct crypto_bignum *x)
 {
-	return EC_POINT_get_affine_coordinates_GFp(e->group,
-						   (const EC_POINT *) p,
-						   (BIGNUM *) x, NULL,
-						   e->bnctx) == 1 ? 0 : -1;
+	return EC_POINT_get_affine_coordinates(e->group,
+					       (const EC_POINT *) p,
+					       (BIGNUM *) x, NULL,
+					       e->bnctx) == 1 ? 0 : -1;
 }
 
 
@@ -1868,8 +2398,8 @@
 	y_bn = BN_new();
 
 	if (x_bn && y_bn &&
-	    EC_POINT_get_affine_coordinates_GFp(e->group, (EC_POINT *) point,
-						x_bn, y_bn, e->bnctx)) {
+	    EC_POINT_get_affine_coordinates(e->group, (EC_POINT *) point,
+					    x_bn, y_bn, e->bnctx)) {
 		if (x) {
 			crypto_bignum_to_bin((struct crypto_bignum *) x_bn,
 					     x, len, len);
@@ -1907,8 +2437,7 @@
 		return NULL;
 	}
 
-	if (!EC_POINT_set_affine_coordinates_GFp(e->group, elem, x, y,
-						 e->bnctx)) {
+	if (!EC_POINT_set_affine_coordinates(e->group, elem, x, y, e->bnctx)) {
 		EC_POINT_clear_free(elem);
 		elem = NULL;
 	}
@@ -2009,8 +2538,8 @@
 	x = BN_new();
 	y = BN_new();
 	if (!x || !y ||
-	    EC_POINT_get_affine_coordinates_GFp(e->group, (const EC_POINT *) p,
-						x, y, e->bnctx) != 1)
+	    EC_POINT_get_affine_coordinates(e->group, (const EC_POINT *) p,
+					    x, y, e->bnctx) != 1)
 		goto fail;
 
 	x_str = BN_bn2hex(x);
@@ -2035,6 +2564,33 @@
 
 struct crypto_ecdh * crypto_ecdh_init(int group)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	struct crypto_ecdh *ecdh;
+	const char *name;
+
+	ecdh = os_zalloc(sizeof(*ecdh));
+	if (!ecdh)
+		goto fail;
+
+	ecdh->ec = crypto_ec_init(group);
+	if (!ecdh->ec)
+		goto fail;
+
+	name = OSSL_EC_curve_nid2name(ecdh->ec->nid);
+	if (!name)
+		goto fail;
+
+	ecdh->pkey = EVP_EC_gen(name);
+	if (!ecdh->pkey)
+		goto fail;
+
+done:
+	return ecdh;
+fail:
+	crypto_ecdh_deinit(ecdh);
+	ecdh = NULL;
+	goto done;
+#else /* OpenSSL version >= 3.0 */
 	struct crypto_ecdh *ecdh;
 	EVP_PKEY *params = NULL;
 	EC_KEY *ec_params = NULL;
@@ -2089,11 +2645,32 @@
 	crypto_ecdh_deinit(ecdh);
 	ecdh = NULL;
 	goto done;
+#endif /* OpenSSL version >= 3.0 */
 }
 
 
 struct crypto_ecdh * crypto_ecdh_init2(int group, struct crypto_ec_key *own_key)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	struct crypto_ecdh *ecdh;
+
+	ecdh = os_zalloc(sizeof(*ecdh));
+	if (!ecdh)
+		goto fail;
+
+	ecdh->ec = crypto_ec_init(group);
+	if (!ecdh->ec)
+		goto fail;
+
+	ecdh->pkey = EVP_PKEY_dup((EVP_PKEY *) own_key);
+	if (!ecdh->pkey)
+		goto fail;
+
+	return ecdh;
+fail:
+	crypto_ecdh_deinit(ecdh);
+	return NULL;
+#else /* OpenSSL version >= 3.0 */
 	struct crypto_ecdh *ecdh;
 
 	ecdh = os_zalloc(sizeof(*ecdh));
@@ -2115,11 +2692,34 @@
 fail:
 	crypto_ecdh_deinit(ecdh);
 	return NULL;
+#endif /* OpenSSL version >= 3.0 */
 }
 
 
 struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	struct wpabuf *buf = NULL;
+	unsigned char *pub;
+	size_t len, exp_len;
+
+	len = EVP_PKEY_get1_encoded_public_key(ecdh->pkey, &pub);
+	if (len == 0)
+		return NULL;
+
+	/* Encoded using SECG SEC 1, Sec. 2.3.4 format */
+	exp_len = 1 + 2 * crypto_ec_prime_len(ecdh->ec);
+	if (len != exp_len) {
+		wpa_printf(MSG_ERROR,
+			   "OpenSSL:%s: Unexpected encoded public key length %zu (expected %zu)",
+			   __func__, len, exp_len);
+		goto fail;
+	}
+	buf = wpabuf_alloc_copy(pub + 1, inc_y ? len - 1 : len / 2);
+fail:
+	OPENSSL_free(pub);
+	return buf;
+#else /* OpenSSL version >= 3.0 */
 	struct wpabuf *buf = NULL;
 	EC_KEY *eckey;
 	const EC_POINT *pubkey;
@@ -2145,10 +2745,10 @@
 	if (!x || !buf)
 		goto fail;
 
-	if (EC_POINT_get_affine_coordinates_GFp(ecdh->ec->group, pubkey,
-						x, y, ecdh->ec->bnctx) != 1) {
+	if (EC_POINT_get_affine_coordinates(ecdh->ec->group, pubkey,
+					    x, y, ecdh->ec->bnctx) != 1) {
 		wpa_printf(MSG_ERROR,
-			   "OpenSSL: EC_POINT_get_affine_coordinates_GFp failed: %s",
+			   "OpenSSL: EC_POINT_get_affine_coordinates failed: %s",
 			   ERR_error_string(ERR_get_error(), NULL));
 		goto fail;
 	}
@@ -2175,12 +2775,57 @@
 	wpabuf_free(buf);
 	buf = NULL;
 	goto done;
+#endif /* OpenSSL version >= 3.0 */
 }
 
 
 struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
 					const u8 *key, size_t len)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	EVP_PKEY *peerkey = EVP_PKEY_new();
+	EVP_PKEY_CTX *ctx;
+	size_t res_len;
+	struct wpabuf *res = NULL;
+	u8 *peer;
+
+	/* Encode using SECG SEC 1, Sec. 2.3.4 format */
+	peer = os_malloc(1 + len);
+	if (!peer)
+		return NULL;
+	peer[0] = inc_y ? 0x04 : 0x02;
+	os_memcpy(peer + 1, key, len);
+
+	if (!peerkey ||
+	    EVP_PKEY_copy_parameters(peerkey, ecdh->pkey) != 1 ||
+	    EVP_PKEY_set1_encoded_public_key(peerkey, peer, 1 + len) != 1) {
+		wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_set1_encoded_public_key failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+		EVP_PKEY_free(peerkey);
+		os_free(peer);
+		return NULL;
+	}
+	os_free(peer);
+
+	ctx = EVP_PKEY_CTX_new(ecdh->pkey, NULL);
+	if (!ctx ||
+	    EVP_PKEY_derive_init(ctx) != 1 ||
+	    EVP_PKEY_derive_set_peer(ctx, peerkey) != 1 ||
+	    EVP_PKEY_derive(ctx, NULL, &res_len) != 1 ||
+	    !(res = wpabuf_alloc(res_len)) ||
+	    EVP_PKEY_derive(ctx, wpabuf_mhead(res), &res_len) != 1) {
+		wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_derive failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+		wpabuf_free(res);
+		res = NULL;
+	} else {
+		wpabuf_put(res, res_len);
+	}
+
+	EVP_PKEY_free(peerkey);
+	EVP_PKEY_CTX_free(ctx);
+	return res;
+#else /* OpenSSL version >= 3.0 */
 	BIGNUM *x, *y = NULL;
 	EVP_PKEY_CTX *ctx = NULL;
 	EVP_PKEY *peerkey = NULL;
@@ -2198,19 +2843,18 @@
 		y = BN_bin2bn(key + len / 2, len / 2, NULL);
 		if (!y)
 			goto fail;
-		if (!EC_POINT_set_affine_coordinates_GFp(ecdh->ec->group, pub,
-							 x, y,
-							 ecdh->ec->bnctx)) {
+		if (!EC_POINT_set_affine_coordinates(ecdh->ec->group, pub,
+						     x, y, ecdh->ec->bnctx)) {
 			wpa_printf(MSG_ERROR,
-				   "OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
+				   "OpenSSL: EC_POINT_set_affine_coordinates failed: %s",
 				   ERR_error_string(ERR_get_error(), NULL));
 			goto fail;
 		}
-	} else if (!EC_POINT_set_compressed_coordinates_GFp(ecdh->ec->group,
-							    pub, x, 0,
-							    ecdh->ec->bnctx)) {
+	} else if (!EC_POINT_set_compressed_coordinates(ecdh->ec->group,
+							pub, x, 0,
+							ecdh->ec->bnctx)) {
 		wpa_printf(MSG_ERROR,
-			   "OpenSSL: EC_POINT_set_compressed_coordinates_GFp failed: %s",
+			   "OpenSSL: EC_POINT_set_compressed_coordinates failed: %s",
 			   ERR_error_string(ERR_get_error(), NULL));
 		goto fail;
 	}
@@ -2270,6 +2914,7 @@
 	wpabuf_free(secret);
 	secret = NULL;
 	goto done;
+#endif /* OpenSSL version >= 3.0 */
 }
 
 
@@ -2370,9 +3015,9 @@
 	if (!x || !y || !point)
 		goto fail;
 
-	if (!EC_POINT_set_affine_coordinates_GFp(ec_group, point, x, y, ctx)) {
+	if (!EC_POINT_set_affine_coordinates(ec_group, point, x, y, ctx)) {
 		wpa_printf(MSG_ERROR,
-			   "OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
+			   "OpenSSL: EC_POINT_set_affine_coordinates failed: %s",
 			   ERR_error_string(ERR_get_error(), NULL));
 		goto fail;
 	}
@@ -2777,12 +3422,53 @@
 }
 
 
-struct wpabuf * crypto_ec_key_sign_r_s(struct crypto_ec_key *key,
-				       const u8 *data, size_t len)
+static int openssl_evp_pkey_ec_prime_len(struct crypto_ec_key *key)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	char gname[50];
+	int nid;
+	EC_GROUP *group;
+	BIGNUM *prime = NULL;
+	int prime_len = -1;
+
+	if (EVP_PKEY_get_group_name((EVP_PKEY *) key, gname, sizeof(gname),
+				    NULL) != 1)
+		return -1;
+	nid = OBJ_txt2nid(gname);
+	group = EC_GROUP_new_by_curve_name(nid);
+	prime = BN_new();
+	if (!group || !prime)
+		return -1;
+	if (EC_GROUP_get_curve(group, prime, NULL, NULL, NULL) == 1)
+		prime_len = BN_num_bytes(prime);
+	EC_GROUP_free(group);
+	BN_free(prime);
+	return prime_len;
+#else
 	const EC_GROUP *group;
 	const EC_KEY *eckey;
 	BIGNUM *prime = NULL;
+	int prime_len = -1;
+
+	eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key);
+	if (!eckey)
+		goto fail;
+	group = EC_KEY_get0_group(eckey);
+	prime = BN_new();
+	if (!prime || !group ||
+	    !EC_GROUP_get_curve(group, prime, NULL, NULL, NULL))
+		goto fail;
+	prime_len = BN_num_bytes(prime);
+fail:
+	BN_free(prime);
+	return prime_len;
+#endif
+}
+
+
+struct wpabuf * crypto_ec_key_sign_r_s(struct crypto_ec_key *key,
+				       const u8 *data, size_t len)
+{
 	ECDSA_SIG *sig = NULL;
 	const BIGNUM *r, *s;
 	u8 *r_buf, *s_buf;
@@ -2790,20 +3476,15 @@
 	const unsigned char *p;
 	int prime_len;
 
+	prime_len = openssl_evp_pkey_ec_prime_len(key);
+	if (prime_len < 0)
+		return NULL;
+
 	buf = crypto_ec_key_sign(key, data, len);
 	if (!buf)
 		return NULL;
 
 	/* Extract (r,s) from Ecdsa-Sig-Value */
-	eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key);
-	if (!eckey)
-		goto fail;
-	group = EC_KEY_get0_group(eckey);
-	prime = BN_new();
-	if (!prime || !group ||
-	    !EC_GROUP_get_curve_GFp(group, prime, NULL, NULL, NULL))
-		goto fail;
-	prime_len = BN_num_bytes(prime);
 
 	p = wpabuf_head(buf);
 	sig = d2i_ECDSA_SIG(NULL, &p, wpabuf_len(buf));
@@ -2822,7 +3503,6 @@
 		goto fail;
 
 out:
-	BN_free(prime);
 	ECDSA_SIG_free(sig);
 	return buf;
 fail:
@@ -2893,6 +3573,15 @@
 
 int crypto_ec_key_group(struct crypto_ec_key *key)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	char gname[50];
+	int nid;
+
+	if (EVP_PKEY_get_group_name((EVP_PKEY *) key, gname, sizeof(gname),
+				    NULL) != 1)
+		return -1;
+	nid = OBJ_txt2nid(gname);
+#else
 	const EC_KEY *eckey;
 	const EC_GROUP *group;
 	int nid;
@@ -2904,6 +3593,7 @@
 	if (!group)
 		return -1;
 	nid = EC_GROUP_get_curve_name(group);
+#endif
 	switch (nid) {
 	case NID_X9_62_prime256v1:
 		return 19;
@@ -2932,8 +3622,13 @@
 
 int crypto_ec_key_cmp(struct crypto_ec_key *key1, struct crypto_ec_key *key2)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	if (EVP_PKEY_eq((EVP_PKEY *) key1, (EVP_PKEY *) key2) != 1)
+		return -1;
+#else
 	if (EVP_PKEY_cmp((EVP_PKEY *) key1, (EVP_PKEY *) key2) != 1)
 		return -1;
+#endif
 	return 0;
 }
 
@@ -3242,3 +3937,138 @@
 }
 
 #endif /* CONFIG_ECC */
+
+
+static EVP_PKEY * crypto_rsa_key_read_public(FILE *f)
+{
+	EVP_PKEY *pkey;
+	X509 *x509;
+
+	pkey = PEM_read_PUBKEY(f, NULL, NULL, NULL);
+	if (pkey)
+		return pkey;
+
+	rewind(f);
+	x509 = PEM_read_X509(f, NULL, NULL, NULL);
+	if (!x509)
+		return NULL;
+
+	pkey = X509_get_pubkey(x509);
+	X509_free(x509);
+
+	if (!pkey)
+		return NULL;
+	if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) {
+		EVP_PKEY_free(pkey);
+		return NULL;
+	}
+
+	return pkey;
+}
+
+
+struct crypto_rsa_key * crypto_rsa_key_read(const char *file, bool private_key)
+{
+	FILE *f;
+	EVP_PKEY *pkey;
+
+	f = fopen(file, "r");
+	if (!f)
+		return NULL;
+	if (private_key)
+		pkey = PEM_read_PrivateKey(f, NULL, NULL, NULL);
+	else
+		pkey = crypto_rsa_key_read_public(f);
+	fclose(f);
+	return (struct crypto_rsa_key *) pkey;
+}
+
+
+#ifndef OPENSSL_NO_SHA256
+
+struct wpabuf * crypto_rsa_oaep_sha256_encrypt(struct crypto_rsa_key *key,
+					       const struct wpabuf *in)
+{
+#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x30400000L
+	EVP_PKEY *pkey = (EVP_PKEY *) key;
+	EVP_PKEY_CTX *pkctx;
+	struct wpabuf *res = NULL;
+	size_t outlen;
+
+	pkctx = EVP_PKEY_CTX_new(pkey, NULL);
+	if (!pkctx)
+		goto fail;
+
+	if (EVP_PKEY_encrypt_init(pkctx) != 1 ||
+	    EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_OAEP_PADDING) <= 0 ||
+	    EVP_PKEY_CTX_set_rsa_oaep_md(pkctx, EVP_sha256()) <= 0 ||
+	    EVP_PKEY_encrypt(pkctx, NULL, &outlen, wpabuf_head(in),
+			     wpabuf_len(in)) != 1 ||
+	    !(res = wpabuf_alloc(outlen)) ||
+	    EVP_PKEY_encrypt(pkctx, wpabuf_put(res, 0), &outlen,
+			     wpabuf_head(in), wpabuf_len(in)) != 1) {
+		wpabuf_free(res);
+		res = NULL;
+		goto fail;
+	}
+	wpabuf_put(res, outlen);
+
+fail:
+	EVP_PKEY_CTX_free(pkctx);
+	return res;
+#else
+	wpa_printf(MSG_ERROR, "%s() not supported", __func__);
+	return NULL;
+#endif
+}
+
+
+struct wpabuf * crypto_rsa_oaep_sha256_decrypt(struct crypto_rsa_key *key,
+					       const struct wpabuf *in)
+{
+#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x30400000L
+	EVP_PKEY *pkey = (EVP_PKEY *) key;
+	EVP_PKEY_CTX *pkctx;
+	struct wpabuf *res = NULL;
+	size_t outlen;
+
+	pkctx = EVP_PKEY_CTX_new(pkey, NULL);
+	if (!pkctx)
+		goto fail;
+
+	if (EVP_PKEY_decrypt_init(pkctx) != 1 ||
+	    EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_OAEP_PADDING) <= 0 ||
+	    EVP_PKEY_CTX_set_rsa_oaep_md(pkctx, EVP_sha256()) <= 0 ||
+	    EVP_PKEY_decrypt(pkctx, NULL, &outlen, wpabuf_head(in),
+			     wpabuf_len(in)) != 1 ||
+	    !(res = wpabuf_alloc(outlen)) ||
+	    EVP_PKEY_decrypt(pkctx, wpabuf_put(res, 0), &outlen,
+			     wpabuf_head(in), wpabuf_len(in)) != 1) {
+		wpabuf_free(res);
+		res = NULL;
+		goto fail;
+	}
+	wpabuf_put(res, outlen);
+
+fail:
+	EVP_PKEY_CTX_free(pkctx);
+	return res;
+#else
+	wpa_printf(MSG_ERROR, "%s() not supported", __func__);
+	return NULL;
+#endif
+}
+
+#endif /* OPENSSL_NO_SHA256 */
+
+
+void crypto_rsa_key_free(struct crypto_rsa_key *key)
+{
+	EVP_PKEY_free((EVP_PKEY *) key);
+}
+
+
+void crypto_unload(void)
+{
+	openssl_unload_legacy_provider();
+}
diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c
index 00ecf61..f47beeb 100644
--- a/src/crypto/crypto_wolfssl.c
+++ b/src/crypto/crypto_wolfssl.c
@@ -26,6 +26,8 @@
 #include <wolfssl/wolfcrypt/dh.h>
 #include <wolfssl/wolfcrypt/cmac.h>
 #include <wolfssl/wolfcrypt/ecc.h>
+#include <wolfssl/wolfcrypt/asn_public.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
 #include <wolfssl/openssl/bn.h>
 
 
@@ -85,6 +87,7 @@
 		wc_ShaUpdate(&sha, addr[i], len[i]);
 
 	wc_ShaFinal(&sha, mac);
+	wc_ShaFree(&sha);
 
 	return 0;
 }
@@ -106,6 +109,7 @@
 		wc_Sha256Update(&sha256, addr[i], len[i]);
 
 	wc_Sha256Final(&sha256, mac);
+	wc_Sha256Free(&sha256);
 
 	return 0;
 }
@@ -128,6 +132,7 @@
 		wc_Sha384Update(&sha384, addr[i], len[i]);
 
 	wc_Sha384Final(&sha384, mac);
+	wc_Sha384Free(&sha384);
 
 	return 0;
 }
@@ -150,6 +155,7 @@
 		wc_Sha512Update(&sha512, addr[i], len[i]);
 
 	wc_Sha512Final(&sha512, mac);
+	wc_Sha512Free(&sha512);
 
 	return 0;
 }
@@ -169,13 +175,16 @@
 	if (TEST_FAIL())
 		return -1;
 
-	if (wc_HmacSetKey(&hmac, type, key, (word32) key_len) != 0)
+	if (wc_HmacInit(&hmac, NULL, INVALID_DEVID) != 0 ||
+	    wc_HmacSetKey(&hmac, type, key, (word32) key_len) != 0)
 		return -1;
 	for (i = 0; i < num_elem; i++)
 		if (wc_HmacUpdate(&hmac, addr[i], len[i]) != 0)
 			return -1;
 	if (wc_HmacFinal(&hmac, mac) != 0)
 		return -1;
+	wc_HmacFree(&hmac);
+
 	return 0;
 }
 
@@ -274,9 +283,18 @@
 int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
 		int iterations, u8 *buf, size_t buflen)
 {
-	if (wc_PBKDF2(buf, (const byte*)passphrase, os_strlen(passphrase), ssid,
-		      ssid_len, iterations, buflen, WC_SHA) != 0)
+	int ret;
+
+	ret = wc_PBKDF2(buf, (const byte *) passphrase, os_strlen(passphrase),
+			ssid, ssid_len, iterations, buflen, WC_SHA);
+	if (ret != 0) {
+		if (ret == HMAC_MIN_KEYLEN_E) {
+			wpa_printf(MSG_ERROR,
+				   "wolfSSL: Password is too short. Make sure your password is at least %d characters long. This is a requirement for FIPS builds.",
+				   HMAC_FIPS_MIN_KEY);
+		}
 		return -1;
+	}
 	return 0;
 }
 
@@ -409,8 +427,11 @@
 }
 
 
+#ifndef CONFIG_FIPS
+#ifndef CONFIG_OPENSSL_INTERNAL_AES_WRAP
 int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
 {
+#ifdef HAVE_AES_KEYWRAP
 	int ret;
 
 	if (TEST_FAIL())
@@ -419,12 +440,16 @@
 	ret = wc_AesKeyWrap(kek, kek_len, plain, n * 8, cipher, (n + 1) * 8,
 			    NULL);
 	return ret != (n + 1) * 8 ? -1 : 0;
+#else /* HAVE_AES_KEYWRAP */
+	return -1;
+#endif /* HAVE_AES_KEYWRAP */
 }
 
 
 int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
 	       u8 *plain)
 {
+#ifdef HAVE_AES_KEYWRAP
 	int ret;
 
 	if (TEST_FAIL())
@@ -433,7 +458,12 @@
 	ret = wc_AesKeyUnWrap(kek, kek_len, cipher, (n + 1) * 8, plain, n * 8,
 			      NULL);
 	return ret != n * 8 ? -1 : 0;
+#else /* HAVE_AES_KEYWRAP */
+	return -1;
+#endif /* HAVE_AES_KEYWRAP */
 }
+#endif /* CONFIG_OPENSSL_INTERNAL_AES_WRAP */
+#endif /* CONFIG_FIPS */
 
 
 #ifndef CONFIG_NO_RC4
@@ -670,6 +700,7 @@
 	    != 0)
 		goto done;
 
+	priv_sz = pub_sz = RFC3526_LEN;
 	if (wc_DhGenerateKeyPair(dh, &rng, wpabuf_mhead(privkey), &priv_sz,
 				 wpabuf_mhead(pubkey), &pub_sz) != 0)
 		goto done;
@@ -803,6 +834,7 @@
 	if (wc_DhSetKey(dh, prime, prime_len, &generator, 1) != 0)
 		goto done;
 
+	priv_sz = pub_sz = prime_len;
 	if (wc_DhGenerateKeyPair(dh, &rng, privkey, &priv_sz, pubkey, &pub_sz)
 	    != 0)
 		goto done;
@@ -919,7 +951,8 @@
 		goto done;
 	}
 
-	if (wc_HmacSetKey(&hash->hmac, type, key, key_len) != 0)
+	if (wc_HmacInit(&hash->hmac, NULL, INVALID_DEVID) != 0 ||
+	    wc_HmacSetKey(&hash->hmac, type, key, key_len) != 0)
 		goto done;
 
 	ret = hash;
@@ -1634,35 +1667,21 @@
 crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
 			      const struct crypto_bignum *x)
 {
-	mp_int *y2 = NULL;
-	mp_int t;
-	int calced = 0;
+	mp_int *y2;
 
 	if (TEST_FAIL())
 		return NULL;
 
-	if (mp_init(&t) != MP_OKAY)
-		return NULL;
-
+	/* y^2 = x^3 + ax + b = (x^2 + a)x + b */
 	y2 = (mp_int *) crypto_bignum_init();
-	if (!y2)
-		goto done;
-
-	if (mp_sqrmod((mp_int *) x, &e->prime, y2) != 0 ||
+	if (!y2 ||
+	    mp_sqrmod((mp_int *) x, &e->prime, y2) != 0 ||
+	    mp_addmod(y2, &e->a, &e->prime, y2) != 0 ||
 	    mp_mulmod((mp_int *) x, y2, &e->prime, y2) != 0 ||
-	    mp_mulmod((mp_int *) x, &e->a, &e->prime, &t) != 0 ||
-	    mp_addmod(y2, &t, &e->prime, y2) != 0 ||
-	    mp_addmod(y2, &e->b, &e->prime, y2) != 0)
-		goto done;
-
-	calced = 1;
-done:
-	if (!calced) {
-		if (y2) {
-			mp_clear(y2);
-			os_free(y2);
-		}
-		mp_clear(&t);
+	    mp_addmod(y2, &e->b, &e->prime, y2) != 0) {
+		mp_clear(y2);
+		os_free(y2);
+		y2 = NULL;
 	}
 
 	return (struct crypto_bignum *) y2;
@@ -1694,33 +1713,37 @@
 
 struct crypto_ecdh {
 	struct crypto_ec *ec;
+	WC_RNG rng;
 };
 
 struct crypto_ecdh * crypto_ecdh_init(int group)
 {
 	struct crypto_ecdh *ecdh = NULL;
-	WC_RNG rng;
 	int ret;
 
-	if (wc_InitRng(&rng) != 0)
-		goto fail;
-
 	ecdh = os_zalloc(sizeof(*ecdh));
 	if (!ecdh)
 		goto fail;
 
+	if (wc_InitRng(&ecdh->rng) != 0)
+		goto fail;
+
 	ecdh->ec = crypto_ec_init(group);
 	if (!ecdh->ec)
 		goto fail;
 
-	ret = wc_ecc_make_key_ex(&rng, ecdh->ec->key.dp->size, &ecdh->ec->key,
-				 ecdh->ec->key.dp->id);
+	ret = wc_ecc_make_key_ex(&ecdh->rng, ecdh->ec->key.dp->size,
+				 &ecdh->ec->key, ecdh->ec->key.dp->id);
 	if (ret < 0)
 		goto fail;
 
-done:
-	wc_FreeRng(&rng);
+#if defined(ECC_TIMING_RESISTANT) && !defined(CONFIG_FIPS)
+	ret = wc_ecc_set_rng(&ecdh->ec->key, &ecdh->rng);
+	if (ret < 0)
+		goto fail;
+#endif /* ECC_TIMING_RESISTANT && !CONFIG_FIPS */
 
+done:
 	return ecdh;
 fail:
 	crypto_ecdh_deinit(ecdh);
@@ -1733,6 +1756,7 @@
 {
 	if (ecdh) {
 		crypto_ec_deinit(ecdh->ec);
+		wc_FreeRng(&ecdh->rng);
 		os_free(ecdh);
 	}
 }
@@ -1822,4 +1846,266 @@
 	return crypto_ec_prime_len(ecdh->ec);
 }
 
+
+struct crypto_ec_key {
+	ecc_key *eckey;
+	WC_RNG *rng; /* Needs to be initialized before use.
+		      * *NOT* initialized in crypto_ec_key_init */
+};
+
+
+static struct crypto_ec_key * crypto_ec_key_init(void)
+{
+	struct crypto_ec_key *key;
+
+	key = os_zalloc(sizeof(struct crypto_ec_key));
+	if (key) {
+#ifdef CONFIG_FIPS
+		key->eckey = os_zalloc(sizeof(ecc_key));
+#else /* CONFIG_FIPS */
+		key->eckey = wc_ecc_key_new(NULL);
+#endif /* CONFIG_FIPS */
+		/* Omit key->rng initialization because it seeds itself and thus
+		 * consumes entropy that may never be used. Lazy initialize when
+		 * necessary. */
+		if (!key->eckey) {
+			wpa_printf(MSG_ERROR,
+				   "wolfSSL: crypto_ec_key_init() failed");
+			crypto_ec_key_deinit(key);
+			key = NULL;
+		}
+#ifdef CONFIG_FIPS
+		else if (wc_ecc_init_ex(key->eckey, NULL, INVALID_DEVID) != 0) {
+			wpa_printf(MSG_ERROR, "wolfSSL: wc_ecc_init_ex failed");
+			crypto_ec_key_deinit(key);
+			key = NULL;
+		}
+#endif /* CONFIG_FIPS */
+	}
+	return key;
+}
+
+
+void crypto_ec_key_deinit(struct crypto_ec_key *key)
+{
+	if (key) {
+#ifdef CONFIG_FIPS
+		os_free(key->rng);
+		os_free(key->eckey);
+#else /* CONFIG_FIPS */
+		wc_rng_free(key->rng);
+		wc_ecc_key_free(key->eckey);
+#endif /* CONFIG_FIPS */
+		os_free(key);
+	}
+}
+
+
+struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len)
+{
+	struct crypto_ec_key *ret;
+	word32 idx = 0;
+
+	ret = crypto_ec_key_init();
+	if (!ret) {
+		wpa_printf(MSG_ERROR, "wolfSSL: crypto_ec_key_init failed");
+		goto fail;
+	}
+
+	if (wc_EccPrivateKeyDecode(der, &idx, ret->eckey, (word32) der_len) !=
+	    0) {
+		wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPrivateKeyDecode failed");
+		goto fail;
+	}
+
+	return ret;
+fail:
+	if (ret)
+		crypto_ec_key_deinit(ret);
+	return NULL;
+}
+
+
+int crypto_ec_key_group(struct crypto_ec_key *key)
+{
+
+	if (!key || !key->eckey || !key->eckey->dp) {
+		wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters",
+			   __func__);
+		return -1;
+	}
+
+	switch (key->eckey->dp->id) {
+	case ECC_SECP256R1:
+		return 19;
+	case ECC_SECP384R1:
+		return 20;
+	case ECC_SECP521R1:
+		return 21;
+	case ECC_BRAINPOOLP256R1:
+		return 28;
+	case ECC_BRAINPOOLP384R1:
+		return 29;
+	case ECC_BRAINPOOLP512R1:
+		return 30;
+	}
+
+	wpa_printf(MSG_ERROR, "wolfSSL: Unsupported curve (id=%d) in EC key",
+		   key->eckey->dp->id);
+	return -1;
+}
+
+
+struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key)
+{
+	byte *der = NULL;
+	int der_len;
+	struct wpabuf *ret = NULL;
+
+	if (!key || !key->eckey) {
+		wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters",
+			   __func__);
+		goto fail;
+	}
+
+	der_len = wc_EccPublicKeyDerSize(key->eckey, 1);
+	if (der_len <= 0) {
+		wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPublicKeyDerSize failed");
+		goto fail;
+	}
+
+	der = os_malloc(der_len);
+	if (!der)
+		goto fail;
+
+	der_len = wc_EccPublicKeyToDer(key->eckey, der, der_len, 1);
+	if (der_len <= 0) {
+		wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPublicKeyToDer failed");
+		goto fail;
+	}
+
+	ret = wpabuf_alloc_copy(der, der_len);
+	os_free(der);
+	return ret;
+
+fail:
+	os_free(der);
+	return NULL;
+}
+
+
+struct crypto_ec_key * crypto_ec_key_parse_pub(const u8 *der, size_t der_len)
+{
+	word32 idx = 0;
+	struct crypto_ec_key *ret = NULL;
+
+	ret = crypto_ec_key_init();
+	if (!ret) {
+		wpa_printf(MSG_ERROR, "wolfSSL: crypto_ec_key_init failed");
+		goto fail;
+	}
+
+	if (wc_EccPublicKeyDecode(der, &idx, ret->eckey, (word32) der_len) != 0)
+	{
+		wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPublicKeyDecode failed");
+		goto fail;
+	}
+
+	return ret;
+fail:
+	crypto_ec_key_deinit(ret);
+	return NULL;
+}
+
+
+struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data,
+				   size_t len)
+{
+	byte *der = NULL;
+	int der_len;
+	word32 w32_der_len;
+	struct wpabuf *ret = NULL;
+
+	if (!key || !key->eckey || !data || len == 0) {
+		wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters",
+			   __func__);
+		goto fail;
+	}
+
+	if (!key->rng) {
+		/* Lazy init key->rng */
+#ifdef CONFIG_FIPS
+		key->rng = os_zalloc(sizeof(WC_RNG));
+#else /* CONFIG_FIPS */
+		key->rng = wc_rng_new(NULL, 0, NULL);
+#endif /* CONFIG_FIPS */
+		if (!key->rng) {
+			wpa_printf(MSG_ERROR, "wolfSSL: wc_rng_new failed");
+			goto fail;
+		}
+#ifdef CONFIG_FIPS
+		if (wc_InitRng(key->rng) != 0) {
+			wpa_printf(MSG_ERROR, "wolfSSL: wc_InitRng failed");
+			goto fail;
+		}
+#endif /* CONFIG_FIPS */
+	}
+
+	der_len = wc_ecc_sig_size(key->eckey);
+	if (der_len <= 0) {
+		wpa_printf(MSG_ERROR, "wolfSSL: wc_ecc_sig_size failed");
+		goto fail;
+	}
+
+	der = os_malloc(der_len);
+	if (!der)
+		goto fail;
+
+	w32_der_len = (word32) der_len;
+	if (wc_ecc_sign_hash(data, len, der, &w32_der_len, key->rng, key->eckey)
+	    != 0) {
+		wpa_printf(MSG_ERROR, "wolfSSL: wc_ecc_sign_hash failed");
+		goto fail;
+	}
+
+	ret = wpabuf_alloc_copy(der, der_len);
+	os_free(der);
+	if (!ret)
+		wpa_printf(MSG_ERROR, "wolfSSL: wpabuf_alloc_copy failed");
+	return ret;
+fail:
+	os_free(der);
+	return NULL;
+}
+
+
+int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data,
+				   size_t len, const u8 *sig, size_t sig_len)
+{
+	int res = 0;
+
+	if (!key || !key->eckey || !data || len == 0 || !sig || sig_len == 0) {
+		wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters",
+			   __func__);
+		return -1;
+	}
+
+	if (wc_ecc_verify_hash(sig, sig_len, data, len, &res, key->eckey) != 0)
+	{
+		wpa_printf(MSG_ERROR, "wolfSSL: wc_ecc_verify_hash failed");
+		return -1;
+	}
+
+	if (res != 1)
+		wpa_printf(MSG_DEBUG,
+			   "wolfSSL: crypto_ec_key_verify_signature failed");
+
+	return res;
+}
+
 #endif /* CONFIG_ECC */
+
+
+void crypto_unload(void)
+{
+}
diff --git a/src/crypto/sha1-pbkdf2.c b/src/crypto/sha1-pbkdf2.c
index 8effe2f..d2bdc95 100644
--- a/src/crypto/sha1-pbkdf2.c
+++ b/src/crypto/sha1-pbkdf2.c
@@ -50,6 +50,8 @@
 		for (j = 0; j < SHA1_MAC_LEN; j++)
 			digest[j] ^= tmp2[j];
 	}
+	forced_memzero(tmp, SHA1_MAC_LEN);
+	forced_memzero(tmp2, SHA1_MAC_LEN);
 
 	return 0;
 }
@@ -87,6 +89,7 @@
 		pos += plen;
 		left -= plen;
 	}
+	forced_memzero(digest, SHA1_MAC_LEN);
 
 	return 0;
 }
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 09fb73b..7a2ee32 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -22,7 +22,8 @@
 	TLS_CERT_CHAIN_SUCCESS,
 	TLS_CERT_CHAIN_FAILURE,
 	TLS_PEER_CERTIFICATE,
-	TLS_ALERT
+	TLS_ALERT,
+	TLS_UNSAFE_RENEGOTIATION_DISABLED,
 };
 
 /*
@@ -112,6 +113,7 @@
 #define TLS_CONN_ENABLE_TLSv1_1 BIT(15)
 #define TLS_CONN_ENABLE_TLSv1_2 BIT(16)
 #define TLS_CONN_TEAP_ANON_DH BIT(17)
+#define TLS_CONN_ALLOW_UNSAFE_RENEGOTIATION BIT(18)
 
 /**
  * struct tls_connection_params - Parameters for TLS connection
@@ -148,8 +150,6 @@
  * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
  * passphrase is used.
  * @dh_file: File name for DH/DSA data in PEM format, or %NULL if not used
- * @dh_blob: dh_file as inlined data or %NULL if not used
- * @dh_blob_len: dh_blob length
  * @engine: 1 = use engine (e.g., a smartcard) for private key operations
  * (this is OpenSSL specific for now)
  * @engine_id: engine id string (this is OpenSSL specific for now)
@@ -198,8 +198,6 @@
 	const char *private_key_passwd;
 	const char *private_key_passwd2;
 	const char *dh_file;
-	const u8 *dh_blob;
-	size_t dh_blob_len;
 
 	/* OpenSSL specific variables */
 	int engine;
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index daa01d9..e3f5b5a 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -1766,6 +1766,7 @@
 void tls_connection_set_success_data(struct tls_connection *conn,
 				     struct wpabuf *data)
 {
+	wpabuf_free(data);
 }
 
 
diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c
index 8095b43..f3e05ce 100644
--- a/src/crypto/tls_internal.c
+++ b/src/crypto/tls_internal.c
@@ -281,13 +281,6 @@
 		return -1;
 	}
 
-	if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
-			       params->dh_blob_len)) {
-		wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
-		tlsv1_cred_free(cred);
-		return -1;
-	}
-
 	if (tlsv1_client_set_cred(conn->client, cred) < 0) {
 		tlsv1_cred_free(cred);
 		return -1;
@@ -342,8 +335,7 @@
 		return -1;
 	}
 
-	if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
-			       params->dh_blob_len)) {
+	if (tlsv1_set_dhparams(cred, params->dh_file, NULL, 0)) {
 		wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
 		return -1;
 	}
@@ -791,6 +783,7 @@
 void tls_connection_set_success_data(struct tls_connection *conn,
 				     struct wpabuf *data)
 {
+	wpabuf_free(data);
 }
 
 
diff --git a/src/crypto/tls_none.c b/src/crypto/tls_none.c
index 6d6fb0c..87f45f8 100644
--- a/src/crypto/tls_none.c
+++ b/src/crypto/tls_none.c
@@ -212,6 +212,7 @@
 void tls_connection_set_success_data(struct tls_connection *conn,
 				     struct wpabuf *data)
 {
+	wpabuf_free(data);
 }
 
 
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index ba3ef80..a1b5166 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -7,6 +7,9 @@
  */
 
 #include "includes.h"
+#ifdef CONFIG_TESTING_OPTIONS
+#include <fcntl.h>
+#endif /* CONFIG_TESTING_OPTIONS */
 
 #ifndef CONFIG_SMARTCARD
 #ifndef OPENSSL_NO_ENGINE
@@ -24,14 +27,21 @@
 #ifndef OPENSSL_NO_ENGINE
 #include <openssl/engine.h>
 #endif /* OPENSSL_NO_ENGINE */
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/core_names.h>
+#include <openssl/decoder.h>
+#include <openssl/param_build.h>
+#else /* OpenSSL version >= 3.0 */
 #ifndef OPENSSL_NO_DSA
 #include <openssl/dsa.h>
 #endif
 #ifndef OPENSSL_NO_DH
 #include <openssl/dh.h>
 #endif
+#endif /* OpenSSL version >= 3.0 */
 
 #include "common.h"
+#include "utils/list.h"
 #include "crypto.h"
 #include "sha1.h"
 #include "sha256.h"
@@ -65,9 +75,7 @@
 #endif /* OPENSSL_NO_TLSEXT */
 #endif /* SSL_set_tlsext_status_type */
 
-#if (OPENSSL_VERSION_NUMBER < 0x10100000L || \
-     (defined(LIBRESSL_VERSION_NUMBER) && \
-      LIBRESSL_VERSION_NUMBER < 0x20700000L)) && \
+#if OPENSSL_VERSION_NUMBER < 0x10100000L && \
     !defined(BORINGSSL_API_VERSION)
 /*
  * SSL_get_client_random() and SSL_get_server_random() were added in OpenSSL
@@ -111,17 +119,7 @@
 
 #endif
 
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
-	(defined(LIBRESSL_VERSION_NUMBER) && \
-	 LIBRESSL_VERSION_NUMBER < 0x20700000L)
-#ifdef CONFIG_SUITEB
-static int RSA_bits(const RSA *r)
-{
-	return BN_num_bits(r->n);
-}
-#endif /* CONFIG_SUITEB */
-
-
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
 static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x)
 {
 	return ASN1_STRING_data((ASN1_STRING *) x);
@@ -234,12 +232,18 @@
 static int tls_openssl_ref_count = 0;
 static int tls_ex_idx_session = -1;
 
+struct tls_session_data {
+	struct dl_list list;
+	struct wpabuf *buf;
+};
+
 struct tls_context {
 	void (*event_cb)(void *ctx, enum tls_event ev,
 			 union tls_event_data *data);
 	void *cb_ctx;
 	int cert_in_cb;
 	char *ocsp_stapling_response;
+	struct dl_list sessions; /* struct tls_session_data */
 };
 
 static struct tls_context *tls_global = NULL;
@@ -307,6 +311,7 @@
 	struct tls_context *context = os_zalloc(sizeof(*context));
 	if (context == NULL)
 		return NULL;
+	dl_list_init(&context->sessions);
 	if (conf) {
 		context->event_cb = conf->event_cb;
 		context->cb_ctx = conf->cb_ctx;
@@ -958,21 +963,53 @@
 #endif /* OPENSSL_NO_ENGINE */
 
 
+static struct tls_session_data * get_session_data(struct tls_context *context,
+						  const struct wpabuf *buf)
+{
+	struct tls_session_data *data;
+
+	dl_list_for_each(data, &context->sessions, struct tls_session_data,
+			 list) {
+		if (data->buf == buf)
+			return data;
+	}
+
+	return NULL;
+}
+
+
 static void remove_session_cb(SSL_CTX *ctx, SSL_SESSION *sess)
 {
 	struct wpabuf *buf;
+	struct tls_context *context;
+	struct tls_session_data *found;
+
+	wpa_printf(MSG_DEBUG,
+		   "OpenSSL: Remove session %p (tls_ex_idx_session=%d)", sess,
+		   tls_ex_idx_session);
 
 	if (tls_ex_idx_session < 0)
 		return;
 	buf = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
 	if (!buf)
 		return;
+
+	context = SSL_CTX_get_app_data(ctx);
+	SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL);
+	found = get_session_data(context, buf);
+	if (!found) {
+		wpa_printf(MSG_DEBUG,
+			   "OpenSSL: Do not free application session data %p (sess %p)",
+			   buf, sess);
+		return;
+	}
+
+	dl_list_del(&found->list);
+	os_free(found);
 	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);
 }
 
 
@@ -1019,9 +1056,7 @@
 		}
 #endif /* OPENSSL_FIPS */
 #endif /* CONFIG_FIPS */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
-	(defined(LIBRESSL_VERSION_NUMBER) && \
-	 LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
 		SSL_load_error_strings();
 		SSL_library_init();
 #ifndef OPENSSL_NO_SHA256
@@ -1098,8 +1133,19 @@
 		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);
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && \
+	!defined(LIBRESSL_VERSION_NUMBER) && \
+	!defined(OPENSSL_IS_BORINGSSL)
+		/* One session ticket is sufficient for EAP-TLS */
+		SSL_CTX_set_num_tickets(ssl, 1);
+#endif
 	} else {
 		SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_OFF);
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && \
+	!defined(LIBRESSL_VERSION_NUMBER) && \
+	!defined(OPENSSL_IS_BORINGSSL)
+		SSL_CTX_set_num_tickets(ssl, 0);
+#endif
 	}
 
 	if (tls_ex_idx_session < 0) {
@@ -1148,18 +1194,30 @@
 	struct tls_data *data = ssl_ctx;
 	SSL_CTX *ssl = data->ssl;
 	struct tls_context *context = SSL_CTX_get_app_data(ssl);
+	struct tls_session_data *sess_data;
+
+	if (data->tls_session_lifetime > 0) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: Flush sessions");
+		SSL_CTX_flush_sessions(ssl, 0);
+		wpa_printf(MSG_DEBUG, "OpenSSL: Flush sessions - done");
+	}
+	while ((sess_data = dl_list_first(&context->sessions,
+					  struct tls_session_data, list))) {
+		wpa_printf(MSG_DEBUG,
+			   "OpenSSL: Freeing not-flushed session data %p",
+			   sess_data->buf);
+		wpabuf_free(sess_data->buf);
+		dl_list_del(&sess_data->list);
+		os_free(sess_data);
+	}
 	if (context != tls_global)
 		os_free(context);
-	if (data->tls_session_lifetime > 0)
-		SSL_CTX_flush_sessions(ssl, 0);
 	os_free(data->ca_cert);
 	SSL_CTX_free(ssl);
 
 	tls_openssl_ref_count--;
 	if (tls_openssl_ref_count == 0) {
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
-	(defined(LIBRESSL_VERSION_NUMBER) && \
-	 LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
 #ifndef OPENSSL_NO_ENGINE
 		ENGINE_cleanup();
 #endif /* OPENSSL_NO_ENGINE */
@@ -1561,6 +1619,63 @@
 }
 
 
+#ifdef CONFIG_TESTING_OPTIONS
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
+/*
+ * By setting the environment variable SSLKEYLOGFILE to a filename keying
+ * material will be exported that you may use with Wireshark to decode any
+ * TLS flows. Please see the following for more details:
+ *
+ *	https://gitlab.com/wireshark/wireshark/-/wikis/TLS#tls-decryption
+ *
+ * Example logging sessions are (you should delete the file on each run):
+ *
+ *	rm -f /tmp/sslkey.log
+ *	env SSLKEYLOGFILE=/tmp/sslkey.log hostapd ...
+ *
+ *	rm -f /tmp/sslkey.log
+ *	env SSLKEYLOGFILE=/tmp/sslkey.log wpa_supplicant ...
+ *
+ *	rm -f /tmp/sslkey.log
+ *	env SSLKEYLOGFILE=/tmp/sslkey.log eapol_test ...
+ */
+static void tls_keylog_cb(const SSL *ssl, const char *line)
+{
+	int fd;
+	const char *filename;
+	struct iovec iov[2];
+
+	filename = getenv("SSLKEYLOGFILE");
+	if (!filename)
+		return;
+
+	fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
+	if (fd < 0) {
+		wpa_printf(MSG_ERROR,
+			   "OpenSSL: Failed to open keylog file %s: %s",
+			   filename, strerror(errno));
+		return;
+	}
+
+	/* Assume less than _POSIX_PIPE_BUF (512) where writes are guaranteed
+	 * to be atomic for O_APPEND. */
+	iov[0].iov_base = (void *) line;
+	iov[0].iov_len = os_strlen(line);
+	iov[1].iov_base = "\n";
+	iov[1].iov_len = 1;
+
+	if (writev(fd, iov, ARRAY_SIZE(iov)) < 01) {
+		wpa_printf(MSG_DEBUG,
+			   "OpenSSL: Failed to write to keylog file %s: %s",
+			   filename, strerror(errno));
+	}
+
+	close(fd);
+}
+#endif
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
 struct tls_connection * tls_connection_init(void *ssl_ctx)
 {
 	struct tls_data *data = ssl_ctx;
@@ -1618,6 +1733,14 @@
 	SSL_clear_options(conn->ssl, SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
 #endif
 
+#ifdef CONFIG_TESTING_OPTIONS
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
+	/* Set the keylog file if the admin requested it. */
+	if (getenv("SSLKEYLOGFILE"))
+		SSL_CTX_set_keylog_callback(conn->ssl_ctx, tls_keylog_cb);
+#endif
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	conn->ssl_in = BIO_new(BIO_s_mem());
 	if (!conn->ssl_in) {
 		tls_show_errors(MSG_INFO, __func__,
@@ -2560,16 +2683,11 @@
 #ifdef CONFIG_SUITEB
 	if (conn->flags & TLS_CONN_SUITEB) {
 		EVP_PKEY *pk;
-		RSA *rsa;
 		int len = -1;
 
 		pk = X509_get_pubkey(err_cert);
 		if (pk) {
-			rsa = EVP_PKEY_get1_RSA(pk);
-			if (rsa) {
-				len = RSA_bits(rsa);
-				RSA_free(rsa);
-			}
+			len = EVP_PKEY_bits(pk);
 			EVP_PKEY_free(pk);
 		}
 
@@ -2960,7 +3078,6 @@
 
 
 #ifdef CONFIG_SUITEB
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L
 static int suiteb_cert_cb(SSL *ssl, void *arg)
 {
 	struct tls_connection *conn = arg;
@@ -2987,7 +3104,6 @@
 		   conn->server_dh_prime_len);
 	return 0;
 }
-#endif /* OPENSSL_VERSION_NUMBER */
 #endif /* CONFIG_SUITEB */
 
 
@@ -3003,6 +3119,11 @@
 		SSL_clear_options(ssl, SSL_OP_NO_TICKET);
 #endif /* SSL_OP_NO_TICKET */
 
+#ifdef SSL_OP_LEGACY_SERVER_CONNECT
+	if (flags & TLS_CONN_ALLOW_UNSAFE_RENEGOTIATION)
+		SSL_set_options(ssl, SSL_OP_LEGACY_SERVER_CONNECT);
+#endif /* SSL_OP_LEGACY_SERVER_CONNECT */
+
 #ifdef SSL_OP_NO_TLSv1
 	if (flags & TLS_CONN_DISABLE_TLSv1_0)
 		SSL_set_options(ssl, SSL_OP_NO_TLSv1);
@@ -3082,7 +3203,6 @@
 	/* Start with defaults from BoringSSL */
 	SSL_set_verify_algorithm_prefs(conn->ssl, NULL, 0);
 #endif /* OPENSSL_IS_BORINGSSL */
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L
 	if (flags & TLS_CONN_SUITEB_NO_ECDH) {
 		const char *ciphers = "DHE-RSA-AES256-GCM-SHA384";
 
@@ -3098,7 +3218,9 @@
 			return -1;
 		}
 	} else if (flags & TLS_CONN_SUITEB) {
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 		EC_KEY *ecdh;
+#endif
 		const char *ciphers =
 			"ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384";
 		int nid[1] = { NID_secp384r1 };
@@ -3115,6 +3237,14 @@
 			return -1;
 		}
 
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+		if (SSL_set1_groups(ssl, nid, 1) != 1) {
+			wpa_printf(MSG_INFO,
+				   "OpenSSL: Failed to set Suite B groups");
+			return -1;
+		}
+
+#else
 		if (SSL_set1_curves(ssl, nid, 1) != 1) {
 			wpa_printf(MSG_INFO,
 				   "OpenSSL: Failed to set Suite B curves");
@@ -3129,6 +3259,7 @@
 			return -1;
 		}
 		EC_KEY_free(ecdh);
+#endif
 	}
 	if (flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) {
 #ifdef OPENSSL_IS_BORINGSSL
@@ -3153,13 +3284,6 @@
 		SSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
 		SSL_set_cert_cb(ssl, suiteb_cert_cb, conn);
 	}
-#else /* OPENSSL_VERSION_NUMBER < 0x10002000L */
-	if (flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) {
-		wpa_printf(MSG_ERROR,
-			   "OpenSSL: Suite B RSA case not supported with this OpenSSL version");
-		return -1;
-	}
-#endif /* OPENSSL_VERSION_NUMBER */
 
 #ifdef OPENSSL_IS_BORINGSSL
 	if (openssl_ciphers && os_strcmp(openssl_ciphers, "SUITEB192") == 0) {
@@ -3293,14 +3417,14 @@
 		return 0;
 
 #ifdef PKCS12_FUNCS
-#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER)
+#ifdef 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
+	 * processing in tls_parse_pkcs12() to allow LibreSSL to build a new
 	 * chain properly.
 	 */
 	SSL_CTX_clear_extra_chain_certs(conn->ssl_ctx);
-#endif /* OPENSSL_VERSION_NUMBER < 0x10002000L */
+#endif /* LIBRESSL_VERSION_NUMBER */
 #endif /* PKCS12_FUNCS */
 
 	if (client_cert_blob &&
@@ -3493,7 +3617,7 @@
 	}
 
 	if (certs) {
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
+#ifndef LIBRESSL_VERSION_NUMBER
 		if (ssl)
 			SSL_clear_chain_certs(ssl);
 		else
@@ -3542,7 +3666,7 @@
 		 * the extra certificates not to be required.
 		 */
 		res = 0;
-#else /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
+#else /* LIBRESSL_VERSION_NUMBER */
 		SSL_CTX_clear_extra_chain_certs(data->ssl);
 		while ((cert = sk_X509_pop(certs)) != NULL) {
 			X509_NAME_oneline(X509_get_subject_name(cert), buf,
@@ -3561,7 +3685,7 @@
 			}
 		}
 		sk_X509_pop_free(certs, X509_free);
-#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
+#endif /* LIBRSESSL_VERSION_NUMBER */
 	}
 
 	PKCS12_free(p12);
@@ -3862,6 +3986,7 @@
 		}
 #endif /* OPENSSL_NO_EC */
 
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 		if (SSL_use_RSAPrivateKey_ASN1(conn->ssl,
 					       (u8 *) private_key_blob,
 					       private_key_blob_len) == 1) {
@@ -3870,6 +3995,7 @@
 			ok = 1;
 			break;
 		}
+#endif
 
 		bio = BIO_new_mem_buf((u8 *) private_key_blob,
 				      private_key_blob_len);
@@ -3977,79 +4103,44 @@
 }
 
 
-static int tls_connection_dh(struct tls_connection *conn, const char *dh_file)
-{
-#ifdef OPENSSL_NO_DH
-	if (dh_file == NULL)
-		return 0;
-	wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but "
-		   "dh_file specified");
-	return -1;
-#else /* OPENSSL_NO_DH */
-	DH *dh;
-	BIO *bio;
-
-	/* TODO: add support for dh_blob */
-	if (dh_file == NULL)
-		return 0;
-	if (conn == NULL)
-		return -1;
-
-	bio = BIO_new_file(dh_file, "r");
-	if (bio == NULL) {
-		wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
-			   dh_file, ERR_error_string(ERR_get_error(), NULL));
-		return -1;
-	}
-	dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
-	BIO_free(bio);
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#ifndef OPENSSL_NO_DH
 #ifndef OPENSSL_NO_DSA
-	while (dh == NULL) {
-		DSA *dsa;
-		wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -"
-			   " trying to parse as DSA params", dh_file,
-			   ERR_error_string(ERR_get_error(), NULL));
-		bio = BIO_new_file(dh_file, "r");
-		if (bio == NULL)
-			break;
-		dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL);
-		BIO_free(bio);
-		if (!dsa) {
-			wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file "
-				   "'%s': %s", dh_file,
-				   ERR_error_string(ERR_get_error(), NULL));
-			break;
-		}
+/* This is needed to replace the deprecated DSA_dup_DH() function */
+static EVP_PKEY * openssl_dsa_to_dh(EVP_PKEY *dsa)
+{
+	OSSL_PARAM_BLD *bld = NULL;
+	OSSL_PARAM *params = NULL;
+	BIGNUM *p = NULL, *q = NULL, *g = NULL;
+	EVP_PKEY_CTX *ctx = NULL;
+	EVP_PKEY *pkey = NULL;
 
-		wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format");
-		dh = DSA_dup_DH(dsa);
-		DSA_free(dsa);
-		if (dh == NULL) {
-			wpa_printf(MSG_INFO, "TLS: Failed to convert DSA "
-				   "params into DH params");
-			break;
-		}
-		break;
-	}
-#endif /* !OPENSSL_NO_DSA */
-	if (dh == NULL) {
-		wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file "
-			   "'%s'", dh_file);
-		return -1;
-	}
+	if (!EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_P, &p) ||
+	    !EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_Q, &q) ||
+	    !EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_G, &g) ||
+	    !(bld = OSSL_PARAM_BLD_new()) ||
+	    !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_P, p) ||
+	    !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_Q, q) ||
+	    !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_G, g) ||
+	    !(params = OSSL_PARAM_BLD_to_param(bld)) ||
+	    !(ctx = EVP_PKEY_CTX_new_from_name(NULL, "DHX", NULL)) ||
+	    EVP_PKEY_fromdata_init(ctx) != 1 ||
+	    EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_KEY_PARAMETERS,
+			      params) != 1)
+		wpa_printf(MSG_INFO,
+			   "TLS: Failed to convert DSA parameters to DH parameters");
 
-	if (SSL_set_tmp_dh(conn->ssl, dh) != 1) {
-		wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': "
-			   "%s", dh_file,
-			   ERR_error_string(ERR_get_error(), NULL));
-		DH_free(dh);
-		return -1;
-	}
-	DH_free(dh);
-	return 0;
-#endif /* OPENSSL_NO_DH */
+	EVP_PKEY_CTX_free(ctx);
+	OSSL_PARAM_free(params);
+	OSSL_PARAM_BLD_free(bld);
+	BN_free(p);
+	BN_free(q);
+	BN_free(g);
+	return pkey;
 }
-
+#endif /* !OPENSSL_NO_DSA */
+#endif /* OPENSSL_NO_DH */
+#endif /* OpenSSL version >= 3.0 */
 
 static int tls_global_dh(struct tls_data *data, const char *dh_file)
 {
@@ -4060,15 +4151,88 @@
 		   "dh_file specified");
 	return -1;
 #else /* OPENSSL_NO_DH */
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	SSL_CTX *ssl_ctx = data->ssl;
+	BIO *bio;
+	OSSL_DECODER_CTX *ctx = NULL;
+	EVP_PKEY *pkey = NULL, *tmpkey = NULL;
+	bool dsa = false;
+
+	if (!ssl_ctx)
+		return -1;
+	if (!dh_file) {
+		SSL_CTX_set_dh_auto(ssl_ctx, 1);
+		return 0;
+	}
+
+	bio = BIO_new_file(dh_file, "r");
+	if (!bio) {
+		wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
+			   dh_file, ERR_error_string(ERR_get_error(), NULL));
+		return -1;
+	}
+	ctx = OSSL_DECODER_CTX_new_for_pkey(
+		&tmpkey, "PEM", NULL, NULL,
+		OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, NULL, NULL);
+	if (!ctx ||
+	    OSSL_DECODER_from_bio(ctx, bio) != 1) {
+		wpa_printf(MSG_INFO,
+			   "TLS: Failed to decode domain parameters from '%s': %s",
+			   dh_file, ERR_error_string(ERR_get_error(), NULL));
+		BIO_free(bio);
+		return -1;
+	}
+	BIO_free(bio);
+
+	if (!tmpkey) {
+		wpa_printf(MSG_INFO, "TLS: Failed to load domain parameters");
+		return -1;
+	}
+
+#ifndef OPENSSL_NO_DSA
+	if (EVP_PKEY_is_a(tmpkey, "DSA")) {
+		pkey = openssl_dsa_to_dh(tmpkey);
+		EVP_PKEY_free(tmpkey);
+		if (!pkey)
+			return -1;
+		dsa = true;
+	}
+#endif /* !OPENSSL_NO_DSA */
+	if (!dsa) {
+		if (EVP_PKEY_is_a(tmpkey, "DH") ||
+		    EVP_PKEY_is_a(tmpkey, "DHX")) {
+		} else {
+			wpa_printf(MSG_INFO,
+				   "TLS: No DH parameters found in %s",
+				   dh_file);
+			EVP_PKEY_free(tmpkey);
+			return -1;
+		}
+		pkey = tmpkey;
+		tmpkey = NULL;
+	}
+
+	if (SSL_CTX_set0_tmp_dh_pkey(ssl_ctx, pkey) != 1) {
+		wpa_printf(MSG_INFO,
+			   "TLS: Failed to set DH params from '%s': %s",
+			   dh_file, ERR_error_string(ERR_get_error(), NULL));
+		EVP_PKEY_free(pkey);
+		return -1;
+	}
+	return 0;
+#else /* OpenSSL version >= 3.0 */
 	SSL_CTX *ssl_ctx = data->ssl;
 	DH *dh;
 	BIO *bio;
 
-	/* TODO: add support for dh_blob */
-	if (dh_file == NULL)
-		return 0;
-	if (ssl_ctx == NULL)
+	if (!ssl_ctx)
 		return -1;
+	if (!dh_file) {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
+		SSL_CTX_set_dh_auto(ssl_ctx, 1);
+#endif
+		return 0;
+	}
 
 	bio = BIO_new_file(dh_file, "r");
 	if (bio == NULL) {
@@ -4122,6 +4286,7 @@
 	}
 	DH_free(dh);
 	return 0;
+#endif /* OpenSSL version >= 3.0 */
 #endif /* OPENSSL_NO_DH */
 }
 
@@ -4152,9 +4317,7 @@
 #ifdef OPENSSL_NEED_EAP_FAST_PRF
 static int openssl_get_keyblock_size(SSL *ssl)
 {
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
-	(defined(LIBRESSL_VERSION_NUMBER) && \
-	 LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
 	const EVP_CIPHER *c;
 	const EVP_MD *h;
 	int md_size;
@@ -4322,6 +4485,7 @@
 static struct wpabuf *
 openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data)
 {
+	struct tls_context *context = conn->context;
 	int res;
 	struct wpabuf *out_data;
 
@@ -4351,7 +4515,19 @@
 			wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to "
 				   "write");
 		else {
+			unsigned long error = ERR_peek_last_error();
+
 			tls_show_errors(MSG_INFO, __func__, "SSL_connect");
+
+			if (context->event_cb &&
+			    ERR_GET_LIB(error) == ERR_LIB_SSL &&
+			    ERR_GET_REASON(error) ==
+			    SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED) {
+				context->event_cb(
+					context->cb_ctx,
+					TLS_UNSAFE_RENEGOTIATION_DISABLED,
+					NULL);
+			}
 			conn->failed++;
 			if (!conn->server && !conn->client_hello_generated) {
 				/* The server would not understand TLS Alert
@@ -4374,8 +4550,6 @@
 	if ((conn->flags & TLS_CONN_SUITEB) && !conn->server &&
 	    os_strncmp(SSL_get_cipher(conn->ssl), "DHE-", 4) == 0 &&
 	    conn->server_dh_prime_len < 3072) {
-		struct tls_context *context = conn->context;
-
 		/*
 		 * This should not be reached since earlier cert_cb should have
 		 * terminated the handshake. Keep this check here for extra
@@ -4867,6 +5041,21 @@
 
 	len = SSL_get_tlsext_status_ocsp_resp(s, &p);
 	if (!p) {
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L
+#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x30400000L
+		if (SSL_version(s) == TLS1_3_VERSION && SSL_session_reused(s)) {
+			/* TLS 1.3 sends the OCSP response with the server
+			 * Certificate message. Since that Certificate message
+			 * is not sent when resuming a session, there can be no
+			 * new OCSP response. Allow this since the OCSP response
+			 * was validated when checking the initial certificate
+			 * exchange. */
+			wpa_printf(MSG_DEBUG,
+				   "OpenSSL: Allow no OCSP response when using TLS 1.3 and a resumed session");
+			return 1;
+		}
+#endif
+#endif
 		wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received");
 		return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
 	}
@@ -5268,12 +5457,6 @@
 		return -1;
 	}
 
-	if (tls_connection_dh(conn, params->dh_file)) {
-		wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
-			   params->dh_file);
-		return -1;
-	}
-
 	ciphers = params->openssl_ciphers;
 #ifdef CONFIG_SUITEB
 #ifdef OPENSSL_IS_BORINGSSL
@@ -5295,22 +5478,21 @@
 	if (!params->openssl_ecdh_curves) {
 #ifndef OPENSSL_IS_BORINGSSL
 #ifndef OPENSSL_NO_EC
-#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \
-	(OPENSSL_VERSION_NUMBER < 0x10100000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
 		if (SSL_set_ecdh_auto(conn->ssl, 1) != 1) {
 			wpa_printf(MSG_INFO,
 				   "OpenSSL: Failed to set ECDH curves to auto");
 			return -1;
 		}
-#endif /* >= 1.0.2 && < 1.1.0 */
+#endif /* < 1.1.0 */
 #endif /* OPENSSL_NO_EC */
 #endif /* OPENSSL_IS_BORINGSSL */
 	} else if (params->openssl_ecdh_curves[0]) {
-#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L)
+#ifdef OPENSSL_IS_BORINGSSL
 		wpa_printf(MSG_INFO,
-			"OpenSSL: ECDH configuration nnot supported");
+			"OpenSSL: ECDH configuration not supported");
 		return -1;
-#else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */
+#else /* !OPENSSL_IS_BORINGSSL */
 #ifndef OPENSSL_NO_EC
 		if (SSL_set1_curves_list(conn->ssl,
 					 params->openssl_ecdh_curves) != 1) {
@@ -5520,22 +5702,21 @@
 	if (!params->openssl_ecdh_curves) {
 #ifndef OPENSSL_IS_BORINGSSL
 #ifndef OPENSSL_NO_EC
-#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \
-	(OPENSSL_VERSION_NUMBER < 0x10100000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
 		if (SSL_CTX_set_ecdh_auto(ssl_ctx, 1) != 1) {
 			wpa_printf(MSG_INFO,
 				   "OpenSSL: Failed to set ECDH curves to auto");
 			return -1;
 		}
-#endif /* >= 1.0.2 && < 1.1.0 */
+#endif /* < 1.1.0 */
 #endif /* OPENSSL_NO_EC */
 #endif /* OPENSSL_IS_BORINGSSL */
 	} else if (params->openssl_ecdh_curves[0]) {
-#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L)
+#ifdef OPENSSL_IS_BORINGSSL
 		wpa_printf(MSG_INFO,
-			"OpenSSL: ECDH configuration nnot supported");
+			"OpenSSL: ECDH configuration not supported");
 		return -1;
-#else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */
+#else /* !OPENSSL_IS_BORINGSSL */
 #ifndef OPENSSL_NO_EC
 #if OPENSSL_VERSION_NUMBER < 0x10100000L
 		SSL_CTX_set_ecdh_auto(ssl_ctx, 1);
@@ -5597,9 +5778,7 @@
 	struct tls_connection *conn = arg;
 	int ret;
 
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
-	(defined(LIBRESSL_VERSION_NUMBER) && \
-	 LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
 	if (conn == NULL || conn->session_ticket_cb == NULL)
 		return 0;
 
@@ -5710,6 +5889,7 @@
 {
 	SSL_SESSION *sess;
 	struct wpabuf *old;
+	struct tls_session_data *sess_data = NULL;
 
 	if (tls_ex_idx_session < 0)
 		goto fail;
@@ -5718,20 +5898,35 @@
 		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);
+		struct tls_session_data *found;
+
+		found = get_session_data(conn->context, old);
+		wpa_printf(MSG_DEBUG,
+			   "OpenSSL: Replacing old success data %p (sess %p)%s",
+			   old, sess, found ? "" : " (not freeing)");
+		if (found) {
+			dl_list_del(&found->list);
+			os_free(found);
+			wpabuf_free(old);
+		}
 	}
-	if (SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1)
+
+	sess_data = os_zalloc(sizeof(*sess_data));
+	if (!sess_data ||
+	    SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1)
 		goto fail;
 
-	wpa_printf(MSG_DEBUG, "OpenSSL: Stored success data %p", data);
+	sess_data->buf = data;
+	dl_list_add(&conn->context->sessions, &sess_data->list);
+	wpa_printf(MSG_DEBUG, "OpenSSL: Stored success data %p (sess %p)",
+		   data, sess);
 	conn->success_data = 1;
 	return;
 
 fail:
 	wpa_printf(MSG_INFO, "OpenSSL: Failed to store success data");
 	wpabuf_free(data);
+	os_free(sess_data);
 }
 
 
diff --git a/src/crypto/tls_openssl_ocsp.c b/src/crypto/tls_openssl_ocsp.c
index 97bf605..b570bea 100644
--- a/src/crypto/tls_openssl_ocsp.c
+++ b/src/crypto/tls_openssl_ocsp.c
@@ -644,13 +644,12 @@
 		   buf);
 
 	ctx = X509_STORE_CTX_new();
-	if (!ctx ||
-	    !X509_STORE_CTX_init(ctx, store, signer, untrusted) ||
-	    !X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_OCSP_HELPER)) {
+	if (!ctx || !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");
@@ -663,6 +662,7 @@
 	}
 
 	if (!signer_trusted) {
+		X509_check_purpose(signer, -1, 0);
 		if ((X509_get_extension_flags(signer) & EXFLAG_XKUSAGE) &&
 		    (X509_get_extended_key_usage(signer) & XKU_OCSP_SIGN)) {
 			wpa_printf(MSG_DEBUG,
diff --git a/src/crypto/tls_wolfssl.c b/src/crypto/tls_wolfssl.c
index cf482bf..b4f1bbe 100644
--- a/src/crypto/tls_wolfssl.c
+++ b/src/crypto/tls_wolfssl.c
@@ -26,6 +26,10 @@
 #include <wolfssl/wolfcrypt/aes.h>
 #endif
 
+#ifdef CONFIG_FIPS
+#include <wolfssl/wolfcrypt/fips_test.h>
+#endif /* CONFIG_FIPS */
+
 #if !defined(CONFIG_FIPS) &&                             \
     (defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) ||   \
      defined(EAP_SERVER_FAST))
@@ -58,6 +62,7 @@
 	void *cb_ctx;
 	int cert_in_cb;
 	char *ocsp_stapling_response;
+	unsigned int tls_session_lifetime;
 };
 
 static struct tls_context *tls_global = NULL;
@@ -94,6 +99,7 @@
 	WOLFSSL_X509 *peer_cert;
 	WOLFSSL_X509 *peer_issuer;
 	WOLFSSL_X509 *peer_issuer_issuer;
+	char *peer_subject; /* peer subject info for authenticated peer */
 };
 
 
@@ -190,6 +196,33 @@
 }
 
 
+#if defined(CONFIG_FIPS) && defined(HAVE_FIPS)
+static void wcFipsCb(int ok, int err, const char *hash)
+{
+	wpa_printf(MSG_INFO,
+		   "wolfFIPS: wolfCrypt Fips error callback, ok = %d, err = %d",
+		   ok, err);
+	wpa_printf(MSG_INFO, "wolfFIPS: message = %s", wc_GetErrorString(err));
+	wpa_printf(MSG_INFO, "wolfFIPS: hash = %s", hash);
+	if (err == IN_CORE_FIPS_E) {
+		wpa_printf(MSG_ERROR,
+			   "wolfFIPS: In core integrity hash check failure, copy above hash");
+		wpa_printf(MSG_ERROR, "wolfFIPS: into verifyCore[] in fips_test.c and rebuild");
+	}
+}
+#endif /* CONFIG_FIPS && HAVE_FIPS */
+
+
+#ifdef DEBUG_WOLFSSL
+static void wolfSSL_logging_cb(const int log_level,
+			       const char * const log_message)
+{
+	(void) log_level;
+	wpa_printf(MSG_DEBUG, "wolfSSL log:%s", log_message);
+}
+#endif /* DEBUG_WOLFSSL */
+
+
 void * tls_init(const struct tls_config *conf)
 {
 	WOLFSSL_CTX *ssl_ctx;
@@ -197,6 +230,7 @@
 	const char *ciphers;
 
 #ifdef DEBUG_WOLFSSL
+	wolfSSL_SetLoggingCb(wolfSSL_logging_cb);
 	wolfSSL_Debugging_ON();
 #endif /* DEBUG_WOLFSSL */
 
@@ -209,7 +243,9 @@
 
 		if (wolfSSL_Init() < 0)
 			return NULL;
-		/* wolfSSL_Debugging_ON(); */
+#if defined(CONFIG_FIPS) && defined(HAVE_FIPS)
+		wolfCrypt_SetCb_fips(wcFipsCb);
+#endif /* CONFIG_FIPS && HAVE_FIPS */
 	}
 
 	tls_ref_count++;
@@ -227,17 +263,21 @@
 	}
 	wolfSSL_SetIORecv(ssl_ctx, wolfssl_receive_cb);
 	wolfSSL_SetIOSend(ssl_ctx, wolfssl_send_cb);
+	context->tls_session_lifetime = conf->tls_session_lifetime;
 	wolfSSL_CTX_set_ex_data(ssl_ctx, 0, context);
 
 	if (conf->tls_session_lifetime > 0) {
+		wolfSSL_CTX_set_session_id_context(ssl_ctx,
+						   (const unsigned char *)
+						   "hostapd", 7);
 		wolfSSL_CTX_set_quiet_shutdown(ssl_ctx, 1);
 		wolfSSL_CTX_set_session_cache_mode(ssl_ctx,
-						   SSL_SESS_CACHE_SERVER);
+						   WOLFSSL_SESS_CACHE_SERVER);
 		wolfSSL_CTX_set_timeout(ssl_ctx, conf->tls_session_lifetime);
 		wolfSSL_CTX_sess_set_remove_cb(ssl_ctx, remove_session_cb);
 	} else {
 		wolfSSL_CTX_set_session_cache_mode(ssl_ctx,
-						   SSL_SESS_CACHE_CLIENT);
+						   WOLFSSL_SESS_CACHE_OFF);
 	}
 
 	if (conf && conf->openssl_ciphers)
@@ -336,6 +376,7 @@
 	os_free(conn->alt_subject_match);
 	os_free(conn->suffix_match);
 	os_free(conn->domain_match);
+	os_free(conn->peer_subject);
 
 	/* self */
 	os_free(conn);
@@ -369,10 +410,13 @@
 	wolfSSL_set_quiet_shutdown(conn->ssl, 1);
 	wolfSSL_shutdown(conn->ssl);
 
-	session = wolfSSL_get_session(conn->ssl);
-	if (wolfSSL_clear(conn->ssl) != 1)
+	session = wolfSSL_get1_session(conn->ssl);
+	if (wolfSSL_clear(conn->ssl) != 1) {
+		wolfSSL_SESSION_free(session);
 		return -1;
+	}
 	wolfSSL_set_session(conn->ssl, session);
+	wolfSSL_SESSION_free(session);
 
 	return 0;
 }
@@ -420,44 +464,6 @@
 }
 
 
-static int tls_connection_dh(struct tls_connection *conn, const char *dh_file,
-			     const u8 *dh_blob, size_t blob_len)
-{
-	if (!dh_file && !dh_blob)
-		return 0;
-
-	wolfSSL_set_accept_state(conn->ssl);
-
-	if (dh_blob) {
-		if (wolfSSL_SetTmpDH_buffer(conn->ssl, dh_blob, blob_len,
-					    SSL_FILETYPE_ASN1) < 0) {
-			wpa_printf(MSG_INFO, "SSL: use DH DER blob failed");
-			return -1;
-		}
-		wpa_printf(MSG_DEBUG, "SSL: use DH blob OK");
-		return 0;
-	}
-
-	if (dh_file) {
-		wpa_printf(MSG_INFO, "SSL: use DH PEM file: %s", dh_file);
-		if (wolfSSL_SetTmpDH_file(conn->ssl, dh_file,
-					  SSL_FILETYPE_PEM) < 0) {
-			wpa_printf(MSG_INFO, "SSL: use DH PEM file failed");
-			if (wolfSSL_SetTmpDH_file(conn->ssl, dh_file,
-						  SSL_FILETYPE_ASN1) < 0) {
-				wpa_printf(MSG_INFO,
-					   "SSL: use DH DER file failed");
-				return -1;
-			}
-		}
-		wpa_printf(MSG_DEBUG, "SSL: use DH file OK");
-		return 0;
-	}
-
-	return 0;
-}
-
-
 static int tls_connection_client_cert(struct tls_connection *conn,
 				      const char *client_cert,
 				      const u8 *client_cert_blob,
@@ -472,7 +478,13 @@
 			    SSL_FILETYPE_ASN1) != SSL_SUCCESS) {
 			wpa_printf(MSG_INFO,
 				   "SSL: use client cert DER blob failed");
-			return -1;
+			if (wolfSSL_use_certificate_chain_buffer_format(
+				    conn->ssl, client_cert_blob, blob_len,
+				    SSL_FILETYPE_PEM) != SSL_SUCCESS) {
+				wpa_printf(MSG_INFO,
+					   "SSL: use client cert PEM blob failed");
+				return -1;
+			}
 		}
 		wpa_printf(MSG_DEBUG, "SSL: use client cert blob OK");
 		return 0;
@@ -534,23 +546,35 @@
 	if (private_key_blob) {
 		if (wolfSSL_use_PrivateKey_buffer(conn->ssl,
 						  private_key_blob, blob_len,
-						  SSL_FILETYPE_ASN1) <= 0) {
+						  SSL_FILETYPE_ASN1) !=
+		    SSL_SUCCESS) {
 			wpa_printf(MSG_INFO,
 				   "SSL: use private DER blob failed");
+			if (wolfSSL_use_PrivateKey_buffer(
+				    conn->ssl,
+				    private_key_blob, blob_len,
+				    SSL_FILETYPE_PEM) != SSL_SUCCESS) {
+				wpa_printf(MSG_INFO,
+					   "SSL: use private PEM blob failed");
+			} else {
+				ok = 1;
+			}
 		} else {
-			wpa_printf(MSG_DEBUG, "SSL: use private key blob OK");
 			ok = 1;
 		}
+		if (ok)
+			wpa_printf(MSG_DEBUG, "SSL: use private key blob OK");
 	}
 
 	if (!ok && private_key) {
 		if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key,
-						SSL_FILETYPE_PEM) <= 0) {
+						SSL_FILETYPE_PEM) !=
+		    SSL_SUCCESS) {
 			wpa_printf(MSG_INFO,
 				   "SSL: use private key PEM file failed");
 			if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key,
-							SSL_FILETYPE_ASN1) <= 0)
-			{
+							SSL_FILETYPE_ASN1) !=
+			    SSL_SUCCESS) {
 				wpa_printf(MSG_INFO,
 					   "SSL: use private key DER file failed");
 			} else {
@@ -721,8 +745,7 @@
 		WOLFSSL_X509_NAME_ENTRY *e;
 		WOLFSSL_ASN1_STRING *cn;
 
-		i = wolfSSL_X509_NAME_get_index_by_NID(name, ASN_COMMON_NAME,
-						       i);
+		i = wolfSSL_X509_NAME_get_index_by_NID(name, NID_commonName, i);
 		if (i == -1)
 			break;
 		e = wolfSSL_X509_NAME_get_entry(name, i);
@@ -1134,6 +1157,11 @@
 		context->event_cb(context->cb_ctx,
 				  TLS_CERT_CHAIN_SUCCESS, NULL);
 
+	if (depth == 0 && preverify_ok) {
+		os_free(conn->peer_subject);
+		conn->peer_subject = os_strdup(buf);
+	}
+
 	return preverify_ok;
 }
 
@@ -1194,8 +1222,14 @@
 		if (wolfSSL_CTX_load_verify_buffer(ctx, ca_cert_blob, blob_len,
 						   SSL_FILETYPE_ASN1) !=
 		    SSL_SUCCESS) {
-			wpa_printf(MSG_INFO, "SSL: failed to load CA blob");
-			return -1;
+			wpa_printf(MSG_INFO, "SSL: failed to load DER CA blob");
+			if (wolfSSL_CTX_load_verify_buffer(
+				    ctx, ca_cert_blob, blob_len,
+				    SSL_FILETYPE_PEM) != SSL_SUCCESS) {
+				wpa_printf(MSG_INFO,
+					   "SSL: failed to load PEM CA blob");
+				return -1;
+			}
 		}
 		wpa_printf(MSG_DEBUG, "SSL: use CA cert blob OK");
 		return 0;
@@ -1238,10 +1272,8 @@
 static void tls_set_conn_flags(WOLFSSL *ssl, unsigned int flags)
 {
 #ifdef HAVE_SESSION_TICKET
-#if 0
 	if (!(flags & TLS_CONN_DISABLE_SESSION_TICKET))
 		wolfSSL_UseSessionTicket(ssl);
-#endif
 #endif /* HAVE_SESSION_TICKET */
 
 	if (flags & TLS_CONN_DISABLE_TLSv1_0)
@@ -1250,6 +1282,8 @@
 		wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
 	if (flags & TLS_CONN_DISABLE_TLSv1_2)
 		wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_2);
+	if (flags & TLS_CONN_DISABLE_TLSv1_3)
+		wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_3);
 }
 
 
@@ -1289,12 +1323,6 @@
 		return -1;
 	}
 
-	if (tls_connection_dh(conn, params->dh_file, params->dh_blob,
-			      params->dh_blob_len) < 0) {
-		wpa_printf(MSG_INFO, "Error setting DH");
-		return -1;
-	}
-
 	if (params->openssl_ciphers &&
 	    wolfSSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) {
 		wpa_printf(MSG_INFO,
@@ -1311,7 +1339,8 @@
 					    WOLFSSL_CSR_OCSP_USE_NONCE) !=
 		    SSL_SUCCESS)
 			return -1;
-		wolfSSL_CTX_EnableOCSP(tls_ctx, 0);
+		if (wolfSSL_EnableOCSPStapling(conn->ssl) != SSL_SUCCESS)
+			return -1;
 	}
 #endif /* HAVE_CERTIFICATE_STATUS_REQUEST */
 #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
@@ -1320,7 +1349,8 @@
 					      WOLFSSL_CSR2_OCSP_MULTI, 0) !=
 		    SSL_SUCCESS)
 			return -1;
-		wolfSSL_CTX_EnableOCSP(tls_ctx, 0);
+		if (wolfSSL_EnableOCSPStapling(conn->ssl) != SSL_SUCCESS)
+			return -1;
 	}
 #endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */
 #if !defined(HAVE_CERTIFICATE_STATUS_REQUEST) && \
@@ -1427,25 +1457,10 @@
 }
 
 
-static int tls_global_dh(void *ssl_ctx, const char *dh_file,
-			 const u8 *dh_blob, size_t blob_len)
+static int tls_global_dh(void *ssl_ctx, const char *dh_file)
 {
 	WOLFSSL_CTX *ctx = ssl_ctx;
 
-	if (!dh_file && !dh_blob)
-		return 0;
-
-	if (dh_blob) {
-		if (wolfSSL_CTX_SetTmpDH_buffer(ctx, dh_blob, blob_len,
-						SSL_FILETYPE_ASN1) < 0) {
-			wpa_printf(MSG_INFO,
-				   "SSL: global use DH DER blob failed");
-			return -1;
-		}
-		wpa_printf(MSG_DEBUG, "SSL: global use DH blob OK");
-		return 0;
-	}
-
 	if (dh_file) {
 		if (wolfSSL_CTX_SetTmpDH_file(ctx, dh_file, SSL_FILETYPE_PEM) <
 		    0) {
@@ -1532,8 +1547,7 @@
 		return -1;
 	}
 
-	if (tls_global_dh(tls_ctx, params->dh_file, params->dh_blob,
-			  params->dh_blob_len) < 0) {
+	if (tls_global_dh(tls_ctx, params->dh_file) < 0) {
 		wpa_printf(MSG_INFO, "SSL: Failed to load DH file '%s'",
 			   params->dh_file);
 		return -1;
@@ -1590,6 +1604,9 @@
 			      int verify_peer, unsigned int flags,
 			      const u8 *session_ctx, size_t session_ctx_len)
 {
+	static int counter = 0;
+	struct tls_context *context;
+
 	if (!conn)
 		return -1;
 
@@ -1607,6 +1624,22 @@
 
 	wolfSSL_set_accept_state(conn->ssl);
 
+	context = wolfSSL_CTX_get_ex_data((WOLFSSL_CTX *) ssl_ctx, 0);
+	if (context && context->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++;
+		wolfSSL_set_session_id_context(conn->ssl,
+					       (const unsigned char *) &counter,
+					       sizeof(counter));
+	} else {
+		wolfSSL_set_session_id_context(conn->ssl, session_ctx,
+					       session_ctx_len);
+	}
+
 	/* TODO: do we need to fake a session like OpenSSL does here? */
 
 	return 0;
@@ -1997,11 +2030,21 @@
 			      const char *label, const u8 *context,
 			      size_t context_len, u8 *out, size_t out_len)
 {
-	if (context)
+	if (!conn)
 		return -1;
-	if (!conn || wolfSSL_make_eap_keys(conn->ssl, out, out_len, label) != 0)
+#if LIBWOLFSSL_VERSION_HEX >= 0x04007000
+	if (wolfSSL_export_keying_material(conn->ssl, out, out_len,
+					   label, os_strlen(label),
+					   context, context_len,
+					   context != NULL) != WOLFSSL_SUCCESS)
 		return -1;
 	return 0;
+#else
+	if (context ||
+	    wolfSSL_make_eap_keys(conn->ssl, out, out_len, label) != 0)
+		return -1;
+#endif
+	return 0;
 }
 
 
@@ -2046,9 +2089,15 @@
 			       _out, skip + out_len);
 		ret = 0;
 	} else {
+#ifdef CONFIG_FIPS
+		wpa_printf(MSG_ERROR,
+			   "wolfSSL: Can't use sha1_md5 in FIPS build");
+		ret = -1;
+#else /* CONFIG_FIPS */
 		ret = tls_prf_sha1_md5(master_key, master_key_len,
 				       "key expansion", seed, sizeof(seed),
 				       _out, skip + out_len);
+#endif /* CONFIG_FIPS */
 	}
 
 	forced_memzero(master_key, master_key_len);
@@ -2160,6 +2209,39 @@
 }
 
 
+int tls_get_tls_unique(struct tls_connection *conn, u8 *buf, size_t max_len)
+{
+	size_t len;
+	int reused;
+
+	reused = wolfSSL_session_reused(conn->ssl);
+	if ((wolfSSL_is_server(conn->ssl) && !reused) ||
+	    (!wolfSSL_is_server(conn->ssl) && reused))
+		len = wolfSSL_get_peer_finished(conn->ssl, buf, max_len);
+	else
+		len = wolfSSL_get_finished(conn->ssl, buf, max_len);
+
+	if (len == 0 || len > max_len)
+		return -1;
+
+	return len;
+}
+
+
+u16 tls_connection_get_cipher_suite(struct tls_connection *conn)
+{
+	return (u16) wolfSSL_get_current_cipher_suite(conn->ssl);
+}
+
+
+const char * tls_connection_get_peer_subject(struct tls_connection *conn)
+{
+	if (conn)
+		return conn->peer_subject;
+	return NULL;
+}
+
+
 void tls_connection_set_success_data(struct tls_connection *conn,
 				     struct wpabuf *data)
 {
@@ -2206,3 +2288,11 @@
 		return NULL;
 	return wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
 }
+
+
+bool tls_connection_get_own_cert_used(struct tls_connection *conn)
+{
+	if (conn)
+		return wolfSSL_get_certificate(conn->ssl) != NULL;
+	return false;
+}