[wpa_supplicant] cumilative patch from commit 30748d2b3

Bug: 312315629
Test: Connect to open, WPA2, WPA3 and OWE
Test: Establish P2P connection
Test: Basic SoftAp tests
Test: Ran above tests on both Pixel 7a and Pixel6
Test: Regression test (312319701)

BYPASS_INCLUSIVE_LANGUAGE_REASON=Merged from open source
30748d2b3 SAE: Require PMKID match to PMKSA with SAE-EXT-KEY
nl80211: Use attribute NL80211_ATTR_BSSID to scan for specific BSSID
9b89df758 WNM: Do not start scan on disassociation imminent if BSSID is set
b08980309 hostapd: Add support for SAE offload for AP interface
d984c7b29 hostapd: Add support for OWE offload for STA/AP interface
da364180f hostapd: Support 4-way handshake offload for AP/P2P GO
77386f51a Adjust the RSSI and throughput estimate in roaming algorithm
790beb84a Adjust the SNR when comparing BSSes based on Tx power config
93a68a1fc OWE: Remove now unnecessary attempt to update transition mode BSS
00b312587 OWE: Do not update the BSS entry with zero length SSID for transition
9c9712657 OWE: Optimize transition mode scan to use known channels
5b12a0559 Use SSID from driver when finding the current BSS entry
a3020f852 MLD: Use BSS Parameters in TBTT Info to check SSID match
0635f83e4 MLD: Support multiple TBTT Information fields in RNR elements
c18aef624 MLD: Move TBTT Information field parsing into a helper function
99a8dd049 MLD: Support multiple RNR elements
be212bdb5 MLD: Move RNR element parsing into a helper function
84c33cc81 MBSSID: Use DTIM Count 0 in the Beacon template for nontransmitted BSSID
3e1fb2dec dragonfly: Fix legendre symbol calculation failure handling
76ae985b0 Remove QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINK_ID constraint
cc1867f5c MLD STA: Use MLD MAC address as destination for EAPOL-Key request
c92311fed MLD STA: Fix destination address for Group Key handshake msg 2/2
4f20dd52f wpa_cli/hostapd_cli: Add driver_flags2 command
c0da381a3 nl80211: Add capa.flags2 to STATUS-DRIVER
d193726aa nl80211: Dump driver_flags2 in debug prints
ed1ae82a3 Update the driver_flags2 to string conversion
bbc7ffe85 Rename driver capability for radar background detection
5025047ac Fix use after free warning introduced by gcc 12.1
236c0cfbc SAE: Pass SAE password on connect for SAE authentication offload support
6cc78b394 nl80211: Set NL80211_WPA_VERSION_2 vs. _3 based on AKM
c3b8452e0 nl80211: SAE authentication offload support
750403f3a mka: Fix re-establishment by resetting MI
61f0e19b8 mka: Fix unexpected cleanup on missing MKA_LIFE_TIME while installing SC/SA
c84388ee4 Compile-time config for dynamically loading libraries in wpa_supplicant
890953a32 wolfSSL: Old FIPS APIs have void return
ec7f064fa wolfSSL: Implement DPP backend functions
b37238d3a wolfSSL: Set up generator manually in FIPS build
8dabc1fed wolfSSL: Get EC generator for DPP
732ed5abe wolfSSL: Add crypto_ecdh_init2()
15a7c9b9e wolfSSL: Refactor crypto ECC section
41b5c9d8d wolfSSL: Use wc_ecc_get_curve_size_from_id()
378bef369 wolfSSL: Use wc_ecc_forcezero_point() in non-FIPS builds
de38571b8 wolfSSL: More complete crypto_ec_key_group()
d48f6b913 wolfSSL: EC group-to-id conversion into a helper function
a16916b74 wolfSSL: Improve logging
7ebb5469b wolfSSL: Improve error checking and logging in AES functions
10fd91d8f wolfSSL: Better error message in pbkdf2_sha1() for FIPS password failure
aa4c4d079 wolfSSL: Always clean up resources and log errors in wolfssl_hmac_vector()
644d87c34 wolfSSL: Improve error checking in vector hashing functions
5e20b924d wolfSSL: Add crypto logging macros
a0e8d9ae7 wolfSSL: Add FIPS warning
48a65d47c wolfSSL: Put wolfSSL headers in alphabetical order
a2eeb7f6d wolfSSL: Add more precise logging in wolfssl_handshake()
83f144bf6 wolfSSL: Debug print ciphersuites
568a5a815 EHT: Include crypto.h to avoid implicit function definition
0776c51ed DPP: Handle wpas_dpp_connected() processing in eloop callback
5c5f86900 DPP: Start next auth init from driver event to avoid race condition
f9965a650 Use os_reltime_initialized() for Michael MIC failure event
a8517c132 Add support for AKM suite 00-0F-AC:23
005b0ce36 defs: Enclose all structs between the pragmas
41a60f658 hostapd: Add support to send CW change notification
544801d74 wpa_supplicant: Add channel 140 to ht40plus allowed list for mesh/IBSS
75d33c988 OWE: Fix for entry->ssid possibly NULL dereference
e97d7c5a6 Only advertise MSCS and SCS in Association Request if supported by AP
a5d0bb42a Reduce delay between Association Request and Association Response
3f2c41e31 Check max number of TBTT info when adding Neighbor AP Information field
fc0b0cdcb hostapd: Avoid unnecessary Beacon frame update for co-location
8056b79ff Add DSSS Parameter Set element only for 2.4 GHz
056e68829 common: Fix ieee802_11_rsnx_capab()
ab3e679ae MBSSID: Check xrates_supported for all BSSs explicitly
4bfc007b6 MBSSID: Fix Non-Inheritance element encoding
42add3c27 Scan 6 GHz channels after change to 6 GHz-allowed regdom
0b8a67225 Parse 6 GHz capability from driver capabilities
41baf0159 nl80211: Fix uses_6ghz flag
17bdf34c4 Use default IEs in wpa_supplicant_trigger_scan()
aac288914 OKC with Suite B AKMPs in hostapd
0c9df339f OKC with Suite B AKMPs in wpa_supplicant
2bd8887e9 P2P: Pass the known BSSID to the driver to optimize scan time
bffd2b399 nl80211: Skip interface down/up when setting MAC address
9e426e068 Enable IPv6 in wpa_supplicant and eapol_test builds
3d8de6191 dbus: Use proper dbus_bool_t value TRUE instead of 1
03a9a57ac dbus: Add NonColoc6GHz and 6GHzOnly flags in wpa_supplicant scan
e5ea30fee SME: MLD: Handle reconfiguration Multi-Link element
7ea2798c2 Test command for sending ML probe request
de5e01010 wpa_supplicant: Support ML probe request
a12f39ad4 nl80211: Add support for minimal probe request content
c84709c59 hostapd: Output BSS Color (he_bss_color) when using STATUS
11a6ae242 More consistent use of mesh peer connected/disconnected notification
bd37f8615 Fix MESH-PEER-DISCONNECTED message logic on control iface
d986e8702 Respect disable_ht40/disable_vht/disable_he in AP/mesh mode
f7f8ea0aa nl80211: Change QoS Map configuration to be per bss, not radio
67bf89f55 WNM: Choose the best available BSS, not just the first one
fc7e74496 Sync with wireless-next.git include/uapi/linux/nl80211.h
5a96a516a dbus: Report guard interval and dual carrier modulation
3cb51378f Abort ongoing scan on DISCONNECT
5b21f4861 l2_packet_freebsd: Enable receiving priority tagged (VID=0) frames
0aa44ccf8 WNM: Lower rankings of current AP if disassociation imminent bit set
3242793cb P2P: Remove pending p2p-listen radio work on stopping listen
18330d1f6 hostapd: Update op_class after AP channel switching
2563edb8c Use 6 GHz default noise when estimating 6 GHz SNR
7a7339932 ACS: Fix typo in bw_40 frequency array
b99bb32f5 Don't disconnect on scan_freq update from control interface
cc5a00800 Ensure WDS is available on combined backhaul and fronthaul APs
1aeeebaa6 defconfig: Remove remaining reference to IEEE80211W symbol
8477fa7eb Check the need for SA Query earlier in association processing
a6440b57c Update correct VHT/HE/EHT mode in channel switch event
c86064716 Add NULL check for pmksa cache free_cb() callback
2f911fb15 SAE: Remove current PMKSA from driver after reauth threshold is passed
2d4be0019 Double the first group rekey timeout if over 100 associated stations
a89cf6ba4 Reserve QCA vendor sub command id 234
1dfcafff3 FILS: EHT additions
26f29ef46 FILS: Fix NSS calculation for HE mode
fcbb643ff FILS: Rename local variable to indicate HE mode
dcf66d2f4 FILS: Move maximum NSS determination to a new function
24e0938b3 FILS: Move phy index determination to new function
015af1bee DPP: Use CONFIG_SAE consistently to avoid a compiler warning
55ea12bb7 AP MLD: Add missing CONFIG_SAE checks
ef8d48c4c Update Wide Bandwidth Channel Switch element
c4c5c991d SAE: Do not reject reauth threshold passed PMKSA in association event
7a9587cee PASN: Copy PMK to PASN context on responder
e59d2a31c hostapd: Fix premature beacon set during association handling
ae928e67a Add channel 144 (5720 MHz) into operating class conversion tables
c80ded25c Refine roam stats frame subtypes in a QCA vendor attribute
ed89ab429 Update roam stats of AP BSSID to user space in a QCA vendor attribute
881cb4198 EAP-SIM/AKA peer: Simplify identity selection for MK derivation
ec6acdbb6 EAP-SIM/AKA server: Configurable limit to fast re-authentication
c6268e103 EAP-SIM/AKA server: Allow method specific identity exchange to be skipped
40af6560b EAP-SIM/AKA peer: Fix identity selection for MK derivation with AT_IDENTITY
bc9256980 Define a QCA vendor attribute to set traffic shaping policy
dec5ab645 Add _IS_ML flag attribute to the ADD_STA_NODE QCA vendor command
0d65e27fb Extend maximum allowed bandwidth update type QCA vendor interface
e510a3bad Add QCA vendor attributes to indicate MLO capabilities
e5ccbfc69 Split long comment lines in QCA vendor related definitions
4c9af238c Fix inconsistent whitespace use in QCA vendor related definitions
af6e0306b Fix typos in QCA vendor related definitions
dd25885a9 Remove space-before-tab in QCA vendor related definitions
f42906418 TDLS: Set EHT/MLO information for TDLS STA into the driver
940ef9a05 TDLS: Use link-specific BSSID instead of sm->bssid for MLO cases
5f30f62ee TDLS: Reply to Discovery Request on the link with matching BSSID
626501434 TDLS: Learn MLD link ID from TDLS Discovery Response
a41c8dbdd TDLS: Copy peer's EHT capabilities
c7561502f nl80211: Use a QCA vendor command to set the link for TDLS Discovery Response
e3a68081b driver: Add option for link ID to be specified for send_tdls_mgmt()
f85b2b2de Extend wpa_parse_kde_ies() to include EHT capabilities
3e7151693 Document per-ESS MAC address (mac_addr=3 and mac_value)
ba1579f3b Clear BIGTK values from wpa_supplicant state machine when not needed
377d617b5 Define new BSS command info mask for AP MLD address
f6eaa7b72 Add QCA vendor attribute for TTLM negotiation support type
12fabc476 Add QCA vendor attribute for configuring max A-MPDU aggregation count
b3d852560 Change QCA vendor configure attribution name of peer MAC address
123d16d86 Update hw_mode when CSA finishes
32dcec952 Send actual MFP configuration when driver takes care of BSS selection
edfca280c SCS: Add support for optional QoS Charateristics parameters
33da38655 SCS: Add support for QoS Characteristics in SCS request
c43766504 Add Non EHT SCS Capability in (Re)Association Request frames
12154861e Add support for conversion to little endian for 24 bits
609864d6a Add QCA vendor attribute to configure MLD ID in ML probe request
78b153f90 Calculate defragmented FTE length during IE parsing
aa08d9d76 Fix use of defragmented FTE information
ac9bf1cc2 Decrement hmac_sha*_vector() maximum num_elem value to 11
7381c60db FT: Make FTE MIC calculation more flexible
e6f64a8e1 FT: FTE MIC calculation for MLO Reassociation Request frame
4c079dcc6 Increment hmac_sha*_vector() maximum num_elem value to 25
338a78846 Add a QCA vendor sub command for transmit latency statistics
1085e3bdc Update iface->current_mode when fetching new hw_features
0a6842d50 nl80211: Fix beacon rate configuration for legacy rates 36, 48, 54 Mbps
dd1330b50 Fix hostapd interface cleanup with multiple interfaces
7637d0f25 P2P: Do not filter pref_freq_list if the driver does not provide one
47a65ccbf P2P: Clean wpa_s->last_ssid when removing a temporary group network
fe72afe71 Define QCA vendor attribute for high RSSI roam trigger threshold
e080930aa Define QCA vendor roam control RSSI attributes
585637355 Extend QCA vendor command to include more parameters for netdev events
6f293b321 QCA vendor attributes for updating roaming AP BSSID info
7e1f5c44c EHT: 320 MHz DFS support
a94ba5322 EHT: Support puncturing for 320 MHz channel bandwidth
bd209633e AP: Use is_zero_ether_addr() to check if BSSID is NULL
763a19286 AP: Add configuration option to specify the desired MLD address
2763d1d97 hostapd: Fix AID assignment in multiple BSSID
bc0636841 wpa_supplicant: Fix configuration parsing error for tx_queue_*
a685d8413 BSS coloring: Fix CCA with multiple BSS
b7db495ad AP: Fix ieee802_1x_ml_set_sta_authorized()
8f148d513 Fix a compiler warning on prototype mismatch
bf9cbb462 Fix writing of BIGTK in FT protocol
084745ffc Add QCA vendor attributes for NDP setup
3973300b8 FTE protected element check for MLO Reassociation Response frame
43b5f11d9 Defragmentation of FTE
053bd8af8 Recognize FTE MLO subelements
d320692d9 AP MLD: Handle new STA event when using SME offload to the driver
96deacf5d nl80211: Skip STA MLO link channel switch handling in AP mode
99a96b2f9 AP MLD: OWE when SME is offloaded to the driver
e53d44ac6 AP MLD: Use STA assoc link address in external auth status to the driver
4636476b7 Set RRM used config if the (Re)Association Request frame has RRM IE
a50d1ea6a Add QCA vendor attributes for user defined power save parameters
50ee26fc7 P2P: Check p2p_channel_select() return value
fb2b7858a FILS: Fix HE MCS field initialization
f80d83368 ACS: Remove invalid debug print
7a37a94ea Check whether element parsing has failed
a4c133ea7 WPS: Optimize attribute parsing workaround
518ae8c7c P2P: Do not print control characters in debug
de9a11f4d TTLS client: Support phase2_auth=2
8e6485a1b PEAP client: Update Phase 2 authentication requirements
30f5bdc34 Add support to configure per-MLO link maximum supported channel width
3d1ec9d0a Add QCA vendor interface to support per-MLO link configurations
f83cc05aa Reserve QCA vendor sub command id 232
82db29c37 QCA vendor test config attribute for MLO link powersave
f37a7dec3 Add vendor attributes for EPCS feature
a8c66bbb7 QCA vendor interface to control maximum allowed bandwidth update type
19e880d1f Add support to get the TDLS wider bandwidth capability
a8a112d4d Add documentation and nested attribute enums for existing QCA TDLS commands
91783b21b Define a QCA vendor attribute to configure UL MU transmission
05a2f4c4f EHT: Process puncturing bitmap from channel select driver event for ACS
9b233e9f0 nl80211: Always return NL_SKIP from survey dump handler
3a995cb5a Determine current hw mode before channel switch
a786c9b4a Enhance QCA_WLAN_VENDOR_ATTR_CONFIG_EHT_MLO_MAX_NUM_LINKS
aa4b8492e AP MLD: Provide Link ID when requesting current seqnum for a group key
5199cff4c AP/MLO: Forward received EAPOL frames to correct BSS
5c6cad01f AP/MLO: Forward Management frame TX status to correct BSS
996759ccf AP/MLO: Forward EAPOL TX status to correct BSS
8b5653669 AP: Use MLD address for traffic tests
6046aef73 AP: Don't process SAE/OWE association info on MLD links
90d819c24 AP: Use MLD address for SAE commit derivation
8b49853f4 AP: Specify the link ID for set_key() callback for group keys
8a8752876 MLO: Get the correct AA and SPA based on MLD operation for RSN authenticator
d5e93c804 MLO: Add MLO KDEs to EAPOL-Key msg 1/2 of the group handshake
79212e93f MLO: Validate MLO KDEs in EAPOL-Key msg 4/4
856d99410 MLO: Add MLO KDEs to EAPOL-Key msg 3/4
137b85509 MLO: Mechanism for fetching group key information for the links
eb28ee20e MLO: Validate MLO Link KDEs in EAPOL-Key msg 2/4
151ac359d MLO: Add MAC Address KDE to EAPOL-Key msg 1/4 for MLO association
3102d7676 MLO: Store MLO link information in RSN Authentication
cb130bbcb AP: MLO: Forward link specific events to the identified link
3613c8a96 nl80211: Use frequency to determine MLD link for MLME events
d3e20b211 AP/driver: Add link id to the set_tx_queue_params() callback
fbbca2bf1 AP: Provide the link ID for an MLD setting when setting VLAN
172b0a9a2 AP/driver: Add link ID to send EAPOL callbacks
c5271faf5 AP: Print MLD info in STATUS command
d75ebe23d AP: Handle Management frame TX status for AP MLD address
7a9ae9f43 AP: Do not prune station when adding a link station
5a61644ff driver: Specify link ID for 'send_mlme' and 'sta_deauth' callbacks
64d9ba3e6 Use a shared function for setting port authorization changes
edacd72d9 AP: MLO: Handle IEEE 802.1X port authorization
565020534 AP: MLO: Handle deauthentication/disassociation of MLD station
ced69780c AP: Cleanup coding style for deauth/disassoc handling
62fcfe8d2 AP: Move deauthentication/disassociation steps into helper functions
55038680a AP: MLO: Handle association callback
408b2a562 AP: MLO: Add Multi-Link element to (Re)Association Response frame
5f5db9366 AP: MLO: Process Multi-Link element from (Re)Association Request frame
d924be3bd AP: AID allocation for MLD
11a607d12 AP: Fill MLO information in struct hostapd_sta_add_params
bcbe80a66 AP: MLO: Handle Multi-Link element during authentication
f540d078c AP: Support building Basic Multi-Link element
79a9df6e8 AP: Match received Management frames against MLD address
a213fee11 AP: MLO: Make IEEE 802.1X SM, authserv, and RADIUS client singletons
7b45c2e6b nl80211: Select frame TX frequency according to the transmitting link
2b541601d AP: Include an RNR element in Beacon frames for AP MLD
0c6c94804 nl80211: Support setting up an AP on a specified link
df3fe12c9 nl80211: Move nl80211_put_freq_params()
e3605e809 driver: Allow to provide a link ID when setting a channel
be44a7afd driver: Add MLD link id to AP parameters
7fa99b324 AP: Allow starting multiple interfaces within single MLD
f2dd75093 AP: Add some basic MLD configuration options
1b14b38b1 nl80211: Fetch EML/MLD capabilities
8dffa0ccb AP: MLO: Retrieve EML and MLD capabilities from driver
4697887df nl80211: Rename the per iface-type capabilities struct
0837863fb AP: Handle 6 GHz AP state machine with NO_IR flags

Change-Id: I35521fd34f5769ba2323d49cbc8000a5565b8ee1
Signed-off-by: Sunil Ravi <sunilravi@google.com>
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index ff0869c..0ac8fc1 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -21,6 +21,8 @@
 #ifndef CRYPTO_H
 #define CRYPTO_H
 
+#define HMAC_VECTOR_MAX_ELEM 11
+
 /**
  * md4_vector - MD4 hash for data vector
  * @num_elem: Number of elements in the data vector
diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c
index f47beeb..2691743 100644
--- a/src/crypto/crypto_wolfssl.c
+++ b/src/crypto/crypto_wolfssl.c
@@ -10,25 +10,148 @@
 
 #include "common.h"
 #include "crypto.h"
+#include "tls/asn1.h"
 
 /* wolfSSL headers */
-#include <wolfssl/options.h>
+#include <wolfssl/options.h> /* options.h needs to be included first */
+#include <wolfssl/version.h>
+#include <wolfssl/openssl/bn.h>
+#include <wolfssl/wolfcrypt/aes.h>
+#include <wolfssl/wolfcrypt/arc4.h>
+#include <wolfssl/wolfcrypt/asn_public.h>
+#include <wolfssl/wolfcrypt/cmac.h>
+#include <wolfssl/wolfcrypt/des3.h>
+#include <wolfssl/wolfcrypt/dh.h>
+#include <wolfssl/wolfcrypt/ecc.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#include <wolfssl/wolfcrypt/hmac.h>
 #include <wolfssl/wolfcrypt/md4.h>
 #include <wolfssl/wolfcrypt/md5.h>
+#include <wolfssl/wolfcrypt/pkcs7.h>
+#include <wolfssl/wolfcrypt/pwdbased.h>
 #include <wolfssl/wolfcrypt/sha.h>
 #include <wolfssl/wolfcrypt/sha256.h>
 #include <wolfssl/wolfcrypt/sha512.h>
-#include <wolfssl/wolfcrypt/hmac.h>
-#include <wolfssl/wolfcrypt/pwdbased.h>
-#include <wolfssl/wolfcrypt/arc4.h>
-#include <wolfssl/wolfcrypt/des3.h>
-#include <wolfssl/wolfcrypt/aes.h>
-#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>
+
+#ifdef CONFIG_FIPS
+#ifndef HAVE_FIPS
+#warning "You are compiling wpa_supplicant/hostapd in FIPS mode but wolfSSL is not configured for FIPS mode."
+#endif /* HAVE_FIPS */
+#endif /* CONFIG_FIPS */
+
+
+#ifdef CONFIG_FIPS
+#if !defined(HAVE_FIPS_VERSION) || HAVE_FIPS_VERSION <= 2
+#define WOLFSSL_OLD_FIPS
+#endif
+#endif
+
+#if LIBWOLFSSL_VERSION_HEX < 0x05004000
+static int wc_EccPublicKeyToDer_ex(ecc_key *key, byte *output,
+				   word32 inLen, int with_AlgCurve,
+				   int comp)
+{
+	return wc_EccPublicKeyToDer(key, output, inLen, with_AlgCurve);
+}
+#endif /* version < 5.4.0 */
+
+#define LOG_WOLF_ERROR_VA(msg, ...) \
+	wpa_printf(MSG_ERROR, "wolfSSL: %s:%d " msg, \
+		   __func__, __LINE__, __VA_ARGS__)
+
+#define LOG_WOLF_ERROR(msg) \
+	LOG_WOLF_ERROR_VA("%s", (msg))
+
+#define LOG_WOLF_ERROR_FUNC(func, err) \
+	LOG_WOLF_ERROR_VA(#func " failed with err: %d %s", \
+			  (err), wc_GetErrorString(err))
+
+#define LOG_WOLF_ERROR_FUNC_NULL(func) \
+	LOG_WOLF_ERROR(#func " failed with NULL return")
+
+#define LOG_INVALID_PARAMETERS() \
+	LOG_WOLF_ERROR("invalid input parameters")
+
+
+/* Helper functions to make type allocation uniform */
+
+static WC_RNG * wc_rng_init(void)
+{
+	WC_RNG *ret;
+
+#ifdef CONFIG_FIPS
+	ret = os_zalloc(sizeof(WC_RNG));
+	if (!ret) {
+		LOG_WOLF_ERROR_FUNC_NULL(os_zalloc);
+	} else {
+		int err;
+
+		err = wc_InitRng(ret);
+		if (err != 0) {
+			LOG_WOLF_ERROR_FUNC(wc_InitRng, err);
+			os_free(ret);
+			ret = NULL;
+		}
+	}
+#else /* CONFIG_FIPS */
+	ret = wc_rng_new(NULL, 0, NULL);
+	if (!ret)
+		LOG_WOLF_ERROR_FUNC_NULL(wc_rng_new);
+#endif /* CONFIG_FIPS */
+
+	return ret;
+}
+
+
+static void wc_rng_deinit(WC_RNG *rng)
+{
+#ifdef CONFIG_FIPS
+	wc_FreeRng(rng);
+	os_free(rng);
+#else /* CONFIG_FIPS */
+	wc_rng_free(rng);
+#endif /* CONFIG_FIPS */
+}
+
+
+static ecc_key * ecc_key_init(void)
+{
+	ecc_key *ret;
+#ifdef CONFIG_FIPS
+	int err;
+
+	ret = os_zalloc(sizeof(ecc_key));
+	if (!ret) {
+		LOG_WOLF_ERROR_FUNC_NULL(os_zalloc);
+	} else {
+		err = wc_ecc_init_ex(ret, NULL, INVALID_DEVID);
+		if (err != 0) {
+			LOG_WOLF_ERROR("wc_ecc_init_ex failed");
+			os_free(ret);
+			ret = NULL;
+		}
+	}
+#else /* CONFIG_FIPS */
+	ret = wc_ecc_key_new(NULL);
+	if (!ret)
+		LOG_WOLF_ERROR_FUNC_NULL(wc_ecc_key_new);
+#endif /* CONFIG_FIPS */
+
+	return ret;
+}
+
+
+static void ecc_key_deinit(ecc_key *key)
+{
+#ifdef CONFIG_FIPS
+	wc_ecc_free(key);
+	os_free(key);
+#else /* CONFIG_FIPS */
+	wc_ecc_key_free(key);
+#endif /* CONFIG_FIPS */
+}
+
+/* end of helper functions */
 
 
 #ifndef CONFIG_FIPS
@@ -56,18 +179,36 @@
 {
 	wc_Md5 md5;
 	size_t i;
+	int err;
+	int ret = -1;
 
 	if (TEST_FAIL())
 		return -1;
 
-	wc_InitMd5(&md5);
+	err = wc_InitMd5(&md5);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_InitMd5, err);
+		return -1;
+	}
 
-	for (i = 0; i < num_elem; i++)
-		wc_Md5Update(&md5, addr[i], len[i]);
+	for (i = 0; i < num_elem; i++) {
+		err = wc_Md5Update(&md5, addr[i], len[i]);
+		if (err != 0) {
+			LOG_WOLF_ERROR_FUNC(wc_Md5Update, err);
+			goto fail;
+		}
+	}
 
-	wc_Md5Final(&md5, mac);
+	err = wc_Md5Final(&md5, mac);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_Md5Final, err);
+		goto fail;
+	}
 
-	return 0;
+	ret = 0;
+fail:
+	wc_Md5Free(&md5);
+	return ret;
 }
 
 #endif /* CONFIG_FIPS */
@@ -77,19 +218,36 @@
 {
 	wc_Sha sha;
 	size_t i;
+	int err;
+	int ret = -1;
 
 	if (TEST_FAIL())
 		return -1;
 
-	wc_InitSha(&sha);
+	err = wc_InitSha(&sha);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_InitSha, err);
+		return -1;
+	}
 
-	for (i = 0; i < num_elem; i++)
-		wc_ShaUpdate(&sha, addr[i], len[i]);
+	for (i = 0; i < num_elem; i++) {
+		err = wc_ShaUpdate(&sha, addr[i], len[i]);
+		if (err != 0) {
+			LOG_WOLF_ERROR_FUNC(wc_ShaUpdate, err);
+			goto fail;
+		}
+	}
 
-	wc_ShaFinal(&sha, mac);
+	err = wc_ShaFinal(&sha, mac);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_ShaFinal, err);
+		goto fail;
+	}
+
+	ret = 0;
+fail:
 	wc_ShaFree(&sha);
-
-	return 0;
+	return ret;
 }
 
 
@@ -99,19 +257,36 @@
 {
 	wc_Sha256 sha256;
 	size_t i;
+	int err;
+	int ret = -1;
 
 	if (TEST_FAIL())
 		return -1;
 
-	wc_InitSha256(&sha256);
+	err = wc_InitSha256(&sha256);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_InitSha256, err);
+		return -1;
+	}
 
-	for (i = 0; i < num_elem; i++)
-		wc_Sha256Update(&sha256, addr[i], len[i]);
+	for (i = 0; i < num_elem; i++) {
+		err = wc_Sha256Update(&sha256, addr[i], len[i]);
+		if (err != 0) {
+			LOG_WOLF_ERROR_FUNC(wc_Sha256Update, err);
+			goto fail;
+		}
+	}
 
-	wc_Sha256Final(&sha256, mac);
+	err = wc_Sha256Final(&sha256, mac);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_Sha256Final, err);
+		goto fail;
+	}
+
+	ret = 0;
+fail:
 	wc_Sha256Free(&sha256);
-
-	return 0;
+	return ret;
 }
 #endif /* NO_SHA256_WRAPPER */
 
@@ -122,19 +297,36 @@
 {
 	wc_Sha384 sha384;
 	size_t i;
+	int err;
+	int ret = -1;
 
 	if (TEST_FAIL())
 		return -1;
 
-	wc_InitSha384(&sha384);
+	err = wc_InitSha384(&sha384);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_InitSha384, err);
+		return -1;
+	}
 
-	for (i = 0; i < num_elem; i++)
-		wc_Sha384Update(&sha384, addr[i], len[i]);
+	for (i = 0; i < num_elem; i++) {
+		err = wc_Sha384Update(&sha384, addr[i], len[i]);
+		if (err != 0) {
+			LOG_WOLF_ERROR_FUNC(wc_Sha384Update, err);
+			goto fail;
+		}
+	}
 
-	wc_Sha384Final(&sha384, mac);
+	err = wc_Sha384Final(&sha384, mac);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_Sha384Final, err);
+		goto fail;
+	}
+
+	ret = 0;
+fail:
 	wc_Sha384Free(&sha384);
-
-	return 0;
+	return ret;
 }
 #endif /* CONFIG_SHA384 */
 
@@ -145,19 +337,36 @@
 {
 	wc_Sha512 sha512;
 	size_t i;
+	int err;
+	int ret = -1;
 
 	if (TEST_FAIL())
 		return -1;
 
-	wc_InitSha512(&sha512);
+	err = wc_InitSha512(&sha512);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_InitSha512, err);
+		return -1;
+	}
 
-	for (i = 0; i < num_elem; i++)
-		wc_Sha512Update(&sha512, addr[i], len[i]);
+	for (i = 0; i < num_elem; i++) {
+		err = wc_Sha512Update(&sha512, addr[i], len[i]);
+		if (err != 0) {
+			LOG_WOLF_ERROR_FUNC(wc_Sha512Update, err);
+			goto fail;
+		}
+	}
 
-	wc_Sha512Final(&sha512, mac);
+	err = wc_Sha512Final(&sha512, mac);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_Sha512Final, err);
+		goto fail;
+	}
+
+	ret = 0;
+fail:
 	wc_Sha512Free(&sha512);
-
-	return 0;
+	return ret;
 }
 #endif /* CONFIG_SHA512 */
 
@@ -169,23 +378,43 @@
 {
 	Hmac hmac;
 	size_t i;
+	int err;
+	int ret = -1;
 
 	(void) mdlen;
 
 	if (TEST_FAIL())
 		return -1;
 
-	if (wc_HmacInit(&hmac, NULL, INVALID_DEVID) != 0 ||
-	    wc_HmacSetKey(&hmac, type, key, (word32) key_len) != 0)
+	err = wc_HmacInit(&hmac, NULL, INVALID_DEVID);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_HmacInit, err);
 		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;
+	err = wc_HmacSetKey(&hmac, type, key, (word32) key_len);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_HmacSetKey, err);
+		goto fail;
+	}
+
+	for (i = 0; i < num_elem; i++) {
+		err = wc_HmacUpdate(&hmac, addr[i], len[i]);
+		if (err != 0) {
+			LOG_WOLF_ERROR_FUNC(wc_HmacUpdate, err);
+			goto fail;
+		}
+	}
+	err = wc_HmacFinal(&hmac, mac);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_HmacFinal, err);
+		goto fail;
+	}
+
+	ret = 0;
+fail:
+	wc_HmacFree(&hmac);
+	return ret;
 }
 
 
@@ -289,9 +518,8 @@
 			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);
+			LOG_WOLF_ERROR_VA("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;
 	}
@@ -326,15 +554,20 @@
 void * aes_encrypt_init(const u8 *key, size_t len)
 {
 	Aes *aes;
+	int err;
 
 	if (TEST_FAIL())
 		return NULL;
 
 	aes = os_malloc(sizeof(Aes));
-	if (!aes)
+	if (!aes) {
+		LOG_WOLF_ERROR_FUNC_NULL(os_malloc);
 		return NULL;
+	}
 
-	if (wc_AesSetKey(aes, key, len, NULL, AES_ENCRYPTION) < 0) {
+	err = wc_AesSetKey(aes, key, len, NULL, AES_ENCRYPTION);
+	if (err < 0) {
+		LOG_WOLF_ERROR_FUNC(wc_AesSetKey, err);
 		os_free(aes);
 		return NULL;
 	}
@@ -345,7 +578,18 @@
 
 int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
 {
+#if defined(HAVE_FIPS) && \
+    (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION <= 2))
+	/* Old FIPS has void return on this API */
 	wc_AesEncryptDirect(ctx, crypt, plain);
+#else
+	int err = wc_AesEncryptDirect(ctx, crypt, plain);
+
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_AesEncryptDirect, err);
+		return -1;
+	}
+#endif
 	return 0;
 }
 
@@ -359,15 +603,20 @@
 void * aes_decrypt_init(const u8 *key, size_t len)
 {
 	Aes *aes;
+	int err;
 
 	if (TEST_FAIL())
 		return NULL;
 
 	aes = os_malloc(sizeof(Aes));
-	if (!aes)
+	if (!aes) {
+		LOG_WOLF_ERROR_FUNC_NULL(os_malloc);
 		return NULL;
+	}
 
-	if (wc_AesSetKey(aes, key, len, NULL, AES_DECRYPTION) < 0) {
+	err = wc_AesSetKey(aes, key, len, NULL, AES_DECRYPTION);
+	if (err < 0) {
+		LOG_WOLF_ERROR_FUNC(wc_AesSetKey, err);
 		os_free(aes);
 		return NULL;
 	}
@@ -378,7 +627,18 @@
 
 int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
 {
+#if defined(HAVE_FIPS) && \
+    (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION <= 2))
+	/* Old FIPS has void return on this API */
 	wc_AesDecryptDirect(ctx, plain, crypt);
+#else
+	int err = wc_AesDecryptDirect(ctx, plain, crypt);
+
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_AesDecryptDirect, err);
+		return -1;
+	}
+#endif
 	return 0;
 }
 
@@ -1334,17 +1594,52 @@
 
 #ifdef CONFIG_ECC
 
+static int crypto_ec_group_2_id(int group)
+{
+	switch (group) {
+	case 19:
+		return ECC_SECP256R1;
+	case 20:
+		return ECC_SECP384R1;
+	case 21:
+		return ECC_SECP521R1;
+	case 25:
+		return ECC_SECP192R1;
+	case 26:
+		return ECC_SECP224R1;
+#ifdef HAVE_ECC_BRAINPOOL
+	case 27:
+		return ECC_BRAINPOOLP224R1;
+	case 28:
+		return ECC_BRAINPOOLP256R1;
+	case 29:
+		return ECC_BRAINPOOLP384R1;
+	case 30:
+		return ECC_BRAINPOOLP512R1;
+#endif /* HAVE_ECC_BRAINPOOL */
+	default:
+		LOG_WOLF_ERROR_VA("Unsupported curve (id=%d) in EC key", group);
+		return ECC_CURVE_INVALID;
+	}
+}
+
+
 int ecc_map(ecc_point *, mp_int *, mp_digit);
 int ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R,
 			     mp_int *a, mp_int *modulus, mp_digit mp);
 
 struct crypto_ec {
-	ecc_key key;
+	ecc_key *key;
+#ifdef CONFIG_DPP
+	ecc_point *g; /* Only used in DPP for now */
+#endif /* CONFIG_DPP */
 	mp_int a;
 	mp_int prime;
 	mp_int order;
 	mp_digit mont_b;
 	mp_int b;
+	int curve_id;
+	bool own_key; /* Should we free the `key` */
 };
 
 
@@ -1352,59 +1647,98 @@
 {
 	int built = 0;
 	struct crypto_ec *e;
-	int curve_id;
+	int curve_id = crypto_ec_group_2_id(group);
+	int err;
 
-	/* Map from IANA registry for IKE D-H groups to OpenSSL NID */
-	switch (group) {
-	case 19:
-		curve_id = ECC_SECP256R1;
-		break;
-	case 20:
-		curve_id = ECC_SECP384R1;
-		break;
-	case 21:
-		curve_id = ECC_SECP521R1;
-		break;
-	case 25:
-		curve_id = ECC_SECP192R1;
-		break;
-	case 26:
-		curve_id = ECC_SECP224R1;
-		break;
-#ifdef HAVE_ECC_BRAINPOOL
-	case 27:
-		curve_id = ECC_BRAINPOOLP224R1;
-		break;
-	case 28:
-		curve_id = ECC_BRAINPOOLP256R1;
-		break;
-	case 29:
-		curve_id = ECC_BRAINPOOLP384R1;
-		break;
-	case 30:
-		curve_id = ECC_BRAINPOOLP512R1;
-		break;
-#endif /* HAVE_ECC_BRAINPOOL */
-	default:
+	if (curve_id == ECC_CURVE_INVALID) {
+		LOG_INVALID_PARAMETERS();
 		return NULL;
 	}
 
 	e = os_zalloc(sizeof(*e));
-	if (!e)
+	if (!e) {
+		LOG_WOLF_ERROR_FUNC_NULL(os_zalloc);
 		return NULL;
+	}
 
-	if (wc_ecc_init(&e->key) != 0 ||
-	    wc_ecc_set_curve(&e->key, 0, curve_id) != 0 ||
-	    mp_init(&e->a) != MP_OKAY ||
-	    mp_init(&e->prime) != MP_OKAY ||
-	    mp_init(&e->order) != MP_OKAY ||
-	    mp_init(&e->b) != MP_OKAY ||
-	    mp_read_radix(&e->a, e->key.dp->Af, 16) != MP_OKAY ||
-	    mp_read_radix(&e->b, e->key.dp->Bf, 16) != MP_OKAY ||
-	    mp_read_radix(&e->prime, e->key.dp->prime, 16) != MP_OKAY ||
-	    mp_read_radix(&e->order, e->key.dp->order, 16) != MP_OKAY ||
-	    mp_montgomery_setup(&e->prime, &e->mont_b) != MP_OKAY)
+	e->curve_id = curve_id;
+	e->own_key = true;
+	e->key = ecc_key_init();
+	if (!e->key) {
+		LOG_WOLF_ERROR_FUNC_NULL(ecc_key_init);
 		goto done;
+	}
+
+	err = wc_ecc_set_curve(e->key, 0, curve_id);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_set_curve, err);
+		goto done;
+	}
+#ifdef CONFIG_DPP
+	e->g = wc_ecc_new_point();
+	if (!e->g) {
+		LOG_WOLF_ERROR_FUNC_NULL(wc_ecc_new_point);
+		goto done;
+	}
+#ifdef CONFIG_FIPS
+	/* Setup generator manually in FIPS mode */
+	if (!e->key->dp) {
+		LOG_WOLF_ERROR_FUNC_NULL(e->key->dp);
+		goto done;
+	}
+	err = mp_read_radix(e->g->x, e->key->dp->Gx, MP_RADIX_HEX);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(mp_read_radix, err);
+		goto done;
+	}
+	err = mp_read_radix(e->g->y, e->key->dp->Gy, MP_RADIX_HEX);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(mp_read_radix, err);
+		goto done;
+	}
+	err = mp_set(e->g->z, 1);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(mp_set, err);
+		goto done;
+	}
+#else /* CONFIG_FIPS */
+	err = wc_ecc_get_generator(e->g, wc_ecc_get_curve_idx(curve_id));
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_get_generator, err);
+		goto done;
+	}
+#endif /* CONFIG_FIPS */
+#endif /* CONFIG_DPP */
+	err = mp_init_multi(&e->a, &e->prime, &e->order, &e->b, NULL, NULL);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(mp_init_multi, err);
+		goto done;
+	}
+	err = mp_read_radix(&e->a, e->key->dp->Af, 16);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(mp_read_radix, err);
+		goto done;
+	}
+	err = mp_read_radix(&e->b, e->key->dp->Bf, 16);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(mp_read_radix, err);
+		goto done;
+	}
+	err = mp_read_radix(&e->prime, e->key->dp->prime, 16);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(mp_read_radix, err);
+		goto done;
+	}
+	err = mp_read_radix(&e->order, e->key->dp->order, 16);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(mp_read_radix, err);
+		goto done;
+	}
+	err = mp_montgomery_setup(&e->prime, &e->mont_b);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(mp_montgomery_setup, err);
+		goto done;
+	}
 
 	built = 1;
 done:
@@ -1425,7 +1759,11 @@
 	mp_clear(&e->order);
 	mp_clear(&e->prime);
 	mp_clear(&e->a);
-	wc_ecc_free(&e->key);
+#ifdef CONFIG_DPP
+	wc_ecc_del_point(e->g);
+#endif /* CONFIG_DPP */
+	if (e->own_key)
+		ecc_key_deinit(e->key);
 	os_free(e);
 }
 
@@ -1490,14 +1828,26 @@
 		return;
 
 	if (clear) {
+#ifdef CONFIG_FIPS
 		mp_forcezero(point->x);
 		mp_forcezero(point->y);
 		mp_forcezero(point->z);
+#else /* CONFIG_FIPS */
+		wc_ecc_forcezero_point(point);
+#endif /* CONFIG_FIPS */
 	}
 	wc_ecc_del_point(point);
 }
 
 
+#ifdef CONFIG_DPP
+const struct crypto_ec_point * crypto_ec_get_generator(struct crypto_ec *e)
+{
+	return (const struct crypto_ec_point *) e->g;
+}
+#endif /* CONFIG_DPP */
+
+
 int crypto_ec_point_x(struct crypto_ec *e, const struct crypto_ec_point *p,
 		      struct crypto_bignum *x)
 {
@@ -1509,27 +1859,41 @@
 			   const struct crypto_ec_point *point, u8 *x, u8 *y)
 {
 	ecc_point *p = (ecc_point *) point;
+	int len;
+	int err;
 
 	if (TEST_FAIL())
 		return -1;
 
 	if (!mp_isone(p->z)) {
-		if (ecc_map(p, &e->prime, e->mont_b) != MP_OKAY)
+		err = ecc_map(p, &e->prime, e->mont_b);
+		if (err != MP_OKAY) {
+			LOG_WOLF_ERROR_FUNC(ecc_map, err);
 			return -1;
+		}
+	}
+
+	len = wc_ecc_get_curve_size_from_id(e->curve_id);
+	if (len <= 0) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_get_curve_size_from_id, len);
+		LOG_WOLF_ERROR_VA("wc_ecc_get_curve_size_from_id error for curve_id %d", e->curve_id);
+		return -1;
 	}
 
 	if (x) {
 		if (crypto_bignum_to_bin((struct crypto_bignum *)p->x, x,
-					 e->key.dp->size,
-					 e->key.dp->size) <= 0)
+					 (size_t) len, (size_t) len) <= 0) {
+			LOG_WOLF_ERROR_FUNC(crypto_bignum_to_bin, -1);
 			return -1;
+		}
 	}
 
 	if (y) {
 		if (crypto_bignum_to_bin((struct crypto_bignum *) p->y, y,
-					 e->key.dp->size,
-					 e->key.dp->size) <= 0)
+					 (size_t) len, (size_t) len) <= 0) {
+			LOG_WOLF_ERROR_FUNC(crypto_bignum_to_bin, -1);
 			return -1;
+		}
 	}
 
 	return 0;
@@ -1549,10 +1913,10 @@
 	if (!point)
 		goto done;
 
-	if (mp_read_unsigned_bin(point->x, val, e->key.dp->size) != MP_OKAY)
+	if (mp_read_unsigned_bin(point->x, val, e->key->dp->size) != MP_OKAY)
 		goto done;
-	val += e->key.dp->size;
-	if (mp_read_unsigned_bin(point->y, val, e->key.dp->size) != MP_OKAY)
+	val += e->key->dp->size;
+	if (mp_read_unsigned_bin(point->y, val, e->key->dp->size) != MP_OKAY)
 		goto done;
 	mp_set(point->z, 1);
 
@@ -1710,53 +2074,123 @@
 	return wc_ecc_cmp_point((ecc_point *) a, (ecc_point *) b);
 }
 
+struct crypto_ec_key {
+	ecc_key *eckey;
+	WC_RNG *rng; /* Needs to be initialized before use.
+		      * *NOT* initialized in crypto_ec_key_init */
+};
+
 
 struct crypto_ecdh {
 	struct crypto_ec *ec;
-	WC_RNG rng;
+	WC_RNG *rng;
 };
 
-struct crypto_ecdh * crypto_ecdh_init(int group)
+static struct crypto_ecdh * _crypto_ecdh_init(int group)
 {
 	struct crypto_ecdh *ecdh = NULL;
+#if defined(ECC_TIMING_RESISTANT) && !defined(WOLFSSL_OLD_FIPS)
 	int ret;
+#endif /* ECC_TIMING_RESISTANT && !WOLFSSL_OLD_FIPS */
 
 	ecdh = os_zalloc(sizeof(*ecdh));
-	if (!ecdh)
-		goto fail;
+	if (!ecdh) {
+		LOG_WOLF_ERROR_FUNC_NULL(os_zalloc);
+		return NULL;
+	}
 
-	if (wc_InitRng(&ecdh->rng) != 0)
+	ecdh->rng = wc_rng_init();
+	if (!ecdh->rng) {
+		LOG_WOLF_ERROR_FUNC_NULL(wc_rng_init);
 		goto fail;
+	}
 
 	ecdh->ec = crypto_ec_init(group);
-	if (!ecdh->ec)
+	if (!ecdh->ec) {
+		LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_init);
 		goto fail;
+	}
 
-	ret = wc_ecc_make_key_ex(&ecdh->rng, ecdh->ec->key.dp->size,
-				 &ecdh->ec->key, ecdh->ec->key.dp->id);
-	if (ret < 0)
+#if defined(ECC_TIMING_RESISTANT) && !defined(WOLFSSL_OLD_FIPS)
+	ret = wc_ecc_set_rng(ecdh->ec->key, ecdh->rng);
+	if (ret != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_set_rng, ret);
 		goto fail;
+	}
+#endif /* ECC_TIMING_RESISTANT && !WOLFSSL_OLD_FIPS */
 
-#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);
-	ecdh = NULL;
-	goto done;
+	return NULL;
+}
+
+
+struct crypto_ecdh * crypto_ecdh_init(int group)
+{
+	struct crypto_ecdh *ret = NULL;
+	int err;
+
+	ret = _crypto_ecdh_init(group);
+
+	if (!ret) {
+		LOG_WOLF_ERROR_FUNC_NULL(_crypto_ecdh_init);
+		return NULL;
+	}
+
+	err = wc_ecc_make_key_ex(ret->rng, 0, ret->ec->key,
+				 crypto_ec_group_2_id(group));
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_make_key_ex, err);
+		crypto_ecdh_deinit(ret);
+		ret = NULL;
+	}
+
+	return ret;
+}
+
+
+struct crypto_ecdh * crypto_ecdh_init2(int group, struct crypto_ec_key *own_key)
+{
+	struct crypto_ecdh *ret = NULL;
+
+	if (!own_key || crypto_ec_key_group(own_key) != group) {
+		LOG_INVALID_PARAMETERS();
+		return NULL;
+	}
+
+	ret = _crypto_ecdh_init(group);
+	if (ret) {
+		/* Already init'ed to the right group. Enough to substitute the
+		 * key. */
+		ecc_key_deinit(ret->ec->key);
+		ret->ec->key = own_key->eckey;
+		ret->ec->own_key = false;
+#if defined(ECC_TIMING_RESISTANT) && !defined(WOLFSSL_OLD_FIPS)
+		if (!ret->ec->key->rng) {
+			int err = wc_ecc_set_rng(ret->ec->key, ret->rng);
+
+			if (err != 0)
+				LOG_WOLF_ERROR_FUNC(wc_ecc_set_rng, err);
+		}
+#endif /* ECC_TIMING_RESISTANT && !CONFIG_FIPS */
+	}
+
+	return ret;
 }
 
 
 void crypto_ecdh_deinit(struct crypto_ecdh *ecdh)
 {
 	if (ecdh) {
+#if defined(ECC_TIMING_RESISTANT) && !defined(WOLFSSL_OLD_FIPS)
+		/* Disassociate the rng */
+		if (ecdh->ec && ecdh->ec->key &&
+		    ecdh->ec->key->rng == ecdh->rng)
+			(void) wc_ecc_set_rng(ecdh->ec->key, NULL);
+#endif /* ECC_TIMING_RESISTANT && !WOLFSSL_OLD_FIPS */
 		crypto_ec_deinit(ecdh->ec);
-		wc_FreeRng(&ecdh->rng);
+		wc_rng_deinit(ecdh->rng);
 		os_free(ecdh);
 	}
 }
@@ -1766,20 +2200,20 @@
 {
 	struct wpabuf *buf = NULL;
 	int ret;
-	int len = ecdh->ec->key.dp->size;
+	int len = ecdh->ec->key->dp->size;
 
 	buf = wpabuf_alloc(inc_y ? 2 * len : len);
 	if (!buf)
 		goto fail;
 
 	ret = crypto_bignum_to_bin((struct crypto_bignum *)
-				   ecdh->ec->key.pubkey.x, wpabuf_put(buf, len),
+				   ecdh->ec->key->pubkey.x, wpabuf_put(buf, len),
 				   len, len);
 	if (ret < 0)
 		goto fail;
 	if (inc_y) {
 		ret = crypto_bignum_to_bin((struct crypto_bignum *)
-					   ecdh->ec->key.pubkey.y,
+					   ecdh->ec->key->pubkey.y,
 					   wpabuf_put(buf, len), len, len);
 		if (ret < 0)
 			goto fail;
@@ -1800,35 +2234,47 @@
 	int ret;
 	struct wpabuf *pubkey = NULL;
 	struct wpabuf *secret = NULL;
-	word32 key_len = ecdh->ec->key.dp->size;
+	word32 key_len = ecdh->ec->key->dp->size;
 	ecc_point *point = NULL;
 	size_t need_key_len = inc_y ? 2 * key_len : key_len;
 
-	if (len < need_key_len)
+	if (len < need_key_len) {
+		LOG_WOLF_ERROR("key len too small");
 		goto fail;
+	}
 	pubkey = wpabuf_alloc(1 + 2 * key_len);
-	if (!pubkey)
+	if (!pubkey) {
+		LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc);
 		goto fail;
+	}
 	wpabuf_put_u8(pubkey, inc_y ? ECC_POINT_UNCOMP : ECC_POINT_COMP_EVEN);
 	wpabuf_put_data(pubkey, key, need_key_len);
 
 	point = wc_ecc_new_point();
-	if (!point)
+	if (!point) {
+		LOG_WOLF_ERROR_FUNC_NULL(wc_ecc_new_point);
 		goto fail;
+	}
 
 	ret = wc_ecc_import_point_der(wpabuf_mhead(pubkey), 1 + 2 * key_len,
-				      ecdh->ec->key.idx, point);
-	if (ret != MP_OKAY)
+				      ecdh->ec->key->idx, point);
+	if (ret != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_import_point_der, ret);
 		goto fail;
+	}
 
 	secret = wpabuf_alloc(key_len);
-	if (!secret)
+	if (!secret) {
+		LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc);
 		goto fail;
+	}
 
-	ret = wc_ecc_shared_secret_ex(&ecdh->ec->key, point,
+	ret = wc_ecc_shared_secret_ex(ecdh->ec->key, point,
 				      wpabuf_put(secret, key_len), &key_len);
-	if (ret != MP_OKAY)
+	if (ret != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_shared_secret_ex, ret);
 		goto fail;
+	}
 
 done:
 	wc_ecc_del_point(point);
@@ -1846,41 +2292,21 @@
 	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 */
+		key->eckey = ecc_key_init();
 		/* 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");
+			LOG_WOLF_ERROR_FUNC_NULL(ecc_key_init);
 			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;
 }
@@ -1889,32 +2315,40 @@
 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 */
+		ecc_key_deinit(key->eckey);
+		wc_rng_deinit(key->rng);
 		os_free(key);
 	}
 }
 
 
+static WC_RNG * crypto_ec_key_init_rng(struct crypto_ec_key *key)
+{
+	if (!key->rng) {
+		/* Lazy init key->rng */
+		key->rng = wc_rng_init();
+		if (!key->rng)
+			LOG_WOLF_ERROR_FUNC_NULL(wc_rng_init);
+	}
+	return key->rng;
+}
+
+
 struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len)
 {
 	struct crypto_ec_key *ret;
 	word32 idx = 0;
+	int err;
 
 	ret = crypto_ec_key_init();
 	if (!ret) {
-		wpa_printf(MSG_ERROR, "wolfSSL: crypto_ec_key_init failed");
+		LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init);
 		goto fail;
 	}
 
-	if (wc_EccPrivateKeyDecode(der, &idx, ret->eckey, (word32) der_len) !=
-	    0) {
-		wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPrivateKeyDecode failed");
+	err = wc_EccPrivateKeyDecode(der, &idx, ret->eckey, (word32) der_len);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_EccPrivateKeyDecode, err);
 		goto fail;
 	}
 
@@ -1930,8 +2364,7 @@
 {
 
 	if (!key || !key->eckey || !key->eckey->dp) {
-		wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters",
-			   __func__);
+		LOG_INVALID_PARAMETERS();
 		return -1;
 	}
 
@@ -1942,54 +2375,114 @@
 		return 20;
 	case ECC_SECP521R1:
 		return 21;
+	case ECC_SECP192R1:
+		return 25;
+	case ECC_SECP224R1:
+		return 26;
+#ifdef HAVE_ECC_BRAINPOOL
+	case ECC_BRAINPOOLP224R1:
+		return 27;
 	case ECC_BRAINPOOLP256R1:
 		return 28;
 	case ECC_BRAINPOOLP384R1:
 		return 29;
 	case ECC_BRAINPOOLP512R1:
 		return 30;
+#endif /* HAVE_ECC_BRAINPOOL */
 	}
 
-	wpa_printf(MSG_ERROR, "wolfSSL: Unsupported curve (id=%d) in EC key",
-		   key->eckey->dp->id);
+	LOG_WOLF_ERROR_VA("Unsupported curve (id=%d) in EC key",
+			  key->eckey->dp->id);
 	return -1;
 }
 
 
+static int crypto_ec_key_gen_public_key(struct crypto_ec_key *key)
+{
+	int err;
+
+#ifdef WOLFSSL_OLD_FIPS
+	err = wc_ecc_make_pub(key->eckey, NULL);
+#else /* WOLFSSL_OLD_FIPS */
+	/* Have wolfSSL generate the public key to make it available for output
+	 */
+	if (!crypto_ec_key_init_rng(key)) {
+		LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init_rng);
+		return -1;
+	}
+
+	err = wc_ecc_make_pub_ex(key->eckey, NULL, key->rng);
+#endif /* WOLFSSL_OLD_FIPS */
+
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_make_pub_ex, err);
+		return -1;
+	}
+
+	return 0;
+}
+
+
 struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key)
 {
-	byte *der = NULL;
 	int der_len;
 	struct wpabuf *ret = NULL;
+	int err;
 
 	if (!key || !key->eckey) {
-		wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters",
-			   __func__);
+		LOG_INVALID_PARAMETERS();
 		goto fail;
 	}
 
-	der_len = wc_EccPublicKeyDerSize(key->eckey, 1);
-	if (der_len <= 0) {
-		wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPublicKeyDerSize failed");
+#ifdef WOLFSSL_OLD_FIPS
+	if (key->eckey->type == ECC_PRIVATEKEY_ONLY &&
+	    crypto_ec_key_gen_public_key(key) != 0) {
+		LOG_WOLF_ERROR_FUNC(crypto_ec_key_gen_public_key, -1);
+		goto fail;
+	}
+#endif /* WOLFSSL_OLD_FIPS */
+
+	der_len = err = wc_EccPublicKeyToDer_ex(key->eckey, NULL, 0, 1, 1);
+	if (err == ECC_PRIVATEONLY_E) {
+		if (crypto_ec_key_gen_public_key(key) != 0) {
+			LOG_WOLF_ERROR_FUNC(crypto_ec_key_gen_public_key, -1);
+			goto fail;
+		}
+		der_len = err = wc_EccPublicKeyToDer_ex(key->eckey, NULL, 0, 1,
+							1);
+	}
+	if (err <= 0) {
+		LOG_WOLF_ERROR_FUNC(wc_EccPublicKeyDerSize, err);
 		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");
+	ret = wpabuf_alloc(der_len);
+	if (!ret) {
+		LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc);
 		goto fail;
 	}
 
-	ret = wpabuf_alloc_copy(der, der_len);
-	os_free(der);
+	err = wc_EccPublicKeyToDer_ex(key->eckey, wpabuf_mhead(ret), der_len, 1,
+				      1);
+	if (err == ECC_PRIVATEONLY_E) {
+		if (crypto_ec_key_gen_public_key(key) != 0) {
+			LOG_WOLF_ERROR_FUNC(crypto_ec_key_gen_public_key, -1);
+			goto fail;
+		}
+		err = wc_EccPublicKeyToDer_ex(key->eckey, wpabuf_mhead(ret),
+					      der_len, 1, 1);
+	}
+	if (err <= 0) {
+		LOG_WOLF_ERROR_FUNC(wc_EccPublicKeyToDer, err);
+		goto fail;
+	}
+	der_len = err;
+	wpabuf_put(ret, der_len);
+
 	return ret;
 
 fail:
-	os_free(der);
+	wpabuf_free(ret);
 	return NULL;
 }
 
@@ -1998,16 +2491,17 @@
 {
 	word32 idx = 0;
 	struct crypto_ec_key *ret = NULL;
+	int err;
 
 	ret = crypto_ec_key_init();
 	if (!ret) {
-		wpa_printf(MSG_ERROR, "wolfSSL: crypto_ec_key_init failed");
+		LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init);
 		goto fail;
 	}
 
-	if (wc_EccPublicKeyDecode(der, &idx, ret->eckey, (word32) der_len) != 0)
-	{
-		wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPublicKeyDecode failed");
+	err = wc_EccPublicKeyDecode(der, &idx, ret->eckey, (word32) der_len);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_EccPublicKeyDecode, err);
 		goto fail;
 	}
 
@@ -2021,60 +2515,45 @@
 struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data,
 				   size_t len)
 {
-	byte *der = NULL;
 	int der_len;
+	int err;
 	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__);
+		LOG_INVALID_PARAMETERS();
 		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 */
+	if (!crypto_ec_key_init_rng(key)) {
+		LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init_rng);
+		goto fail;
 	}
 
 	der_len = wc_ecc_sig_size(key->eckey);
 	if (der_len <= 0) {
-		wpa_printf(MSG_ERROR, "wolfSSL: wc_ecc_sig_size failed");
+		LOG_WOLF_ERROR_FUNC(wc_ecc_sig_size, der_len);
 		goto fail;
 	}
 
-	der = os_malloc(der_len);
-	if (!der)
+	ret = wpabuf_alloc(der_len);
+	if (!ret) {
+		LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc);
 		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");
+	err = wc_ecc_sign_hash(data, len, wpabuf_mhead(ret), &w32_der_len,
+			       key->rng, key->eckey);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_sign_hash, err);
 		goto fail;
 	}
+	wpabuf_put(ret, w32_der_len);
 
-	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);
+	wpabuf_free(ret);
 	return NULL;
 }
 
@@ -2085,26 +2564,996 @@
 	int res = 0;
 
 	if (!key || !key->eckey || !data || len == 0 || !sig || sig_len == 0) {
-		wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters",
-			   __func__);
+		LOG_INVALID_PARAMETERS();
 		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");
+		LOG_WOLF_ERROR("wc_ecc_verify_hash failed");
 		return -1;
 	}
 
 	if (res != 1)
-		wpa_printf(MSG_DEBUG,
-			   "wolfSSL: crypto_ec_key_verify_signature failed");
+		LOG_WOLF_ERROR("crypto_ec_key_verify_signature failed");
 
 	return res;
 }
 
 #endif /* CONFIG_ECC */
 
+#ifdef CONFIG_DPP
+
+struct wpabuf * crypto_ec_key_get_ecprivate_key(struct crypto_ec_key *key,
+						bool include_pub)
+{
+	int len;
+	int err;
+	struct wpabuf *ret = NULL;
+
+	if (!key || !key->eckey) {
+		LOG_INVALID_PARAMETERS();
+		return NULL;
+	}
+
+#ifdef WOLFSSL_OLD_FIPS
+	if (key->eckey->type != ECC_PRIVATEKEY &&
+	    key->eckey->type != ECC_PRIVATEKEY_ONLY) {
+		LOG_INVALID_PARAMETERS();
+		return NULL;
+	}
+#endif /* WOLFSSL_OLD_FIPS */
+
+	len = err = wc_EccKeyDerSize(key->eckey, include_pub);
+	if (err == ECC_PRIVATEONLY_E && include_pub) {
+		if (crypto_ec_key_gen_public_key(key) != 0) {
+			LOG_WOLF_ERROR_FUNC(crypto_ec_key_gen_public_key, -1);
+			return NULL;
+		}
+		len = err = wc_EccKeyDerSize(key->eckey, include_pub);
+	}
+	if (err <= 0) {
+		/* Exception for BAD_FUNC_ARG because higher levels blindly call
+		 * this function to determine if this is a private key or not.
+		 * BAD_FUNC_ARG most probably means that key->eckey is a public
+		 * key not private. */
+		if (err != BAD_FUNC_ARG)
+			LOG_WOLF_ERROR_FUNC(wc_EccKeyDerSize, err);
+		return NULL;
+	}
+
+	ret = wpabuf_alloc(len);
+	if (!ret) {
+		LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc);
+		return NULL;
+	}
+
+	if (include_pub)
+		err = wc_EccKeyToDer(key->eckey, wpabuf_put(ret, len), len);
+	else
+		err = wc_EccPrivateKeyToDer(key->eckey, wpabuf_put(ret, len),
+					    len);
+
+	if (err != len) {
+		LOG_WOLF_ERROR_VA("%s failed with err: %d", include_pub ?
+				  "wc_EccKeyToDer" : "wc_EccPrivateKeyToDer",
+				  err);
+		wpabuf_free(ret);
+		ret = NULL;
+	}
+
+	return ret;
+}
+
+
+struct wpabuf * crypto_ec_key_get_pubkey_point(struct crypto_ec_key *key,
+					       int prefix)
+{
+	int err;
+	word32 len = 0;
+	struct wpabuf *ret = NULL;
+
+	if (!key || !key->eckey) {
+		LOG_INVALID_PARAMETERS();
+		return NULL;
+	}
+
+	err = wc_ecc_export_x963(key->eckey, NULL, &len);
+	if (err != LENGTH_ONLY_E) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_export_x963, err);
+		goto fail;
+	}
+
+	ret = wpabuf_alloc(len);
+	if (!ret) {
+		LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc);
+		goto fail;
+	}
+
+	err = wc_ecc_export_x963(key->eckey, wpabuf_mhead(ret), &len);
+	if (err == ECC_PRIVATEONLY_E) {
+		if (crypto_ec_key_gen_public_key(key) != 0) {
+			LOG_WOLF_ERROR_FUNC(crypto_ec_key_gen_public_key, -1);
+			goto fail;
+		}
+		err = wc_ecc_export_x963(key->eckey, wpabuf_mhead(ret), &len);
+	}
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_export_x963, err);
+		goto fail;
+	}
+
+	if (!prefix)
+		os_memmove(wpabuf_mhead(ret), wpabuf_mhead_u8(ret) + 1,
+			   (size_t)--len);
+	wpabuf_put(ret, len);
+
+	return ret;
+
+fail:
+	wpabuf_free(ret);
+	return NULL;
+}
+
+
+struct crypto_ec_key * crypto_ec_key_set_pub(int group, const u8 *x,
+					     const u8 *y, size_t len)
+{
+	struct crypto_ec_key *ret = NULL;
+	int curve_id = crypto_ec_group_2_id(group);
+	int err;
+
+	if (!x || !y || len == 0 || curve_id == ECC_CURVE_INVALID ||
+	    wc_ecc_get_curve_size_from_id(curve_id) != (int) len) {
+		LOG_INVALID_PARAMETERS();
+		return NULL;
+	}
+
+	ret = crypto_ec_key_init();
+	if (!ret) {
+		LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init);
+		return NULL;
+	}
+
+	/* Cast necessary for FIPS API */
+	err = wc_ecc_import_unsigned(ret->eckey, (u8 *) x, (u8 *) y, NULL,
+				     curve_id);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_import_unsigned, err);
+		crypto_ec_key_deinit(ret);
+		return NULL;
+	}
+
+	return ret;
+}
+
+
+int crypto_ec_key_cmp(struct crypto_ec_key *key1, struct crypto_ec_key *key2)
+{
+	int ret;
+	struct wpabuf *key1_buf = crypto_ec_key_get_subject_public_key(key1);
+	struct wpabuf *key2_buf = crypto_ec_key_get_subject_public_key(key2);
+
+	if ((key1 && !key1_buf) || (key2 && !key2_buf)) {
+		LOG_WOLF_ERROR("crypto_ec_key_get_subject_public_key failed");
+		return -1;
+	}
+
+	ret = wpabuf_cmp(key1_buf, key2_buf);
+	if (ret != 0)
+		ret = -1; /* Default to -1 for different keys */
+
+	wpabuf_clear_free(key1_buf);
+	wpabuf_clear_free(key2_buf);
+	return ret;
+}
+
+
+/* wolfSSL doesn't have a pretty print function for keys so just print out the
+ * PEM of the private key. */
+void crypto_ec_key_debug_print(const struct crypto_ec_key *key,
+			       const char *title)
+{
+	struct wpabuf * key_buf;
+	struct wpabuf * out = NULL;
+	int err;
+	int pem_len;
+
+	if (!key || !key->eckey) {
+		LOG_INVALID_PARAMETERS();
+		return;
+	}
+
+	if (key->eckey->type == ECC_PUBLICKEY)
+		key_buf = crypto_ec_key_get_subject_public_key(
+			(struct crypto_ec_key *) key);
+	else
+		key_buf = crypto_ec_key_get_ecprivate_key(
+			(struct crypto_ec_key *) key, 1);
+
+	if (!key_buf) {
+		LOG_WOLF_ERROR_VA("%s has returned NULL",
+				  key->eckey->type == ECC_PUBLICKEY ?
+				  "crypto_ec_key_get_subject_public_key" :
+				  "crypto_ec_key_get_ecprivate_key");
+		goto fail;
+	}
+
+	if (!title)
+		title = "";
+
+	err = wc_DerToPem(wpabuf_head(key_buf), wpabuf_len(key_buf), NULL, 0,
+			  ECC_TYPE);
+	if (err <= 0) {
+		LOG_WOLF_ERROR_FUNC(wc_DerToPem, err);
+		goto fail;
+	}
+	pem_len = err;
+
+	out = wpabuf_alloc(pem_len + 1);
+	if (!out) {
+		LOG_WOLF_ERROR_FUNC_NULL(wc_DerToPem);
+		goto fail;
+	}
+
+	err = wc_DerToPem(wpabuf_head(key_buf), wpabuf_len(key_buf),
+			  wpabuf_mhead(out), pem_len, ECC_TYPE);
+	if (err <= 0) {
+		LOG_WOLF_ERROR_FUNC(wc_DerToPem, err);
+		goto fail;
+	}
+
+	wpabuf_mhead_u8(out)[err] = '\0';
+	wpabuf_put(out, err + 1);
+	wpa_printf(MSG_DEBUG, "%s:\n%s", title,
+		   (const char *) wpabuf_head(out));
+
+fail:
+	wpabuf_clear_free(key_buf);
+	wpabuf_clear_free(out);
+}
+
+
+void crypto_ec_point_debug_print(const struct crypto_ec *e,
+				 const struct crypto_ec_point *p,
+				 const char *title)
+{
+	u8 x[ECC_MAXSIZE];
+	u8 y[ECC_MAXSIZE];
+	int coord_size;
+	int err;
+
+	if (!p || !e) {
+		LOG_INVALID_PARAMETERS();
+		return;
+	}
+
+	coord_size = e->key->dp->size;
+
+	if (!title)
+		title = "";
+
+	err = crypto_ec_point_to_bin((struct crypto_ec *)e, p, x, y);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(crypto_ec_point_to_bin, err);
+		return;
+	}
+
+	wpa_hexdump(MSG_DEBUG, title, x, coord_size);
+	wpa_hexdump(MSG_DEBUG, title, y, coord_size);
+}
+
+
+struct crypto_ec_key * crypto_ec_key_gen(int group)
+{
+	int curve_id = crypto_ec_group_2_id(group);
+	int err;
+	struct crypto_ec_key * ret = NULL;
+
+	if (curve_id == ECC_CURVE_INVALID) {
+		LOG_INVALID_PARAMETERS();
+		return NULL;
+	}
+
+	ret = crypto_ec_key_init();
+	if (!ret) {
+		LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init);
+		return NULL;
+	}
+
+	if (!crypto_ec_key_init_rng(ret)) {
+		LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init_rng);
+		goto fail;
+	}
+
+	err = wc_ecc_make_key_ex(ret->rng, 0, ret->eckey, curve_id);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_make_key_ex, err);
+		goto fail;
+	}
+
+	return ret;
+fail:
+	crypto_ec_key_deinit(ret);
+	return NULL;
+}
+
+
+int crypto_ec_key_verify_signature_r_s(struct crypto_ec_key *key,
+				       const u8 *data, size_t len,
+				       const u8 *r, size_t r_len,
+				       const u8 *s, size_t s_len)
+{
+	int err;
+	u8 sig[ECC_MAX_SIG_SIZE];
+	word32 sig_len = ECC_MAX_SIG_SIZE;
+
+	if (!key || !key->eckey || !data || !len || !r || !r_len ||
+	    !s || !s_len) {
+		LOG_INVALID_PARAMETERS();
+		return -1;
+	}
+
+	err = wc_ecc_rs_raw_to_sig(r, r_len, s, s_len, sig, &sig_len);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_rs_raw_to_sig, err);
+		return -1;
+	}
+
+	return crypto_ec_key_verify_signature(key, data, len, sig, sig_len);
+}
+
+
+struct crypto_ec_point * crypto_ec_key_get_public_key(struct crypto_ec_key *key)
+{
+	ecc_point *point = NULL;
+	int err;
+	u8 *der = NULL;
+	word32 der_len = 0;
+
+	if (!key || !key->eckey || !key->eckey->dp) {
+		LOG_INVALID_PARAMETERS();
+		goto fail;
+	}
+
+	err = wc_ecc_export_x963(key->eckey, NULL, &der_len);
+	if (err != LENGTH_ONLY_E) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_export_x963, err);
+		goto fail;
+	}
+
+	der = os_malloc(der_len);
+	if (!der) {
+		LOG_WOLF_ERROR_FUNC_NULL(os_malloc);
+		goto fail;
+	}
+
+	err = wc_ecc_export_x963(key->eckey, der, &der_len);
+	if (err == ECC_PRIVATEONLY_E) {
+		if (crypto_ec_key_gen_public_key(key) != 0) {
+			LOG_WOLF_ERROR_FUNC(crypto_ec_key_gen_public_key, -1);
+			goto fail;
+		}
+		err = wc_ecc_export_x963(key->eckey, der, &der_len);
+	}
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_export_x963, err);
+		goto fail;
+	}
+
+	point = wc_ecc_new_point();
+	if (!point) {
+		LOG_WOLF_ERROR_FUNC_NULL(wc_ecc_new_point);
+		goto fail;
+	}
+
+	err = wc_ecc_import_point_der(der, der_len, key->eckey->idx, point);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_import_point_der, err);
+		goto fail;
+	}
+
+	os_free(der);
+	return (struct crypto_ec_point *) point;
+
+fail:
+	os_free(der);
+	if (point)
+		wc_ecc_del_point(point);
+	return NULL;
+}
+
+
+struct crypto_bignum * crypto_ec_key_get_private_key(struct crypto_ec_key *key)
+{
+	u8 priv[ECC_MAXSIZE];
+	word32 priv_len = ECC_MAXSIZE;
+#ifdef WOLFSSL_OLD_FIPS
+	/* Needed to be compliant with the old API */
+	u8 qx[ECC_MAXSIZE];
+	word32 qx_len = ECC_MAXSIZE;
+	u8 qy[ECC_MAXSIZE];
+	word32 qy_len = ECC_MAXSIZE;
+#endif /* WOLFSSL_OLD_FIPS */
+	struct crypto_bignum *ret = NULL;
+	int err;
+
+	if (!key || !key->eckey) {
+		LOG_INVALID_PARAMETERS();
+		return NULL;
+	}
+
+#ifndef WOLFSSL_OLD_FIPS
+	err = wc_ecc_export_private_raw(key->eckey, NULL, NULL, NULL, NULL,
+					priv, &priv_len);
+#else /* WOLFSSL_OLD_FIPS */
+	err = wc_ecc_export_private_raw(key->eckey, qx, &qx_len, qy, &qy_len,
+					priv, &priv_len);
+#endif /* WOLFSSL_OLD_FIPS */
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_export_private_raw, err);
+		return NULL;
+	}
+
+	ret = crypto_bignum_init_set(priv, priv_len);
+	forced_memzero(priv, priv_len);
+	return ret;
+}
+
+
+struct wpabuf * crypto_ec_key_sign_r_s(struct crypto_ec_key *key,
+				       const u8 *data, size_t len)
+{
+	int err;
+	u8 success = 0;
+	mp_int r;
+	mp_int s;
+	u8 rs_init = 0;
+	int sz;
+	struct wpabuf * ret = NULL;
+
+	if (!key || !key->eckey || !key->eckey->dp || !data || !len) {
+		LOG_INVALID_PARAMETERS();
+		return NULL;
+	}
+
+	sz = key->eckey->dp->size;
+
+	if (!crypto_ec_key_init_rng(key)) {
+		LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init_rng);
+		goto fail;
+	}
+
+	err = mp_init_multi(&r, &s, NULL, NULL, NULL, NULL);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(mp_init_multi, err);
+		goto fail;
+	}
+	rs_init = 1;
+
+	err = wc_ecc_sign_hash_ex(data, len, key->rng, key->eckey, &r, &s);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_sign_hash_ex, err);
+		goto fail;
+	}
+
+	if (mp_unsigned_bin_size(&r) > sz || mp_unsigned_bin_size(&s) > sz) {
+		LOG_WOLF_ERROR_VA("Unexpected size of r or s (%d %d %d)", sz,
+				  mp_unsigned_bin_size(&r),
+				  mp_unsigned_bin_size(&s));
+		goto fail;
+	}
+
+	ret = wpabuf_alloc(2 * sz);
+	if (!ret) {
+		LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc);
+		goto fail;
+	}
+
+	err = mp_to_unsigned_bin_len(&r, wpabuf_put(ret, sz), sz);
+	if (err == MP_OKAY)
+		err = mp_to_unsigned_bin_len(&s, wpabuf_put(ret, sz), sz);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_sign_hash_ex, err);
+		goto fail;
+	}
+
+	success = 1;
+fail:
+	if (rs_init) {
+		mp_free(&r);
+		mp_free(&s);
+	}
+	if (!success) {
+		wpabuf_free(ret);
+		ret = NULL;
+	}
+
+	return ret;
+}
+
+
+struct crypto_ec_key *
+crypto_ec_key_set_pub_point(struct crypto_ec *e,
+			    const struct crypto_ec_point *pub)
+{
+	struct crypto_ec_key  *ret = NULL;
+	int err;
+	byte *buf = NULL;
+	word32 buf_len = 0;
+
+	if (!e || !pub) {
+		LOG_INVALID_PARAMETERS();
+		return NULL;
+	}
+
+	/* Export to DER to not mess with wolfSSL internals */
+	err = wc_ecc_export_point_der(wc_ecc_get_curve_idx(e->curve_id),
+				      (ecc_point *) pub, NULL, &buf_len);
+	if (err != LENGTH_ONLY_E || !buf_len) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_export_point_der, err);
+		goto fail;
+	}
+
+	buf = os_malloc(buf_len);
+	if (!buf) {
+		LOG_WOLF_ERROR_FUNC_NULL(os_malloc);
+		goto fail;
+	}
+
+	err = wc_ecc_export_point_der(wc_ecc_get_curve_idx(e->curve_id),
+			(ecc_point *) pub, buf, &buf_len);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_export_point_der, err);
+		goto fail;
+	}
+
+	ret = crypto_ec_key_init();
+	if (!ret) {
+		LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init);
+		goto fail;
+	}
+
+	err = wc_ecc_import_x963_ex(buf, buf_len, ret->eckey, e->curve_id);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_import_x963_ex, err);
+		goto fail;
+	}
+
+	os_free(buf);
+	return ret;
+
+fail:
+	os_free(buf);
+	crypto_ec_key_deinit(ret);
+	return NULL;
+}
+
+
+struct wpabuf * crypto_pkcs7_get_certificates(const struct wpabuf *pkcs7)
+{
+	PKCS7 *p7 = NULL;
+	struct wpabuf *ret = NULL;
+	int err = 0;
+	int total_sz = 0;
+	int i;
+
+	if (!pkcs7) {
+		LOG_INVALID_PARAMETERS();
+		return NULL;
+	}
+
+	p7 = wc_PKCS7_New(NULL, INVALID_DEVID);
+	if (!p7) {
+		LOG_WOLF_ERROR_FUNC_NULL(wc_PKCS7_New);
+		return NULL;
+	}
+
+	err = wc_PKCS7_VerifySignedData(p7, (byte *) wpabuf_head(pkcs7),
+					wpabuf_len(pkcs7));
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_PKCS7_VerifySignedData, err);
+		wc_PKCS7_Free(p7);
+		goto fail;
+	}
+
+	/* Need to access p7 members directly */
+	for (i = 0; i < MAX_PKCS7_CERTS; i++) {
+		if (p7->certSz[i] == 0)
+			continue;
+		err = wc_DerToPem(p7->cert[i], p7->certSz[i], NULL, 0,
+				  CERT_TYPE);
+		if (err > 0) {
+			total_sz += err;
+		} else {
+			LOG_WOLF_ERROR_FUNC(wc_DerToPem, err);
+			goto fail;
+		}
+	}
+
+	if (total_sz == 0) {
+		LOG_WOLF_ERROR("No certificates found in PKCS7 input");
+		goto fail;
+	}
+
+	ret = wpabuf_alloc(total_sz);
+	if (!ret) {
+		LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc);
+		goto fail;
+	}
+
+	/* Need to access p7 members directly */
+	for (i = 0; i < MAX_PKCS7_CERTS; i++) {
+		if (p7->certSz[i] == 0)
+			continue;
+		/* Not using wpabuf_put() here so that wpabuf_overflow() isn't
+		 * called in case of a size mismatch. wc_DerToPem() checks if
+		 * the output is large enough internally. */
+		err = wc_DerToPem(p7->cert[i], p7->certSz[i],
+				  wpabuf_mhead_u8(ret) + wpabuf_len(ret),
+				  wpabuf_tailroom(ret),
+				  CERT_TYPE);
+		if (err > 0) {
+			wpabuf_put(ret, err);
+		} else {
+			LOG_WOLF_ERROR_FUNC(wc_DerToPem, err);
+			wpabuf_free(ret);
+			ret = NULL;
+			goto fail;
+		}
+	}
+
+fail:
+	if (p7)
+		wc_PKCS7_Free(p7);
+	return ret;
+}
+
+
+/* BEGIN Certificate Signing Request (CSR) APIs */
+
+enum cert_type {
+	cert_type_none = 0,
+	cert_type_decoded_cert,
+	cert_type_cert,
+};
+
+struct crypto_csr {
+	union {
+		/* For parsed csr should be read-only for higher levels */
+		DecodedCert dc;
+		Cert c; /* For generating a csr */
+	} req;
+	enum cert_type type;
+	struct crypto_ec_key *pubkey;
+};
+
+
+/* Helper function to make sure that the correct type is initialized */
+static void crypto_csr_init_type(struct crypto_csr *csr, enum cert_type type,
+				 const byte *source, word32 in_sz)
+{
+	int err;
+
+	if (csr->type == type)
+		return; /* Already correct type */
+
+	switch (csr->type) {
+	case cert_type_decoded_cert:
+		wc_FreeDecodedCert(&csr->req.dc);
+		break;
+	case cert_type_cert:
+#ifdef WOLFSSL_CERT_GEN_CACHE
+		wc_SetCert_Free(&csr->req.c);
+#endif /* WOLFSSL_CERT_GEN_CACHE */
+		break;
+	case cert_type_none:
+		break;
+	}
+
+	switch (type) {
+	case cert_type_decoded_cert:
+		wc_InitDecodedCert(&csr->req.dc, source, in_sz, NULL);
+		break;
+	case cert_type_cert:
+		err = wc_InitCert(&csr->req.c);
+		if (err != 0)
+			LOG_WOLF_ERROR_FUNC(wc_InitCert, err);
+		break;
+	case cert_type_none:
+		break;
+	}
+
+	csr->type = type;
+}
+
+
+struct crypto_csr * crypto_csr_init(void)
+{
+	struct crypto_csr *ret = os_malloc(sizeof(struct crypto_csr));
+
+	if (!ret) {
+		LOG_WOLF_ERROR_FUNC_NULL(os_malloc);
+		return NULL;
+	}
+
+	ret->type = cert_type_none;
+	crypto_csr_init_type(ret, cert_type_cert, NULL, 0);
+	ret->pubkey = NULL;
+
+	return ret;
+}
+
+
+void crypto_csr_deinit(struct crypto_csr *csr)
+{
+	if (csr) {
+		crypto_csr_init_type(csr, cert_type_none, NULL, 0);
+		crypto_ec_key_deinit(csr->pubkey);
+		os_free(csr);
+	}
+}
+
+
+int crypto_csr_set_ec_public_key(struct crypto_csr *csr,
+				 struct crypto_ec_key *key)
+{
+	struct wpabuf *der = NULL;
+
+	if (!csr || !key || !key->eckey) {
+		LOG_INVALID_PARAMETERS();
+		return -1;
+	}
+
+	if (csr->pubkey) {
+		crypto_ec_key_deinit(csr->pubkey);
+		csr->pubkey = NULL;
+	}
+
+	/* Create copy of key to mitigate use-after-free errors */
+	der = crypto_ec_key_get_subject_public_key(key);
+	if (!der) {
+		LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_get_subject_public_key);
+		return -1;
+	}
+
+	csr->pubkey = crypto_ec_key_parse_pub(wpabuf_head(der),
+					      wpabuf_len(der));
+	wpabuf_free(der);
+	if (!csr->pubkey) {
+		LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_parse_pub);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int crypto_csr_set_name(struct crypto_csr *csr, enum crypto_csr_name type,
+			const char *name)
+{
+	int name_len;
+	char *dest;
+
+	if (!csr || !name) {
+		LOG_INVALID_PARAMETERS();
+		return -1;
+	}
+
+	if (csr->type != cert_type_cert) {
+		LOG_WOLF_ERROR_VA("csr is incorrect type (%d)", csr->type);
+		return -1;
+	}
+
+	name_len = os_strlen(name);
+	if (name_len >= CTC_NAME_SIZE) {
+		LOG_WOLF_ERROR("name input too long");
+		return -1;
+	}
+
+	switch (type) {
+	case CSR_NAME_CN:
+		dest = csr->req.c.subject.commonName;
+		break;
+	case CSR_NAME_SN:
+		dest = csr->req.c.subject.sur;
+		break;
+	case CSR_NAME_C:
+		dest = csr->req.c.subject.country;
+		break;
+	case CSR_NAME_O:
+		dest = csr->req.c.subject.org;
+		break;
+	case CSR_NAME_OU:
+		dest = csr->req.c.subject.unit;
+		break;
+	default:
+		LOG_INVALID_PARAMETERS();
+		return -1;
+	}
+
+	os_memcpy(dest, name, name_len);
+	dest[name_len] = '\0';
+
+	return 0;
+}
+
+
+int crypto_csr_set_attribute(struct crypto_csr *csr, enum crypto_csr_attr attr,
+			     int attr_type, const u8 *value, size_t len)
+{
+	if (!csr || attr_type != ASN1_TAG_UTF8STRING || !value ||
+	    len >= CTC_NAME_SIZE) {
+		LOG_INVALID_PARAMETERS();
+		return -1;
+	}
+
+	if (csr->type != cert_type_cert) {
+		LOG_WOLF_ERROR_VA("csr is incorrect type (%d)", csr->type);
+		return -1;
+	}
+
+	switch (attr) {
+	case CSR_ATTR_CHALLENGE_PASSWORD:
+		os_memcpy(csr->req.c.challengePw, value, len);
+		csr->req.c.challengePw[len] = '\0';
+		break;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+
+const u8 * crypto_csr_get_attribute(struct crypto_csr *csr,
+				    enum crypto_csr_attr attr,
+				    size_t *len, int *type)
+{
+	if (!csr || !len || !type) {
+		LOG_INVALID_PARAMETERS();
+		return NULL;;
+	}
+
+	switch (attr) {
+	case CSR_ATTR_CHALLENGE_PASSWORD:
+		switch (csr->type) {
+		case cert_type_decoded_cert:
+			*type = ASN1_TAG_UTF8STRING;
+			*len = csr->req.dc.cPwdLen;
+			return (const u8 *) csr->req.dc.cPwd;
+		case cert_type_cert:
+			*type = ASN1_TAG_UTF8STRING;
+			*len = os_strlen(csr->req.c.challengePw);
+			return (const u8 *) csr->req.c.challengePw;
+		case cert_type_none:
+			return NULL;
+		}
+		break;
+	}
+	return NULL;
+}
+
+
+struct wpabuf * crypto_csr_sign(struct crypto_csr *csr,
+				struct crypto_ec_key *key,
+				enum crypto_hash_alg algo)
+{
+	int err;
+	int len;
+	u8 *buf = NULL;
+	int buf_len;
+	struct wpabuf *ret = NULL;
+
+	if (!csr || !key || !key->eckey) {
+		LOG_INVALID_PARAMETERS();
+		return NULL;
+	}
+
+	if (csr->type != cert_type_cert) {
+		LOG_WOLF_ERROR_VA("csr is incorrect type (%d)", csr->type);
+		return NULL;
+	}
+
+	if (!crypto_ec_key_init_rng(key)) {
+		LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init_rng);
+		return NULL;
+	}
+
+	switch (algo) {
+	case CRYPTO_HASH_ALG_SHA256:
+		csr->req.c.sigType = CTC_SHA256wECDSA;
+		break;
+	case CRYPTO_HASH_ALG_SHA384:
+		csr->req.c.sigType = CTC_SHA384wECDSA;
+		break;
+	case CRYPTO_HASH_ALG_SHA512:
+		csr->req.c.sigType = CTC_SHA512wECDSA;
+		break;
+	default:
+		LOG_INVALID_PARAMETERS();
+		return NULL;
+	}
+
+	/* Pass in large value that is guaranteed to be larger than the
+	 * necessary buffer */
+	err = wc_MakeCertReq(&csr->req.c, NULL, 100000, NULL,
+			     csr->pubkey->eckey);
+	if (err <= 0) {
+		LOG_WOLF_ERROR_FUNC(wc_MakeCertReq, err);
+		goto fail;
+	}
+	len = err;
+
+	buf_len = len + MAX_SEQ_SZ * 2 + MAX_ENCODED_SIG_SZ;
+	buf = os_malloc(buf_len);
+	if (!buf) {
+		LOG_WOLF_ERROR_FUNC_NULL(os_malloc);
+		goto fail;
+	}
+
+	err = wc_MakeCertReq(&csr->req.c, buf, buf_len, NULL,
+			     csr->pubkey->eckey);
+	if (err <= 0) {
+		LOG_WOLF_ERROR_FUNC(wc_MakeCertReq, err);
+		goto fail;
+	}
+	len = err;
+
+	err = wc_SignCert(len, csr->req.c.sigType, buf, buf_len, NULL,
+			  key->eckey, key->rng);
+	if (err <= 0) {
+		LOG_WOLF_ERROR_FUNC(wc_SignCert, err);
+		goto fail;
+	}
+	len = err;
+
+	ret = wpabuf_alloc_copy(buf, len);
+	if (!ret) {
+		LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc_copy);
+		goto fail;
+	}
+
+fail:
+	os_free(buf);
+	return ret;
+}
+
+
+struct crypto_csr * crypto_csr_verify(const struct wpabuf *req)
+{
+	struct crypto_csr *csr = NULL;
+	int err;
+
+	if (!req) {
+		LOG_INVALID_PARAMETERS();
+		return NULL;
+	}
+
+	csr = crypto_csr_init();
+	if (!csr) {
+		LOG_WOLF_ERROR_FUNC_NULL(crypto_csr_init);
+		goto fail;
+	}
+
+	crypto_csr_init_type(csr, cert_type_decoded_cert,
+			     wpabuf_head(req), wpabuf_len(req));
+	err = wc_ParseCert(&csr->req.dc, CERTREQ_TYPE, VERIFY, NULL);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_ParseCert, err);
+		goto fail;
+	}
+
+	return csr;
+fail:
+	crypto_csr_deinit(csr);
+	return NULL;
+}
+
+/* END Certificate Signing Request (CSR) APIs */
+
+#endif /* CONFIG_DPP */
+
 
 void crypto_unload(void)
 {
diff --git a/src/crypto/sha256.c b/src/crypto/sha256.c
index 1ad1068..1e8a122 100644
--- a/src/crypto/sha256.c
+++ b/src/crypto/sha256.c
@@ -28,11 +28,11 @@
 {
 	unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
 	unsigned char tk[32];
-	const u8 *_addr[11];
-	size_t _len[11], i;
+	const u8 *_addr[HMAC_VECTOR_MAX_ELEM + 1];
+	size_t _len[HMAC_VECTOR_MAX_ELEM + 1], i;
 	int ret;
 
-	if (num_elem > 10) {
+	if (num_elem > HMAC_VECTOR_MAX_ELEM) {
 		/*
 		 * Fixed limit on the number of fragments to avoid having to
 		 * allocate memory (which could fail).
diff --git a/src/crypto/sha384.c b/src/crypto/sha384.c
index fd84b82..be07e9c 100644
--- a/src/crypto/sha384.c
+++ b/src/crypto/sha384.c
@@ -28,10 +28,10 @@
 {
 	unsigned char k_pad[128]; /* padding - key XORd with ipad/opad */
 	unsigned char tk[48];
-	const u8 *_addr[11];
-	size_t _len[11], i;
+	const u8 *_addr[HMAC_VECTOR_MAX_ELEM + 1];
+	size_t _len[HMAC_VECTOR_MAX_ELEM + 1], i;
 
-	if (num_elem > 10) {
+	if (num_elem > HMAC_VECTOR_MAX_ELEM) {
 		/*
 		 * Fixed limit on the number of fragments to avoid having to
 		 * allocate memory (which could fail).
diff --git a/src/crypto/sha512.c b/src/crypto/sha512.c
index f60a576..73b54c7 100644
--- a/src/crypto/sha512.c
+++ b/src/crypto/sha512.c
@@ -28,10 +28,10 @@
 {
 	unsigned char k_pad[128]; /* padding - key XORd with ipad/opad */
 	unsigned char tk[64];
-	const u8 *_addr[11];
-	size_t _len[11], i;
+	const u8 *_addr[HMAC_VECTOR_MAX_ELEM + 1];
+	size_t _len[HMAC_VECTOR_MAX_ELEM + 1], i;
 
-	if (num_elem > 10) {
+	if (num_elem > HMAC_VECTOR_MAX_ELEM) {
 		/*
 		 * Fixed limit on the number of fragments to avoid having to
 		 * allocate memory (which could fail).
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 82276c5..f43aefe 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -80,9 +80,15 @@
 };
 
 struct tls_config {
+#ifndef CONFIG_OPENSC_ENGINE_PATH
 	const char *opensc_engine_path;
+#endif /* CONFIG_OPENSC_ENGINE_PATH */
+#ifndef CONFIG_PKCS11_ENGINE_PATH
 	const char *pkcs11_engine_path;
+#endif /* CONFIG_PKCS11_ENGINE_PATH */
+#ifndef CONFIG_PKCS11_MODULE_PATH
 	const char *pkcs11_module_path;
+#endif /* CONFIG_PKCS11_MODULE_PATH */
 	int fips_mode;
 	int cert_in_cb;
 	const char *openssl_ciphers;
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index b378356..103c333 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -1029,6 +1029,26 @@
 	SSL_CTX *ssl;
 	struct tls_context *context;
 	const char *ciphers;
+#ifndef OPENSSL_NO_ENGINE
+#ifdef CONFIG_OPENSC_ENGINE_PATH
+	char const * const opensc_engine_path = CONFIG_OPENSC_ENGINE_PATH;
+#else /* CONFIG_OPENSC_ENGINE_PATH */
+	char const * const opensc_engine_path =
+		conf ? conf->opensc_engine_path : NULL;
+#endif /* CONFIG_OPENSC_ENGINE_PATH */
+#ifdef CONFIG_PKCS11_ENGINE_PATH
+	char const * const pkcs11_engine_path = CONFIG_PKCS11_ENGINE_PATH;
+#else /* CONFIG_PKCS11_ENGINE_PATH */
+	char const * const pkcs11_engine_path =
+		conf ? conf->pkcs11_engine_path : NULL;
+#endif /* CONFIG_PKCS11_ENGINE_PATH */
+#ifdef CONFIG_PKCS11_MODULE_PATH
+	char const * const pkcs11_module_path = CONFIG_PKCS11_MODULE_PATH;
+#else /* CONFIG_PKCS11_MODULE_PATH */
+	char const * const pkcs11_module_path =
+		conf ? conf->pkcs11_module_path : NULL;
+#endif /* CONFIG_PKCS11_MODULE_PATH */
+#endif /* OPENSSL_NO_ENGINE */
 
 	if (tls_openssl_ref_count == 0) {
 		void openssl_load_legacy_provider(void);
@@ -1171,12 +1191,10 @@
 	wpa_printf(MSG_DEBUG, "ENGINE: Loading builtin engines");
 	ENGINE_load_builtin_engines();
 
-	if (conf &&
-	    (conf->opensc_engine_path || conf->pkcs11_engine_path ||
-	     conf->pkcs11_module_path)) {
-		if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) ||
-		    tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path,
-						   conf->pkcs11_module_path)) {
+	if (opensc_engine_path || pkcs11_engine_path || pkcs11_module_path) {
+		if (tls_engine_load_dynamic_opensc(opensc_engine_path) ||
+		    tls_engine_load_dynamic_pkcs11(pkcs11_engine_path,
+						   pkcs11_module_path)) {
 			tls_deinit(data);
 			return NULL;
 		}
diff --git a/src/crypto/tls_wolfssl.c b/src/crypto/tls_wolfssl.c
index b4f1bbe..0b2947d 100644
--- a/src/crypto/tls_wolfssl.c
+++ b/src/crypto/tls_wolfssl.c
@@ -284,6 +284,7 @@
 		ciphers = conf->openssl_ciphers;
 	else
 		ciphers = "ALL";
+	wpa_printf(MSG_DEBUG, "wolfSSL: cipher suites: %s", ciphers);
 	if (wolfSSL_CTX_set_cipher_list(ssl_ctx, ciphers) != 1) {
 		wpa_printf(MSG_ERROR,
 			   "wolfSSL: Failed to set cipher string '%s'",
@@ -1323,6 +1324,8 @@
 		return -1;
 	}
 
+	wpa_printf(MSG_DEBUG, "wolfSSL: cipher suites: %s",
+		   params->openssl_ciphers ? params->openssl_ciphers : "N/A");
 	if (params->openssl_ciphers &&
 	    wolfSSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) {
 		wpa_printf(MSG_INFO,
@@ -1553,6 +1556,8 @@
 		return -1;
 	}
 
+	wpa_printf(MSG_DEBUG, "wolfSSL: cipher suites: %s",
+		   params->openssl_ciphers ? params->openssl_ciphers : "N/A");
 	if (params->openssl_ciphers &&
 	    wolfSSL_CTX_set_cipher_list(tls_ctx,
 					params->openssl_ciphers) != 1) {
@@ -1665,20 +1670,31 @@
 		wpa_printf(MSG_DEBUG, "SSL: wolfSSL_connect: %d", res);
 	}
 
-	if (res != 1) {
+	if (res != WOLFSSL_SUCCESS) {
 		int err = wolfSSL_get_error(conn->ssl, res);
 
-		if (err == SSL_ERROR_WANT_READ) {
+		if (err == WOLFSSL_ERROR_NONE) {
 			wpa_printf(MSG_DEBUG,
-				   "SSL: wolfSSL_connect - want more data");
-		} else if (err == SSL_ERROR_WANT_WRITE) {
+				   "SSL: %s - WOLFSSL_ERROR_NONE (%d)",
+				   server ? "wolfSSL_accept" :
+				   "wolfSSL_connect", res);
+		} else if (err == WOLFSSL_ERROR_WANT_READ) {
 			wpa_printf(MSG_DEBUG,
-				   "SSL: wolfSSL_connect - want to write");
+				   "SSL: %s - want more data",
+				   server ? "wolfSSL_accept" :
+				   "wolfSSL_connect");
+		} else if (err == WOLFSSL_ERROR_WANT_WRITE) {
+			wpa_printf(MSG_DEBUG,
+				   "SSL: %s - want to write",
+				   server ? "wolfSSL_accept" :
+				   "wolfSSL_connect");
 		} else {
 			char msg[80];
 
 			wpa_printf(MSG_DEBUG,
-				   "SSL: wolfSSL_connect - failed %s",
+				   "SSL: %s - failed %s",
+				   server ? "wolfSSL_accept" :
+				   "wolfSSL_connect",
 				   wolfSSL_ERR_error_string(err, msg));
 			conn->failed++;
 		}