Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/README
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/README	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/README	(revision 372)
@@ -1,13 +1,42 @@
+*** Description ***
+
+The wolfSSL embedded SSL library (formerly CyaSSL) is a lightweight SSL/TLS
+library written in ANSI C and targeted for embedded, RTOS, and
+resource-constrained environments - primarily because of its small size, speed,
+and feature set.  It is commonly used in standard operating environments as well
+because of its royalty-free pricing and excellent cross platform support.
+wolfSSL supports industry standards up to the current TLS 1.3 and DTLS 1.3
+levels, is up to 20 times smaller than OpenSSL, and offers progressive ciphers
+such as ChaCha20, Curve25519, NTRU, and Blake2b. User benchmarking and feedback
+reports dramatically better performance when using wolfSSL over OpenSSL.
+
+wolfSSL is powered by the wolfCrypt library. A version of the wolfCrypt
+cryptography library has been FIPS 140-2 validated (Certificate #2425). For
+additional information, visit the wolfCrypt FIPS FAQ
+(https://www.wolfssl.com/license/fips/) or contact fips@wolfssl.com
+
+*** Why choose wolfSSL? ***
+
+There are many reasons to choose wolfSSL as your embedded SSL solution. Some of
+the top reasons include size (typical footprint sizes range from 20-100 kB),
+support for the newest standards (SSL 3.0, TLS 1.0, TLS 1.1, TLS 1.2, TLS 1.3,
+DTLS 1.0, and DTLS 1.2), current and progressive cipher support (including
+stream ciphers), multi-platform, royalty free, and an OpenSSL compatibility API
+to ease porting into existing applications which have previously used the
+OpenSSL package. For a complete feature list, see chapter 4 of the wolfSSL
+manual. (https://www.wolfssl.com/docs/wolfssl-manual/ch4/)
+
 *** Notes, Please read ***
 
 Note 1)
-wolfSSL as of 3.6.6 no longer enables SSLv3 by default.  wolfSSL also no
-longer supports static key cipher suites with PSK, RSA, or ECDH.  This means
-if you plan to use TLS cipher suites you must enable DH (DH is on by default),
-or enable ECC (ECC is on by default on 64bit systems), or you must enable static
-key cipher suites with
+wolfSSL as of 3.6.6 no longer enables SSLv3 by default.  wolfSSL also no longer
+supports static key cipher suites with PSK, RSA, or ECDH. This means if you
+plan to use TLS cipher suites you must enable DH (DH is on by default), or
+enable ECC (ECC is on by default), or you must enable static key cipher suites
+with
+
     WOLFSSL_STATIC_DH
     WOLFSSL_STATIC_RSA
-    or
+      or
     WOLFSSL_STATIC_PSK
 
@@ -17,1703 +46,82 @@
 used in order to build with NTRU suites.
 
-When compiling ssl.c, wolfSSL will now issue a compiler error if no cipher suites
-are available.  You can remove this error by defining WOLFSSL_ALLOW_NO_SUITES
-in the event that you desire that, i.e., you're not using TLS cipher suites.
+When compiling ssl.c, wolfSSL will now issue a compiler error if no cipher
+suites are available. You can remove this error by defining
+WOLFSSL_ALLOW_NO_SUITES in the event that you desire that, i.e., you're not
+using TLS cipher suites.
 
 Note 2)
 wolfSSL takes a different approach to certificate verification than OpenSSL
-does.  The default policy for the client is to verify the server, this means
+does. The default policy for the client is to verify the server, this means
 that if you don't load CAs to verify the server you'll get a connect error,
 no signer error to confirm failure (-188).
+
 If you want to mimic OpenSSL behavior of having SSL_connect succeed even if
 verifying the server fails and reducing security you can do this by calling:
 
-wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0);
+    wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0);
 
-before calling wolfSSL_new();  Though it's not recommended.
+before calling wolfSSL_new();. Though it's not recommended.
+
+Note 3)
+The enum values SHA, SHA256, SHA384, SHA512 are no longer available when
+wolfSSL is built with --enable-opensslextra (OPENSSL_EXTRA) or with the macro
+NO_OLD_SHA_NAMES. These names get mapped to the OpenSSL API for a single call
+hash function. Instead the name WC_SHA, WC_SHA256, WC_SHA384 and WC_SHA512
+should be used for the enum name.
 
 *** end Notes ***
 
 
-********* wolfSSL (Formerly CyaSSL) Release 3.12.2 (10/23/2017)
+********* wolfSSL Release 3.15.7 (12/26/2018)
 
-Release 3.12.2 of wolfSSL has bug fixes and new features including:
+Release 3.15.7 of wolfSSL embedded TLS has bug fixes and new features including:
 
-This release includes many performance improvements with Intel ASM (AVX/AVX2) and AES-NI. New single precision math option to speedup RSA, DH and ECC. Embedded hardware support has been expanded for STM32, PIC32MZ and ATECC508A. AES now supports XTS mode for disk encryption. Certificate improvements for setting serial number, key usage and extended key usage. Refactor of SSL_ and hash types to allow openssl coexistence. Improvements for TLS 1.3. Fixes for OCSP stapling to allow disable and WOLFSSL specific user context for callbacks. Fixes for openssl and MySQL compatibility. Updated Micrium port. Fixes for asynchronous modes.
-
-- Added TLS extension for Supported Point Formats (ec_point_formats)
-- Fix to not send OCSP stapling extensions in client_hello when not enabled
-- Added new API's for disabling OCSP stapling
-- Add check for SIZEOF_LONG with sun and LP64
-- Fixes for various TLS 1.3 disable options (RSA, ECC and ED/Curve 25519).
-- Fix to disallow upgrading to TLS v1.3
-- Fixes for wolfSSL_EVP_CipherFinal() when message size is a round multiple of a block size.
-- Add HMAC benchmark and expanded AES key size benchmarks
-- Added simple GCC ARM Makefile example
-- Add tests for 3072-bit RSA and DH.
-- Fixed DRAFT_18 define and fixed downgrading with TLS v1.3
-- Fixes to allow custom serial number during certificate generation
-- Add method to get WOLFSSL_CTX certificate manager
-- Improvement to `wolfSSL_SetOCSP_Cb` to allow context per WOLFSSL object
-- Alternate certificate chain support `WOLFSSL_ALT_CERT_CHAINS`. Enables checking cert against multiple CA's. 
-- Added new `--disable-oldnames` option to allow for using openssl along-side wolfssl headers (without OPENSSL_EXTRA).
-- Refactor SSL_ and hashing types to use wolf specific prefix (WOLFSSL and WC_) to allow openssl coexistence.
-- Fixes for HAVE_INTEL_MULX
-- Cleanup include paths for MySQL cmake build
-- Added configure option for building library for wolfSSH (--enable-wolfssh)
-- Openssl compatibility layer improvements
-- Expanded API unit tests
-- Fixes for STM32 crypto hardware acceleration
-- Added AES XTS mode (--enable-xts)
-- Added ASN Extended Key Usage Support (see wc_SetExtKeyUsage).
-- Math updates and added TFM_MIPS speedup.
-- Fix for creation of the KeyUsage BitString
-- Fix for 8k keys with MySQL compatibility
-- Fixes for ATECC508A.
-- Fixes for PIC32MZ hashing.
-- Fixes and improvements to asynchronous modes for Intel QuickAssist and Cavium Nitrox V.
-- Update HASH_DRBG Reseed mechanism and add test case
-- Rename the file io.h/io.c to wolfio.h/wolfio.c
-- Cleanup the wolfIO_Send function.
-- OpenSSL Compatibility Additions and Fixes
-- Improvements to Visual Studio DLL project/solution.
-- Added function to generate public ECC key from private key
-- Added async blocking support for sniffer tool.
-- Added wolfCrypt hash tests for empty string and large data.
-- Added ability to use of wolf implementation of `strtok` using `USE_WOLF_STRTOK`.
-- Updated Micrium uC/OS-III Port
-- Updated root certs for OCSP scripts
-- New Single Precision math option for RSA, DH and ECC (off by default). See `--enable-sp`.
-- Speedups for AES GCM with AESNI (--enable-aesni)
-- Speedups for SHA2, ChaCha20/Poly1035 using AVX/AVX2
-
-
-********* wolfSSL (Formerly CyaSSL) Release 3.12.0 (8/04/2017)
-
-Release 3.12.0 of wolfSSL has bug fixes and new features including:
-
-- TLS 1.3 with Nginx! TLS 1.3 with ARMv8! TLS 1.3 with Async Crypto! (--enable-tls13)
-- TLS 1.3 0RTT feature added
-- Added port for using Intel SGX with Linux
-- Update and fix PIC32MZ port
-- Additional unit testing for MD5, SHA, SHA224, SHA256, SHA384, SHA512, RipeMd, HMAC, 3DES, IDEA, ChaCha20, ChaCha20Poly1305 AEAD, Camellia, Rabbit, ARC4, AES, RSA, Hc128
-- AVX and AVX2 assembly for improved ChaCha20 performance
-- Intel QAT fixes for when using --disable-fastmath
-- Update how DTLS handles decryption and MAC failures
-- Update DTLS session export version number for --enable-sessionexport feature
-- Add additional input argument sanity checks to ARMv8 assembly port
-- Fix for making PKCS12 dynamic types match
-- Fixes for potential memory leaks when using --enable-fast-rsa
-- Fix for when using custom ECC curves and add BRAINPOOLP256R1 test
-- Update TI-RTOS port for dependency on new wolfSSL source files
-- DTLS multicast feature added, --enable-mcast
-- Fix for Async crypto with GCC 7.1 and HMAC when not using Intel QuickAssist
-- Improvements and enhancements to Intel QuickAssist support
-- Added Xilinx port
-- Added SHA3 Keccak feature, --enable-sha3
-- Expand wolfSSL Python wrapper to now include a client side implementation
-- Adjust example servers to not treat a peer closed error as a hard error
-- Added more sanity checks to fp_read_unsigned_bin function
-- Add SHA224 and AES key wrap to ARMv8 port
-- Update MQX classics and mmCAU ports
-- Fix for potential buffer over read with wolfSSL_CertPemToDer
-- Add PKCS7/CMS decode support for KARI with IssuerAndSerialNumber
-- Fix ThreadX/NetX warning
-- Fixes for OCSP and CRL non blocking sockets and for incomplete cert chain with OCSP
-- Added RSA PSS sign and verify
-- Fix for STM32F4 AES-GCM
-- Added enable all feature (--enable-all)
-- Added trackmemory feature (--enable-trackmemory)
-- Fixes for AES key wrap and PKCS7 on Windows VS
-- Added benchmark block size argument
-- Support use of staticmemory with PKCS7
-- Fix for Blake2b build with GCC 5.4
-- Fixes for compiling wolfSSL with GCC version 7, most dealing with switch statement fall through warnings.
-- Added warning when compiling without hardened math operations
-
-
-Note:
-There is a known issue with using ChaCha20 AVX assembly on versions of GCC earlier than 5.2. This is encountered with using the wolfSSL enable options --enable-intelasm and --enable-chacha. To avoid this issue ChaCha20 can be enabled with --enable-chacha=noasm.
-If using --enable-intelasm and also using --enable-sha224 or --enable-sha256 there is a known issue with trying to use -fsanitize=address.
-
-This release of wolfSSL fixes 1 low level security vulnerability.
-
-Low level fix for a potential DoS attack on a wolfSSL client. Previously a client would accept many warning alert messages without a limit. This fix puts a limit to the number of warning alert messages received and if this limit is reached a fatal error ALERT_COUNT_E is returned. The max number of warning alerts by default is set to 5 and can be adjusted with the macro WOLFSSL_ALERT_COUNT_MAX. Thanks for the report from Tarun Yadav and Koustav Sadhukhan from Defence Research and Development Organization, INDIA.
-
-
-See INSTALL file for build instructions.
-More info can be found on-line at http://wolfssl.com/wolfSSL/Docs.html
-
-
-********* wolfSSL (Formerly CyaSSL) Release 3.11.1 (5/11/2017)
-
-Release 3.11.1 of wolfSSL is a TLS 1.3 BETA release, which includes:
-
-- TLS 1.3 client and server support for TLS 1.3 with Draft 18 support
-
-This is strictly a BETA release, and designed for testing and user feedback.
-Please send any comments, testing results, or feedback to wolfSSL at
-support@wolfssl.com.
-
-See INSTALL file for build instructions.
-More info can be found on-line at http://wolfssl.com/wolfSSL/Docs.html
-
-
-********* wolfSSL (Formerly CyaSSL) Release 3.11.0 (5/04/2017)
-
-Release 3.11.0 of wolfSSL has bug fixes and new features including:
-
-- Code updates for warnings reported by Coverity scans
-- Testing and warning fixes for FreeBSD on PowerPC
-- Updates and refactoring done to ASN1 parsing functions
-- Change max PSK identity buffer to account for an identity length of 128 characters
-- Update Arduino script to handle recent files and additions
-- Added support for PKCS#7 Signed Data with ECDSA
-- Fix for interoperability with ChaCha20-Poly1305 suites using older draft versions
-- DTLS update to allow multiple handshake messages in one DTLS record. Thanks to Eric Samsel over at Welch Allyn for reporting this bug.
-- Intel QuickAssist asynchronous support (PR #715 - https://www.wolfssl.com/wolfSSL/Blog/Entries/2017/1/18_wolfSSL_Asynchronous_Intel_QuickAssist_Support.html)
-- Added support for HAproxy load balancer
-- Added option to allow SHA1 with TLS 1.2 for IIS compatibility (WOLFSSL_ALLOW_TLS_SHA1)
-- Added Curve25519 51-bit Implementation, increasing performance on systems that have 128 bit types
-- Fix to not send session ID on server side if session cache is off unless we're echoing
-session ID as part of session tickets
-- Fixes for ensuring all default ciphers are setup correctly (see PR #830)
-- Added NXP Hexiwear example in `IDE/HEXIWEAR`.
-- Added wolfSSL_write_dup() to create write only WOLFSSL object for concurrent access
-- Fixes for TLS elliptic curve selection on private key import.
-- Fixes for RNG with Intel rdrand and rdseed speedups.
-- Improved performance with Intel rdrand to use full 64-bit output
-- Added new --enable-intelrand option to indicate use of RDRAND preference for RNG source
-- Removed RNG ARC4 support
-- Added ECC helpers to get size and id from curve name.
-- Added ECC Cofactor DH (ECC-CDH) support
-- Added ECC private key only import / export functions.
-- Added PKCS8 create function
-- Improvements to TLS layer CTX handling for switching keys / certs.
-- Added check for duplicate certificate policy OID in certificates.
-- Normal math speed-up to not allocate on mp_int and defer until mp_grow
-- Reduce heap usage with fast math when not using ALT_ECC_SIZE
-- Fixes for building CRL with Windows
-- Added support for inline CRL lookup when HAVE_CRL_IO is defined
-- Added port for tenAsys INtime RTOS
-- Improvements to uTKernel port (WOLFSSL_uTKERNEL2)
-- Updated WPA Supplicant support
-- Added support for Nginx
-- Update stunnel port for version 5.40
-- Fixes for STM32 hardware crypto acceleration
-- Extended test code coverage in bundled test.c
-- Added a sanity check for minimum authentication tag size with AES-GCM. Thanks to Yueh-Hsun Lin and Peng Li at KNOX Security at Samsung Research America for suggesting this.
-- Added a sanity check that subject key identifier is marked as non-critical and a check that no policy OIDS appear more than once in the cert policies extension. Thanks to the report from Professor Zhenhua Duan, Professor Cong Tian, and Ph.D candidate Chu Chen from Institute of Computing Theory and Technology (ICTT) of Xidian University, China. Profs. Zhenhua Duan and Cong Tian are supervisors of Ph.D candidate Chu Chen.
-
-
-This release of wolfSSL fixes 5 low and 1 medium level security vulnerability.
-
-3 Low level fixes reported by Yueh-Hsun Lin and Peng Li from KNOX Security, Samsung Research America.
-- Fix for out of bounds memory access in wc_DhParamsLoad() when GetLength() returns a zero. Before this fix there is a case where wolfSSL would read out of bounds memory in the function wc_DhParamsLoad.
-- Fix for DH key accepted by wc_DhAgree when the key was malformed.
-- Fix for a double free case when adding CA cert into X509_store.
-
-Low level fix for memory management with static memory feature enabled. By default static memory is disabled. Thanks to GitHub user hajjihraf for reporting this.
-
-Low level fix for out of bounds write in the function wolfSSL_X509_NAME_get_text_by_NID. This function is not used by TLS or crypto operations but could result in a buffer out of bounds write by one if called explicitly in an application. Discovered by Aleksandar Nikolic of Cisco Talos. http://talosintelligence.com/vulnerability-reports/
-
-Medium level fix for check on certificate signature. There is a case in release versions 3.9.10, 3.10.0 and 3.10.2 where a corrupted signature on a peer certificate would not be properly flagged. Thanks to Wens Lo, James Tsai, Kenny Chang, and Oscar Yang at Castles Technology.
-
-
-See INSTALL file for build instructions.
-More info can be found on-line at http://wolfssl.com/wolfSSL/Docs.html
-
-
-********* wolfSSL (Formerly CyaSSL) Release 3.10.2 (2/10/2017)
-
-Release 3.10.2 of wolfSSL has bug fixes and new features including:
-
-- Poly1305 Windows macros fix. Thanks to GitHub user Jay Satiro
-- Compatibility layer expanded with multiple functions added
-- Improve fp_copy performance with ALT_ECC_SIZE
-- OCSP updates and improvements
-- Fixes for IAR EWARM 8 compiler warnings
-- Reduce stack usage with ECC_CACHE_CURVE disabled
-- Added ECC export raw for public and private key
-- Fix for NO_ASN_TIME build
-- Supported curves extensions now populated by default
-- Add DTLS build without big integer math
-- Fix for static memory feature with wc_ecc_verify_hash_ex and not SHAMIR
-- Added PSK interoperability testing to script bundled with wolfSSL
-- Fix for Python wrapper random number generation. Compiler optimizations with Python could place the random number in same buffer location each time. Thanks to GitHub user Erik Bray (embray)
-- Fix for tests on unaligned memory with static memory feature
-- Add macro WOLFSSL_NO_OCSP_OPTIONAL_CERTS to skip optional OCSP certificates
-- Sanity checks on NULL arguments added to wolfSSL_set_fd and wolfSSL_DTLS_SetCookieSecret
-- mp_jacobi stack use reduced, thanks to Szabi Tolnai for providing a solution to reduce stack usage
-
-
-This release of wolfSSL fixes 2 low and 1 medium level security vulnerability.
-
-Low level fix of buffer overflow for when loading in a malformed temporary DH file. Thanks to Yueh-Hsun Lin and Peng Li from KNOX Security, Samsung Research America for the report.
-
-Medium level fix for processing of OCSP response. If using OCSP without hard faults enforced and no alternate revocation checks like OCSP stapling then it is recommended to update.
-
-Low level fix for potential cache attack on RSA operations. If using wolfSSL RSA on a server that other users can have access to monitor the cache, then it is recommended to update wolfSSL. Thanks to Andreas Zankl, Johann Heyszl and Georg Sigl at Fraunhofer AISEC for the initial report.
-
-See INSTALL file for build instructions.
-More info can be found on-line at http://wolfssl.com/wolfSSL/Docs.html
-
-********* wolfSSL (Formerly CyaSSL) Release 3.10.0 (12/21/2016)
-
-Release 3.10.0 of wolfSSL has bug fixes and new features including:
-
-- Added support for SHA224
-- Added scrypt feature
-- Build for Intel SGX use, added in directory IDE/WIN-SGX
-- Fix for ChaCha20-Poly1305 ECDSA certificate type request
-- Enhance PKCS#7 with ECC enveloped data and AES key wrap support
-- Added support for RIOT OS
-- Add support for parsing PKCS#12 files
-- ECC performance increased with custom curves
-- ARMv8 expanded to AArch32 and performance increased
-- Added ANSI-X9.63-KDF support
-- Port to STM32 F2/F4 CubeMX
-- Port to Atmel ATECC508A board
-- Removed fPIE by default when wolfSSL library is compiled
-- Update to Python wrapper, dropping DES and adding wc_RSASetRNG
-- Added support for NXP K82 hardware acceleration
-- Added SCR client and server verify check
-- Added a disable rng option with autoconf
-- Added more tests vectors to test.c with AES-CTR
-- Updated DTLS session export version number
-- Updated DTLS for 64 bit sequence numbers
-- Fix for memory management with TI and WOLFSSL_SMALL_STACK
-- Hardening RSA CRT to be constant time
-- Fix uninitialized warning with IAR compiler
-- Fix for C# wrapper example IO hang on unexpected connection termination
-
-
-This release of wolfSSL fixes a low level security vulnerability. The vulnerability reported was a potential cache attack on RSA operations. If using wolfSSL RSA on a server that other users can have access to monitor the cache, then it is recommended to update wolfSSL. Thanks to Andreas Zankl, Johann Heyszl and Georg Sigl at Fraunhofer AISEC for the report. More information will be available on our site:
-
-https://wolfssl.com/wolfSSL/security/vulnerabilities.php
-
-See INSTALL file for build instructions.
-More info can be found on-line at http://wolfssl.com/wolfSSL/Docs.html
-
-********* wolfSSL (Formerly CyaSSL) Release 3.9.10 (9/23/2016)
-
-Release 3.9.10 of wolfSSL has bug fixes and new features including:
-
-- Default configure option changes:
-  1. DES3 disabled by default
-  2. ECC Supported Curves Extension enabled by default
-  3. New option Extended Master Secret enabled by default
-- Added checking CA certificate path length, and new test certs
-- Fix to DSA pre padding and sanity check on R/S values
-- Added CTX level RNG for single-threaded builds
-- Intel RDSEED enhancements
-- ARMv8 hardware acceleration support for AES-CBC/CTR/GCM, SHA-256
-- Arduino support updates
-- Added the Extended Master Secret TLS extension
-  1. Enabled by default in configure options, API to disable
-  2. Added support for Extended Master Secret to sniffer
-- OCSP fix with issuer key hash, lookup refactor
-- Added support for Frosted OS
-- Added support for DTLS over SCTP
-- Added support for static memory with wolfCrypt
-- Fix to ECC Custom Curve support
-- Support for asynchronous wolfCrypt RSA and TLS client
-- Added distribution build configure option
-- Update the test certificates
-
-This release of wolfSSL fixes medium level security vulnerabilities.  Fixes for
-potential AES, RSA, and ECC side channel leaks is included that a local user
-monitoring the same CPU core cache could exploit.  VM users, hyper-threading
-users, and users where potential attackers have access to the CPU cache will
-need to update if they utilize AES, RSA private keys, or ECC private keys.
-Thanks to Gorka Irazoqui Apecechea and Xiaofei Guo from Intel Corporation for
-the report.  More information will be available on our site:
-
-    https://wolfssl.com/wolfSSL/security/vulnerabilities.php
-
-See INSTALL file for build instructions.
-More info can be found on-line at http://wolfssl.com/wolfSSL/Docs.html
-
-********* wolfSSL (Formerly CyaSSL) Release 3.9.8 (7/29/2016)
-
-Release 3.9.8 of wolfSSL has bug fixes and new features including:
-
-- Add support for custom ECC curves.
-- Add cipher suite ECDHE-ECDSA-AES128-CCM.
-- Add compkey enable option. This option is for compressed ECC keys.
-- Add in the option to use test.h without gettimeofday function using the macro
-  WOLFSSL_USER_CURRTIME.
-- Add RSA blinding for private key operations. Enable option of harden which is
-  on by default. This negates timing attacks.
-- Add ECC and TLS support for all SECP, Koblitz and Brainpool curves.
-- Add helper functions for static memory option to allow getting optimum buffer
-  sizes.
-- Update DTLS behavior on bad MAC. DTLS silently drops packets with bad MACs now.
-- Update fp_isprime function from libtom enchancement/cleanup repository.
-- Update sanity checks on inputs and return values for AES-CMAC.
-- Update wolfSSL for use with MYSQL v5.6.30.
-- Update LPCXpresso eclipse project to not include misc.c when not needed.
-- Fix retransmit of last DTLS flight with timeout notification. The last flight
-  is no longer retransmitted on timeout.
-- Fixes to some code in math sections for compressed ECC keys. This includes
-  edge cases for buffer size on allocation and adjustments for compressed curves
-  build. The code and full list can be found on github with pull request #456.
-- Fix function argument mismatch for build with secure renegotiation.
-- X.509 bug fixes for reading in malformed certificates, reported by researchers
-  at Columbia University
-- Fix GCC version 6 warning about hard tabs in poly1305.c. This was a warning
-  produced by GCC 6 trying to determine the intent of code.
-- Fixes for static memory option. Including avoid potential race conditions with
-  counters, decrement handshake counter correctly.
-- Fix anonymous cipher with Diffie Hellman on the server side. Was an issue of a
-  possible buffer corruption. For information and code see pull request #481.
-
-
-- One high level security fix that requires an update for use with static RSA
-  cipher suites was submitted. This fix was the addition of RSA blinding for
-  private RSA operations. We recommend servers who allow static RSA cipher
-  suites to also generate new private RSA keys. Static RSA cipher suites are
-  turned off by default.
-
-See INSTALL file for build instructions.
-More info can be found on-line at //http://wolfssl.com/wolfSSL/Docs.html
-
- ********* wolfSSL (Formerly CyaSSL) Release 3.9.6 (6/14/2016)
-
-Release 3.9.6 of wolfSSL has bug fixes and new features including:
-
-- Add staticmemory feature
-- Add public wc_GetTime API with base64encode feature
-- Add AES CMAC algorithm
-- Add DTLS sessionexport feature
-- Add python wolfCrypt wrapper
-- Add ECC encrypt/decrypt benchmarks
-- Add dynamic session tickets
-- Add eccshamir option
-- Add Whitewood netRandom support --with-wnr
-- Add embOS port
-- Add minimum key size checks for RSA and ECC
-- Add STARTTLS support to examples
-- Add uTasker port
-- Add asynchronous crypto and wolf event support
-- Add compile check for misc.c with inline
-- Add RNG benchmark
-- Add reduction to stack usage with hash-based RNG
-- Update STM32F2_CRYPTO port with additional algorithms supported
-- Update MDK5 projects
-- Update AES-NI
-- Fix for STM32 with STM32F2_HASH defined
-- Fix for building with MinGw
-- Fix ECC math bugs with ALT_ECC_SIZE and key sizes over 256 bit (1)
-- Fix certificate buffers github issue #422
-- Fix decrypt max size with RSA OAEP
-- Fix DTLS sanity check with DTLS timeout notification
-- Fix free of WOLFSSL_METHOD on failure to create CTX
-- Fix memory leak in failure case with wc_RsaFunction (2)
-
-- No high level security fixes that requires an update though we always
-recommend updating to the latest
-- (1) Code changes for ECC fix can be found at pull requests #411, #416, and #428
-- (2) Builds using RSA with using normal math and not RSA_LOW_MEM should update
-- Tag 3.9.6w is for a Windows example echoserver fix
-
-See INSTALL file for build instructions.
-More info can be found on-line at //http://wolfssl.com/wolfSSL/Docs.html
-
- ********* wolfSSL (Formerly CyaSSL) Release 3.9.0 (3/18/2016)
-
-Release 3.9.0 of wolfSSL has bug fixes and new features including:
-
-- Add new leantls configuration
-- Add RSA OAEP padding at wolfCrypt level
-- Add Arduino port and example client
-- Add fixed point DH operation
-- Add CUSTOM_RAND_GENRATE_SEED_OS and CUSTOM_RAND_GENERATE_BLOCK
-- Add ECDHE-PSK cipher suites
-- Add PSK ChaCha20-Poly1305 cipher suites
-- Add option for fail on no peer cert except PSK suites
-- Add port for Nordic nRF51
-- Add additional ECC NIST test vectors for 256, 384 and 521
-- Add more granular ECC, Ed25519/Curve25519 and AES configs
-- Update to ChaCha20-Poly1305
-- Update support for Freescale KSDK 1.3.0
-- Update DER buffer handling code, refactoring and reducing memory
-- Fix to AESNI 192 bit key expansion
-- Fix to C# wrapper character encoding
-- Fix sequence number issue with DTLS epoch 0 messages
-- Fix RNGA with K64 build
-- Fix ASN.1 X509 V3 certificate policy extension parsing
-- Fix potential free of uninitialized RSA key in asn.c
-- Fix potential underflow when using ECC build with FP_ECC
-- Fixes for warnings in Visual Studio 2015 build
-
-- No high level security fixes that requires an update though we always
-recommend updating to the latest
-- FP_ECC is off by default, users with it enabled should update for the zero
-sized hash fix
-
-See INSTALL file for build instructions.
-More info can be found on-line at //http://wolfssl.com/yaSSL/Docs.html
-
- ********* wolfSSL (Formerly CyaSSL) Release 3.8.0 (12/30/2015)
-
-Release 3.8.0 of wolfSSL has bug fixes and new features including:
-
-- Example client/server with VxWorks
-- AESNI use with AES-GCM
-- Stunnel compatibility enhancements
-- Single shot hash and signature/verify API added
-- Update cavium nitrox port
-- LPCXpresso IDE support added
-- C# wrapper to support wolfSSL use by a C# program
-- (BETA version)OCSP stapling added
-- Update OpenSSH compatibility
-- Improve DTLS handshake when retransmitting finished message
-- fix idea_mult() for 16 and 32bit systems
-- fix LowResTimer on Microchip ports
-
-- No high level security fixes that requires an update though we always
-recommend updating to the latest
-
-See INSTALL file for build instructions.
-More info can be found on-line at //http://wolfssl.com/yaSSL/Docs.html
-
- ********* wolfSSL (Formerly CyaSSL) Release 3.7.0 (10/26/2015)
-
-Release 3.7.0 of wolfSSL has bug fixes and new features including:
-
-- ALPN extension support added for HTTP2 connections with --enable-alpn
-- Change of example/client/client max fragment flag -L -> -F
-- Throughput benchmarking, added scripts/benchmark.test
-- Sniffer API ssl_FreeDecodeBuffer added
-- Addition of AES_GCM to Sniffer
-- Sniffer change to handle unlimited decrypt buffer size
-- New option for the sniffer where it will try to pick up decoding after a
-  sequence number acknowldgement fault. Also includes some additional stats.
-- JNI API setter and getter function for jobject added
-- User RSA crypto plugin abstraction. An example placed in wolfcrypt/user-crypto
-- fix to asn configuration bug
-- AES-GCM/CCM fixes.
-- Port for Rowley added
-- Rowley Crossworks bare metal examples added
-- MDK5-ARM project update
-- FreeRTOS support updates.
-- VXWorks support updates.
-- Added the IDEA cipher and support in wolfSSL.
-- Update wolfSSL website CA.
-- CFLAGS is usable when configuring source.
-
-- No high level security fixes that requires an update though we always
-recommend updating to the latest
-
-See INSTALL file for build instructions.
-More info can be found on-line at //http://wolfssl.com/yaSSL/Docs.html
-
- ********* wolfSSL (Formerly CyaSSL) Release 3.6.8 (09/17/2015)
-
-Release 3.6.8 of wolfSSL fixes two high severity vulnerabilities.  It also
-includes bug fixes and new features including:
-
-- Two High level security fixes, all users SHOULD update.
-  a) If using wolfSSL for DTLS on the server side of a publicly accessible
-     machine you MUST update.
-  b) If using wolfSSL for TLS on the server side with private RSA keys allowing
-     ephemeral key exchange without low memory optimizations you MUST update and
-     regenerate the private RSA keys.
-
-     Please see https://www.wolfssl.com/wolfSSL/Blog/Blog.html for more details
-
-- No filesystem build fixes for various configurations
-- Certificate generation now supports several extensions including KeyUsage,
-    SKID, AKID, and Certificate Policies
-- CRLs can be loaded from buffers as well as files now
-- SHA-512 Certificate Signing generation
-- Fixes for sniffer reassembly processing
-
-See INSTALL file for build instructions.
-More info can be found on-line at //http://wolfssl.com/yaSSL/Docs.html
-
- ********* wolfSSL (Formerly CyaSSL) Release 3.6.6 (08/20/2015)
-
-Release 3.6.6 of wolfSSL has bug fixes and new features including:
-
-- OpenSSH  compatibility with --enable-openssh
-- stunnel  compatibility with --enable-stunnel
-- lighttpd compatibility with --enable-lighty
-- SSLv3 is now disabled by default, can be enabled with --enable-sslv3
-- Ephemeral key cipher suites only are now supported by default
-    To enable static ECDH cipher suites define WOLFSSL_STATIC_DH
-    To enable static  RSA cipher suites define WOLFSSL_STATIC_RSA
-    To enable static  PSK cipher suites define WOLFSSL_STATIC_PSK
-- Added QSH (quantum-safe handshake) extension with --enable-ntru
-- SRP is now part of wolfCrypt, enable with --enabe-srp
-- Certificate handshake messages can now be sent fragmented if the record
-  size is smaller than the total message size, no user action required.
-- DTLS duplicate message fixes
-- Visual Studio project files now support DLL and static builds for 32/64bit.
-- Support for new Freescale I/O
-- FreeRTOS FIPS support
-
-- No high level security fixes that requires an update though we always
-  recommend updating to the latest
-
-See INSTALL file for build instructions.
-More information can be found on-line at //http://wolfssl.com/yaSSL/Docs.html
-
- **************** wolfSSL (Formerly CyaSSL) Release 3.6.0 (06/19/2015)
-
-Release 3.6.0 of wolfSSL has bug fixes and new features including:
-
-- Max Strength build that only allows TLSv1.2, AEAD ciphers, and PFS (Perfect
-   Forward Secrecy).  With --enable-maxstrength
-- Server side session ticket support, the example server and echoserver use the
-   example callback myTicketEncCb(), see wolfSSL_CTX_set_TicketEncCb()
-- FIPS version submitted for iOS.
-- TI Crypto Hardware Acceleration
-- DTLS fragmentation fixes
-- ECC key check validation with wc_ecc_check_key()
-- 32bit code options to reduce memory for Curve25519 and Ed25519
-- wolfSSL JNI build switch with --enable-jni
-- PicoTCP support improvements
-- DH min ephemeral key size enforcement with wolfSSL_CTX_SetMinDhKey_Sz()
-- KEEP_PEER_CERT and AltNames can now be used together
-- ChaCha20 big endian fix
-- SHA-512 signature algorithm support for key exchange and verify messages
-- ECC make key crash fix on RNG failure, ECC users must update.
-- Improvements to usage of time code.
-- Improvements to VS solution files.
-- GNU Binutils 2.24 (and late 2.23) ld has problems with some debug builds,
-  to fix an ld error add C_EXTRA_FLAGS="-fdebug-types-section -g1".
-
-- No high level security fixes that requires an update though we always
-  recommend updating to the latest (except note 14, ecc RNG failure)
-
-See INSTALL file for build instructions.
-More info can be found on-line at //http://wolfssl.com/yaSSL/Docs.html
-
-
- *****************wolfSSL (Formerly CyaSSL) Release 3.4.6 (03/30/2015)
-
-Release 3.4.6 of wolfSSL has bug fixes and new features including:
-
-- Intel Assembly Speedups using instructions rdrand, rdseed, aesni, avx1/2,
-  rorx, mulx, adox, adcx .  They can be enabled with --enable-intelasm.
-  These speedup the use of RNG, SHA2, and public key algorithms.
-- Ed25519 support at the crypto level. Turn on with --enable-ed25519.  Examples
-  in wolcrypt/test/test.c ed25519_test().
-- Post Handshake Memory reductions.  wolfSSL can now hold less than 1,000 bytes
-  of memory per secure connection including cipher state.
-- wolfSSL API and wolfCrypt API fixes, you can still include the cyassl and
-  ctaocrypt headers which will enable the compatibility APIs for the
-  foreseeable future
-- INSTALL file to help direct users to build instructions for their environment
-- For ECC users with the normal math library a fix that prevents a crash when
-  verify signature fails.  Users of 3.4.0 with ECC and the normal math library
-  must update
-- RC4 is now disabled by default in autoconf mode
-- AES-GCM and ChaCha20/Poly1305 are now enabled by default to make AEAD ciphers
-  available without a switch
-- External ChaCha-Poly AEAD API, thanks to Andrew Burks for the contribution
-- DHE-PSK cipher suites can now be built without ASN or Cert support
-- Fix some NO MD5 build issues with optional features
-- Freescale CodeWarrior project updates
-- ECC curves can be individually turned on/off at build time.
-- Sniffer handles Cert Status message and other minor fixes
-- SetMinVersion() at the wolfSSL Context level instead of just SSL session level
-  to allow minimum protocol version allowed at runtime
-- RNG failure resource cleanup fix
-
-- No high level security fixes that requires an update though we always
-  recommend updating to the latest (except note 6 use case of ecc/normal math)
-
-See INSTALL file for build instructions.
-More info can be found on-line at //http://wolfssl.com/yaSSL/Docs.html
-
-
- *****************wolfSSL (Formerly CyaSSL) Release 3.4.0 (02/23/2015)
-
-Release 3.4.0 wolfSSL has bug fixes and new features including:
-
-- wolfSSL API and wolfCrypt API, you can still include the cyassl and ctaocrypt
-  headers which will enable the compatibility APIs for the foreseeable future
-- Example use of the wolfCrypt API can be found in wolfcrypt/test/test.c
-- Example use of the wolfSSL API can be found in examples/client/client.c
-- Curve25519 now supported at the wolfCrypt level, wolfSSL layer coming soon
-- Improvements in the build configuration under AIX
-- Microchip Pic32 MZ updates
-- TIRTOS updates
-- PowerPC updates
-- Xcode project update
-- Bidirectional shutdown examples in client/server with -w (wait for full
-  shutdown) option
-- Cycle counts on benchmarks for x86_64, more coming soon
-- ALT_ECC_SIZE for reducing ecc heap use with fastmath when also using large RSA
-  keys
-- Various compile warnings
-- Scan-build warning fixes
-- Changed a memcpy to memmove in the sniffer (if using sniffer please update)
-- No high level security fixes that requires an update though we always
-  recommend updating to the latest
-
-
- ***********CyaSSL Release 3.3.0 (12/05/2014)
-
-- Countermeasuers for Handshake message duplicates, CHANGE CIPHER without
-  FINISHED, and fast forward attempts.  Thanks to Karthikeyan Bhargavan from
-  the Prosecco team at INRIA Paris-Rocquencourt for the report.
-- FIPS version submitted
-- Removes SSLv2 Client Hello processing, can be enabled with OLD_HELLO_ALLOWED
-- User can set minimum downgrade version with CyaSSL_SetMinVersion()
-- Small stack improvements at TLS/SSL layer
-- TLS Master Secret generation and Key Expansion are now exposed
-- Adds client side Secure Renegotiation, * not recommended *
-- Client side session ticket support, not fully tested with Secure Renegotiation
-- Allows up to 4096bit DHE at TLS Key Exchange layer
-- Handles non standard SessionID sizes in Hello Messages
-- PicoTCP Support
-- Sniffer now supports SNI Virtual Hosts
-- Sniffer now handles non HTTPS protocols using STARTTLS
-- Sniffer can now parse records with multiple messages
-- TI-RTOS updates
-- Fix for ColdFire optimized fp_digit read only in explicit 32bit case
-- ADH Cipher Suite ADH-AES128-SHA for EAP-FAST
-
-The CyaSSL manual is available at:
-http://www.wolfssl.com/documentation/CyaSSL-Manual.pdf.  For build instructions
-and comments about the new features please check the manual.
-
-
-***********CyaSSL Release 3.2.0 (09/10/2014)
-
-Release 3.2.0 CyaSSL has bug fixes and new features including:
-
-- ChaCha20 and Poly1305 crypto and suites
-- Small stack improvements for OCSP, CRL, TLS, DTLS
-- NTRU Encrypt and Decrypt benchmarks
-- Updated Visual Studio project files
-- Updated Keil MDK5 project files
-- Fix for DTLS sequence numbers with GCM/CCM
-- Updated HashDRBG with more secure struct declaration
-- TI-RTOS support and example Code Composer Studio project files
-- Ability to get enabled cipher suites, CyaSSL_get_ciphers()
-- AES-GCM/CCM/Direct support for Freescale mmCAU and CAU
-- Sniffer improvement checking for decrypt key setup
-- Support for raw ECC key import
-- Ability to convert ecc_key to DER, EccKeyToDer()
-- Security fix for RSA Padding check vulnerability reported by Intel Security
-  Advanced Threat Research team
-
-The CyaSSL manual is available at:
-http://www.wolfssl.com/documentation/CyaSSL-Manual.pdf.  For build instructions
-and comments about the new features please check the manual.
-
-
-************ CyaSSL Release 3.1.0 (07/14/2014)
-
-Release 3.1.0 CyaSSL has bug fixes and new features including:
-
-- Fix for older versions of icc without 128-bit type
-- Intel ASM syntax for AES-NI
-- Updated NTRU support, keygen benchmark
-- FIPS check for minimum required HMAC key length
-- Small stack (--enable-smallstack) improvements for PKCS#7, ASN
-- TLS extension support for DTLS
-- Default I/O callbacks external to user
-- Updated example client with bad clock test
-- Ability to set optional ECC context info
-- Ability to enable/disable DH separate from opensslextra
-- Additional test key/cert buffers for CA and server
-- Updated example certificates
-
-The CyaSSL manual is available at:
-http://www.wolfssl.com/documentation/CyaSSL-Manual.pdf.  For build instructions
-and comments about the new features please check the manual.
-
-
-************ CyaSSL Release 3.0.2 (05/30/2014)
-
-Release 3.0.2 CyaSSL has bug fixes and new features including:
-
-- Added the following cipher suites:
-  * TLS_PSK_WITH_AES_128_GCM_SHA256
-  * TLS_PSK_WITH_AES_256_GCM_SHA384
-  * TLS_PSK_WITH_AES_256_CBC_SHA384
-  * TLS_PSK_WITH_NULL_SHA384
-  * TLS_DHE_PSK_WITH_AES_128_GCM_SHA256
-  * TLS_DHE_PSK_WITH_AES_256_GCM_SHA384
-  * TLS_DHE_PSK_WITH_AES_128_CBC_SHA256
-  * TLS_DHE_PSK_WITH_AES_256_CBC_SHA384
-  * TLS_DHE_PSK_WITH_NULL_SHA256
-  * TLS_DHE_PSK_WITH_NULL_SHA384
-  * TLS_DHE_PSK_WITH_AES_128_CCM
-  * TLS_DHE_PSK_WITH_AES_256_CCM
-- Added AES-NI support for Microsoft Visual Studio builds.
-- Changed small stack build to be disabled by default.
-- Updated the Hash DRBG and provided a configure option to enable.
-
-The CyaSSL manual is available at:
-http://www.wolfssl.com/documentation/CyaSSL-Manual.pdf.  For build instructions
-and comments about the new features please check the manual.
-
-
-************ CyaSSL Release 3.0.0 (04/29/2014)
-
-Release 3.0.0 CyaSSL has bug fixes and new features including:
-
-- FIPS release candidate
-- X.509 improvements that address items reported by Suman Jana with security
-  researchers at UT Austin and UC Davis
-- Small stack size improvements, --enable-smallstack. Offloads large local
-  variables to the heap. (Note this is not complete.)
-- Updated AES-CCM-8 cipher suites to use approved suite numbers.
-
-The CyaSSL manual is available at:
-http://www.wolfssl.com/documentation/CyaSSL-Manual.pdf.  For build instructions
-and comments about the new features please check the manual.
-
-
-************ CyaSSL Release 2.9.4 (04/09/2014)
-
-Release 2.9.4 CyaSSL has bug fixes and new features including:
-
-- Security fixes that address items reported by Ivan Fratric of the Google
-  Security Team
-- X.509 Unknown critical extensions treated as errors, report by Suman Jana with
-  security researchers at UT Austin and UC Davis
-- Sniffer fixes for corrupted packet length and Jumbo frames
-- ARM thumb mode assembly fixes
-- Xcode 5.1 support including new clang
-- PIC32 MZ hardware support
-- CyaSSL Object has enough room to read the Record Header now w/o allocs
-- FIPS wrappers for AES, 3DES, SHA1, SHA256, SHA384, HMAC, and RSA.
-- A sample I/O pool is demonstrated with --enable-iopool to overtake memory
-  handling and reduce memory fragmentation on I/O large sizes
-
-The CyaSSL manual is available at:
-http://www.wolfssl.com/documentation/CyaSSL-Manual.pdf.  For build instructions 
-and comments about the new features please check the manual.
-
-
-************ CyaSSL Release 2.9.0 (02/07/2014)
-
-Release 2.9.0 CyaSSL has bug fixes and new features including:
-- Freescale Kinetis RNGB support
-- Freescale Kinetis mmCAU support
-- TLS Hello extensions
-  - ECC
-  - Secure Renegotiation (null) 
-  - Truncated HMAC
-- SCEP support
-  - PKCS #7 Enveloped data and signed data
-  - PKCS #10 Certificate Signing Request generation
-- DTLS sliding window
-- OCSP Improvements
-  - API change to integrate into Certificate Manager
-  - IPv4/IPv6 agnostic
-  - example client/server support for OCSP
-  - OCSP nonces are optional
-- GMAC hashing
-- Windows build additions
-- Windows CYGWIN build fixes
-- Updated test certificates
-- Microchip MPLAB Harmony support
-- Update autoconf scripts
-- Additional X.509 inspection functions
-- ECC encrypt/decrypt primitives
-- ECC Certificate generation
-
-The Freescale Kinetis K53 RNGB documentation can be found in Chapter 33 of the
-K53 Sub-Family Reference Manual:
-http://cache.freescale.com/files/32bit/doc/ref_manual/K53P144M100SF2RM.pdf
-
-Freescale Kinetis K60 mmCAU (AES, DES, 3DES, MD5, SHA, SHA256) documentation
-can be found in the "ColdFire/ColdFire+ CAU and Kinetis mmCAU Software Library
-User Guide":
-http://cache.freescale.com/files/32bit/doc/user_guide/CAUAPIUG.pdf
-
-
-*****************CyaSSL Release 2.8.0 (8/30/2013)
-
-Release 2.8.0 CyaSSL has bug fixes and new features including:
-- AES-GCM and AES-CCM use AES-NI
-- NetX default IO callback handlers
-- IPv6 fixes for DTLS Hello Cookies
-- The ability to unload Certs/Keys after the handshake, CyaSSL_UnloadCertsKeys()
-- SEP certificate extensions
-- Callback getters for easier resource freeing
-- External CYASSL_MAX_ERROR_SZ for correct error buffer sizing
-- MacEncrypt and DecryptVerify Callbacks for User Atomic Record Layer Processing
-- Public Key Callbacks for ECC and RSA
-- Client now sends blank cert upon request if doesn't have one with TLS <= 1.2
-
-
-The CyaSSL manual is available at:
-http://www.wolfssl.com/documentation/CyaSSL-Manual.pdf.  For build instructions 
-and comments about the new features please check the manual.
-
-
-*****************CyaSSL Release 2.7.0 (6/17/2013)
-
-Release 2.7.0 CyaSSL has bug fixes and new features including:
-- SNI support for client and server
-- KEIL MDK-ARM projects
-- Wildcard check to domain name match, and Subject altnames are checked too
-- Better error messages for certificate verification errors
-- Ability to discard session during handshake verify
-- More consistent error returns across all APIs
-- Ability to unload CAs at the CTX or CertManager level
-- Authority subject id support for Certificate matching
-- Persistent session cache functionality
-- Persistent CA cache functionality
-- Client session table lookups to push serverID table to library level
-- Camellia support to sniffer
-- User controllable settings for DTLS timeout values
-- Sniffer fixes for caching long lived sessions
-- DTLS reliability enhancements for the handshake
-- Better ThreadX support
-
-When compiling with Mingw, libtool may give the following warning due to
-path conversion errors:
-
-libtool: link: Could not determine host file name corresponding to **
-libtool: link: Continuing, but uninstalled executables may not work.
-
-If so, examples and testsuite will have problems when run, showing an
-error while loading shared libraries. To resolve, please run "make install".
-
-The CyaSSL manual is available at:
-http://www.wolfssl.com/documentation/CyaSSL-Manual.pdf.  For build instructions 
-and comments about the new features please check the manual.
-
-
-************** CyaSSL Release 2.6.0 (04/15/2013)
-
-Release 2.6.0 CyaSSL has bug fixes and new features including:
-- DTLS 1.2 support including AEAD ciphers
-- SHA-3 finalist Blake2 support, it's fast and uses little resources
-- SHA-384 cipher suites including ECC ones
-- HMAC now supports SHA-512
-- Track memory use for example client/server with -t option
-- Better IPv6 examples with --enable-ipv6, before if ipv6 examples/tests were
-  turned on, localhost only was used.  Now link-local (with scope ids) and ipv6
-  hosts can be used as well.
-- Xcode v4.6 project for iOS v6.1 update
-- settings.h is now checked in all *.c files for true one file setting detection
-- Better alignment at SSL layer for hardware crypto alignment needs
-    * Note, SSL itself isn't friendly to alignment with 5 byte TLS headers and
-      13 bytes DTLS headers, but every effort is now made to align with the
-      CYASSL_GENERAL_ALIGNMENT flag which sets desired alignment requirement
-- NO_64BIT flag to turn off 64bit data type accumulators in public key code
-    * Note, some systems are faster with 32bit accumulators 
-- --enable-stacksize for example client/server stack use
-    * Note, modern desktop Operating Systems may add bytes to each stack frame
-- Updated compression/decompression with direct crypto access
-- All ./configure options are now lowercase only for consistency
-- ./configure builds default to fastmath option
-    * Note, if on ia32 and building in shared mode this may produce a problem
-      with a missing register being available because of PIC, there are at least
-      6 solutions to this:
-      1) --disable-fastmath , don't use fastmath
-      2) --disable-shared, don't build a shared library
-      3) C_EXTRA_FLAGS=-DTFM_NO_ASM , turn off assembly use
-      4) use clang, it just seems to work
-      5) play around with no PIC options to force all registers being open,
-         e.g, --without-pic
-      6) if static lib is still a problem try removing fPIE
-- Many new ./configure switches for option enable/disable for example
-    * rsa
-    * dh
-    * dsa
-    * md5
-    * sha 
-    * arc4
-    * null    (allow NULL ciphers)
-    * oldtls  (only use TLS 1.2)
-    * asn     (no certs or public keys allowed)
-- ./configure generates cyassl/options.h which allows a header the user can 
-  include in their app to make sure the same options are set at the app and
-  CyaSSL level.
-- autoconf no longer needs serial-tests which lowers version requirements of
-  automake to 1.11 and autoconf to 2.63
-
-The CyaSSL manual is available at:
-http://www.wolfssl.com/documentation/CyaSSL-Manual.pdf.  For build instructions 
-and comments about the new features please check the manual.
+- Support for Espressif ESP-IDF development framework
+- Fix for XCode build with iPhone simulator on i386
+- PKCS7 support for generating and verify bundles using a detached signature
+- Fix for build disabling AES-CBC and enabling opensslextra compatibility layer
+- Updates to sniffer for showing session information and handling split messages across records
+- Port update for Micrium uC/OS-III
+- Feature to adjust max fragment size post handshake when compiled with the macro WOLFSSL_ALLOW_MAX_FRAGMENT_ADJUST
+- Adding the macro NO_MULTIBYTE_PRINT for compiling out special characters that embedded devices may have problems with
+- Updates for Doxygen documentation, including PKCS #11 API and more
+- Adding Intel QuickAssist v1.7 driver support for asynchronous crypto
+- Adding Intel QuickAssist RSA key generation and SHA-3 support
+- RSA verify only (--enable-rsavfy) and RSA public only (--enable-rsapub) builds added
+- Enhancements to test cases for increased code coverage
+- Updates to VxWorks port for use with Mongoose, including updates to the OpenSSL compatibility layer
+- Yocto Project ease of use improvements along with many updates and build instructions added to the INSTALL file
+- Maximum ticket nonce size was increased to 8
+- Updating --enable-armasm build for ease of use with autotools
+- Updates to internal code checking TLS 1.3 version with a connection
+- Removing unnecessary extended master secret from ServerHello if using TLS 1.3
+- Fix for TLS v1.3 HelloRetryRequest to be sent immediately and not grouped
 
 
 
-************** CyaSSL Release 2.5.0 (02/04/2013)
+This release of wolfSSL includes a fix for 1 security vulnerability.
 
-Release 2.5.0 CyaSSL has bug fixes and new features including:
-- Fix for TLS CBC padding timing attack identified by Nadhem Alfardan and
-  Kenny Paterson: http://www.isg.rhul.ac.uk/tls/
-- Microchip PIC32 (MIPS16, MIPS32) support
-- Microchip MPLAB X example projects for PIC32 Ethernet Starter Kit
-- Updated CTaoCrypt benchmark app for embedded systems
-- 1024-bit test certs/keys and cert/key buffers
-- AES-CCM-8 crypto and cipher suites
-- Camellia crypto and cipher suites
-- Bumped minimum autoconf version to 2.65, automake version to 1.12
-- Addition of OCSP callbacks
-- STM32F2 support with hardware crypto and RNG 
-- Cavium NITROX support
+Medium level fix for potential cache attack with a variant of Bleichenbacherâs attack. Earlier versions of wolfSSL leaked PKCS #1 v1.5 padding information during private key decryption that could lead to a potential padding oracle attack. It is recommended that users update to the latest version of wolfSSL if they have RSA cipher suites enabled and have the potential for malicious software to be ran on the same system that is performing RSA operations. Users that have only ECC cipher suites enabled and are not performing RSA PKCS #1 v1.5 Decryption operations are not vulnerable. Also users with TLS 1.3 only connections are not vulnerable to this attack. Thanks to Eyal Ronen (Weizmann Institute), Robert Gillham (University of Adelaide), Daniel Genkin (University of Michigan), Adi Shamir (Weizmann Institute), David Wong (NCC Group), and Yuval Yarom (University of Adelaide and Data61) for the report.
 
-CTaoCrypt now has support for the Microchip PIC32 and has been tested with
-the Microchip PIC32 Ethernet Starter Kit, the XC32 compiler and
-MPLAB X IDE in both MIPS16 and MIPS32 instruction set modes. See the README
-located under the <cyassl_root>/mplabx directory for more details.
-
-To add Cavium NITROX support do:
-
-./configure --with-cavium=/home/user/cavium/software
-
-pointing to your licensed cavium/software directory.  Since Cavium doesn't
-build a library we pull in the cavium_common.o file which gives a libtool 
-warning about the portability of this.  Also, if you're using the github source
-tree you'll need to remove the -Wredundant-decls warning from the generated
-Makefile because the cavium headers don't conform to this warning.  Currently
-CyaSSL supports Cavium RNG, AES, 3DES, RC4, HMAC, and RSA directly at the crypto
-layer.  Support at the SSL level is partial and currently just does AES, 3DES,
-and RC4.  RSA and HMAC are slower until the Cavium calls can be utilized in non
-blocking mode.  The example client turns on cavium support as does the crypto
-test and benchmark.  Please see the HAVE_CAVIUM define.
-
-CyaSSL is able to use the STM32F2 hardware-based cryptography and random number
-generator through the STM32F2 Standard Peripheral Library. For necessary
-defines, see the CYASSL_STM32F2 define in settings.h. Documentation for the
-STM32F2 Standard Peripheral Library can be found in the following document: 
-http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/USER_MANUAL/DM00023896.pdf
-
-The CyaSSL manual is available at:
-http://www.wolfssl.com/documentation/CyaSSL-Manual.pdf.  For build instructions 
-and comments about the new features please check the manual.
+The paper for further reading on the attack details can be found at http://cat.eyalro.net/cat.pdf.
 
 
-
-*************** CyaSSL Release 2.4.6 (12/20/2012)
-
-Release 2.4.6 CyaSSL has bug fixes and a few new features including:
-- ECC into main version
-- Lean PSK build (reduced code size, RAM usage, and stack usage)
-- FreeBSD CRL monitor support
-- CyaSSL_peek()
-- CyaSSL_send() and CyaSSL_recv() for I/O flag setting
-- CodeWarrior Support
-- MQX Support
-- Freescale Kinetis support including Hardware RNG
-- autoconf builds use jobserver
-- cyassl-config
-- Sniffer memory reductions
-
-Thanks to Brian Aker for the improved autoconf system, make rpm, cyassl-config,
-warning system, and general good ideas for improving CyaSSL!
-
-The Freescale Kinetis K70 RNGA documentation can be found in Chapter 37 of the
-K70 Sub-Family Reference Manual:
-http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf
-
-The CyaSSL manual is available at:
-http://www.wolfssl.com/documentation/CyaSSL-Manual.pdf.  For build instructions 
-and comments about the new features please check the manual.
+*** Resources ***
 
 
-*************** CyaSSL Release 2.4.0 (10/10/2012)
+[wolfSSL Website](https://www.wolfssl.com/)
 
-Release 2.4.0 CyaSSL has bug fixes and a few new features including:
-- DTLS reliability
-- Reduced memory usage after handshake
-- Updated build process
+[wolfSSL Wiki](https://github.com/wolfSSL/wolfssl/wiki)
 
-The CyaSSL manual is available at:
-http://www.wolfssl.com/documentation/CyaSSL-Manual.pdf.  For build instructions 
-and comments about the new features please check the manual.
+[FIPS FAQ](https://www.wolfssl.com/wolfSSL/fips.html)
 
+[wolfSSL Manual](https://wolfssl.com/wolfSSL/Docs-wolfssl-manual-toc.html)
 
+[wolfSSL API Reference]
+(https://wolfssl.com/wolfSSL/Docs-wolfssl-manual-17-wolfssl-api-reference.html)
 
-*************** CyaSSL Release 2.3.0 (8/10/2012)
+[wolfCrypt API Reference]
+(https://wolfssl.com/wolfSSL/Docs-wolfssl-manual-18-wolfcrypt-api-reference.html)
 
-Release 2.3.0 CyaSSL has bug fixes and a few new features including:
-- AES-GCM crypto and cipher suites
-- make test cipher suite checks
-- Subject AltName processing
-- Command line support for client/server examples
-- Sniffer SessionTicket support
-- SHA-384 cipher suites
-- Verify cipher suite validity when user overrides
-- CRL dir monitoring
-- DTLS Cookie support, reliability coming soon
-
-The CyaSSL manual is available at:
-http://www.wolfssl.com/documentation/CyaSSL-Manual.pdf.  For build instructions 
-and comments about the new features please check the manual.
-
-
-
-***************CyaSSL Release 2.2.0 (5/18/2012)
-
-Release 2.2.0 CyaSSL has bug fixes and a few new features including:
-- Initial CRL support (--enable-crl)
-- Initial OCSP support (--enable-ocsp)
-- Add static ECDH suites
-- SHA-384 support
-- ECC client certificate support
-- Add medium session cache size (1055 sessions) 
-- Updated unit tests
-- Protection against mutex reinitialization
-
-
-The CyaSSL manual is available at:
-http://www.wolfssl.com/documentation/CyaSSL-Manual.pdf.  For build instructions 
-and comments about the new features please check the manual.
-
-
-
-***************CyaSSL Release 2.0.8 (2/24/2012)
-
-Release 2.0.8 CyaSSL has bug fixes and a few new features including:
-- A fix for malicious certificates pointed out by Remi Gacogne (thanks)
-  resulting in NULL pointer use.
-- Respond to renegotiation attempt with no_renegoatation alert
-- Add basic path support for load_verify_locations()
-- Add set Temp EC-DHE key size
-- Extra checks on rsa test when porting into
-
-
-The CyaSSL manual is available at:
-http://www.wolfssl.com/documentation/CyaSSL-Manual.pdf.  For build instructions 
-and comments about the new features please check the manual.
-
-
-
-************* CyaSSL Release 2.0.6 (1/27/2012)
-
-Release 2.0.6 CyaSSL has bug fixes and a few new features including:
-- Fixes for CA basis constraint check
-- CTX reference counting
-- Initial unit test additions
-- Lean and Mean Windows fix
-- ECC benchmarking
-- SSMTP build support
-- Ability to group handshake messages with set_group_messages(ctx/ssl)
-- CA cache addition callback
-- Export Base64_Encode for general use
-
-The CyaSSL manual is available at:
-http://www.wolfssl.com/documentation/CyaSSL-Manual.pdf.  For build instructions 
-and comments about the new features please check the manual.
-
-
-
-************* CyaSSL Release 2.0.2 (12/05/2011)
-
-Release 2.0.2 CyaSSL has bug fixes and a few new features including:
-- CTaoCrypt Runtime library detection settings when directly using the crypto
-  library
-- Default certificate generation now uses SHAwRSA and adds SHA256wRSA generation
-- All test certificates now use 2048bit and SHA-1 for better modern browser
-  support
-- Direct AES block access and AES-CTR (counter) mode
-- Microchip pic32 support
-
-The CyaSSL manual is available at:
-http://www.wolfssl.com/documentation/CyaSSL-Manual.pdf.  For build instructions 
-and comments about the new features please check the manual.
-
-
-
-************* CyaSSL Release 2.0.0rc3 (9/28/2011)
-
-Release 2.0.0rc3 for CyaSSL has bug fixes and a few new features including:
-- updated autoconf support
-- better make install and uninstall  (uses system directories)
-- make test / make check
-- CyaSSL headers now in <cyassl/*.h>
-- CTaocrypt headers now in <cyassl/ctaocrypt/*.h>
-- OpenSSL compatibility headers now in <cyassl/openssl/*.h>
-- examples and tests all run from home directory so can use certs in ./certs
-        (see note 1)
-
-So previous applications that used the OpenSSL compatibility header
-<openssl/ssl.h> now need to include <cyassl/openssl/ssl.h> instead, no other
-changes are required.
-
-Special Thanks to Brian Aker for his autoconf, install, and header patches.
-
-The CyaSSL manual is available at:
-http://www.wolfssl.com/documentation/CyaSSL-Manual.pdf.  For build instructions 
-and comments about the new features please check the manual.
-
-************CyaSSL Release 2.0.0rc2 (6/6/2011)
-
-Release 2.0.0rc2 for CyaSSL has bug fixes and a few new features including:
-- bug fixes (Alerts, DTLS with DHE)
-- FreeRTOS support
-- lwIP support
-- Wshadow warnings removed
-- asn public header
-- CTaoCrypt public headers now all have ctc_ prefix (the manual is still being
-        updated to reflect this change)
-- and more.
-
-This is the 2nd and perhaps final release candidate for version 2.
-Please send any comments or questions to support@wolfssl.com.
-
-The CyaSSL manual is available at:
-http://www.wolfssl.com/documentation/CyaSSL-Manual.pdf.  For build instructions 
-and comments about the new features please check the manual.
-
-***********CyaSSL Release 2.0.0rc1 (5/2/2011)
-
-Release 2.0.0rc1 for CyaSSL has many new features including:
-- bug fixes
-- SHA-256 cipher suites 
-- Root Certificate Verification (instead of needing all certs in the chain) 
-- PKCS #8 private key encryption (supports PKCS #5 v1-v2 and PKCS #12) 
-- Serial number retrieval for x509 
-- PBKDF2 and PKCS #12 PBKDF 
-- UID parsing for x509 
-- SHA-256 certificate signatures 
-- Client and server can send chains (SSL_CTX_use_certificate_chain_file) 
-- CA loading can now parse multiple certificates per file
-- Dynamic memory runtime hooks
-- Runtime hooks for logging
-- EDH on server side
-- More informative error codes
-- More informative logging messages
-- Version downgrade more robust (use SSL_v23*)
-- Shared build only by default through ./configure
-- Compiler visibility is now used, internal functions not polluting namespace
-- Single Makefile, no recursion, for faster and simpler building
-- Turn on all warnings possible build option, warning fixes
-- and more.
-
-Because of all the new features and the multiple OS, compiler, feature-set
-options that CyaSSL allows, there may be some configuration fixes needed.
-Please send any comments or questions to support@wolfssl.com.
-
-The CyaSSL manual is available at:
-http://www.wolfssl.com/documentation/CyaSSL-Manual.pdf.  For build instructions 
-and comments about the new features please check the manual.
-
-****************** CyaSSL Release 1.9.0 (3/2/2011)
-
-Release 1.9.0 for CyaSSL adds bug fixes, improved TLSv1.2 through testing and
-better hash/sig algo ids, --enable-webServer for the yaSSL embedded web server,
-improper AES key setup detection, user cert verify callback improvements, and
-more.
-
-The CyaSSL manual offering is included in the doc/ directory.  For build
-instructions and comments about the new features please check the manual.
-
-Please send any comments or questions to support@wolfssl.com.
-
-****************** CyaSSL Release 1.8.0 (12/23/2010)
-
-Release 1.8.0 for CyaSSL adds bug fixes, x509 v3 CA signed certificate
-generation, a C standard library abstraction layer, lower memory use, increased
-portability through the os_settings.h file, and the ability to use NTRU cipher
-suites when used in conjunction with an NTRU license and library.
-
-The initial CyaSSL manual offering is included in the doc/ directory.  For
-build instructions and comments about the new features please check the manual.
-
-Please send any comments or questions to support@wolfssl.com.
-
-Happy Holidays.
- 
-
-********************* CyaSSL Release 1.6.5 (9/9/2010)
-
-Release 1.6.5 for CyaSSL adds bug fixes and x509 v3 self signed certificate
-generation.
- 
-For general build instructions see doc/Building_CyaSSL.pdf.
-
-To enable certificate generation support add this option to ./configure
-./configure --enable-certgen
-
-An example is included in ctaocrypt/test/test.c and documentation is provided
-in doc/CyaSSL_Extensions_Reference.pdf item 11.
-
-********************** CyaSSL Release 1.6.0 (8/27/2010)
-
-Release 1.6.0 for CyaSSL adds bug fixes, RIPEMD-160, SHA-512, and RSA key
-generation.
- 
-For general build instructions see doc/Building_CyaSSL.pdf.
-
-To add RIPEMD-160 support add this option to ./configure
-./configure --enable-ripemd
-
-To add SHA-512 support add this option to ./configure
-./configure --enable-sha512
-
-To add RSA key generation support add this option to ./configure
-./configure --enable-keygen
-
-Please see ctaocrypt/test/test.c for examples and usage.
-
-For Windows, RIPEMD-160 and SHA-512 are enabled by default but key generation is
-off by default.  To turn key generation on add the define CYASSL_KEY_GEN to
-CyaSSL.
-
-
-*************   CyaSSL Release 1.5.6 (7/28/2010)
-
-Release 1.5.6 for CyaSSL adds bug fixes, compatibility for our JSSE provider,
-and a fix for GCC builds on some systems.
- 
-For general build instructions see doc/Building_CyaSSL.pdf.
-
-To add AES-NI support add this option to ./configure
-./configure --enable-aesni
-
-You'll need GCC 4.4.3 or later to make use of the assembly.
-
-**************  CyaSSL Release 1.5.4 (7/7/2010)
-
-Release 1.5.4 for CyaSSL adds bug fixes, support for AES-NI, SHA1 speed 
-improvements from loop unrolling, and support for the Mongoose Web Server.
- 
-For general build instructions see doc/Building_CyaSSL.pdf.
-
-To add AES-NI support add this option to ./configure
-./configure --enable-aesni
-
-You'll need GCC 4.4.3 or later to make use of the assembly.
-
-***************  CyaSSL Release 1.5.0 (5/11/2010)
-
-Release 1.5.0 for CyaSSL adds bug fixes, GoAhead WebServer support, sniffer
-support, and initial swig interface support.
-
-For general build instructions see doc/Building_CyaSSL.pdf.
-
-To add support for GoAhead WebServer either --enable-opensslExtra or if you
-don't want all the features of opensslExtra you can just define GOAHEAD_WS
-instead.  GOAHEAD_WS can be added to ./configure with CFLAGS=-DGOAHEAD_WS or
-you can define it yourself.
-
-To look at the sniffer support please see the sniffertest app in
-sslSniffer/sslSnifferTest.  Build with --enable-sniffer on *nix or use the
-vcproj files on windows.  You'll need to have pcap installed on *nix and
-WinPcap on windows.
-
-A swig interface file is now located in the swig directory for using Python,
-Java, Perl, and others with CyaSSL.  This is initial support and experimental,
-please send questions or comments to support@wolfssl.com.
-
-When doing load testing with CyaSSL, on the echoserver example say, the client
-machine may run out of tcp ephemeral ports, they will end up in the TIME_WAIT
-queue, and can't be reused by default.  There are generally two ways to fix
-this.  1) Reduce the length sockets remain on the TIME_WAIT queue or 2) Allow
-items on the TIME_WAIT queue to be reused.
-
-
-To reduce the TIME_WAIT length in OS X to 3 seconds (3000 milliseconds)
-
-sudo sysctl -w net.inet.tcp.msl=3000
-
-In Linux
-
-sudo sysctl -w net.ipv4.tcp_tw_reuse=1
-
-allows reuse of sockets in TIME_WAIT
-
-sudo sysctl -w net.ipv4.tcp_tw_recycle=1
-
-works but seems to remove sockets from  TIME_WAIT entirely?
-
-sudo sysctl -w net.ipv4.tcp_fin_timeout=1
-
-doen't control TIME_WAIT, it controls FIN_WAIT(2) contrary to some posts
-
-
-******************** CyaSSL Release 1.4.0 (2/18/2010)
-
-Release 1.3.0 for CyaSSL adds bug fixes, better multi TLS/SSL version support
-through SSLv23_server_method(), and improved documentation in the doc/ folder.
-
-For general build instructions doc/Building_CyaSSL.pdf.
-
-******************** CyaSSL Release 1.3.0 (1/21/2010)
-
-Release 1.3.0 for CyaSSL adds bug fixes, a potential security problem fix,
-better porting support, removal of assert()s, and a complete THREADX port.
-
-For general build instructions see rc1 below.
-
-******************** CyaSSL Release 1.2.0 (11/2/2009)
-
-Release 1.2.0 for CyaSSL adds bug fixes and session negotiation if first use is
-read or write.
-
-For general build instructions see rc1 below.
-
-******************** CyaSSL Release 1.1.0 (9/2/2009)
-
-Release 1.1.0 for CyaSSL adds bug fixes, a check against malicious session
-cache use, support for lighttpd, and TLS 1.2.
-
-To get TLS 1.2 support please use the client and server functions:
-
-SSL_METHOD *TLSv1_2_server_method(void);
-SSL_METHOD *TLSv1_2_client_method(void);
-
-CyaSSL was tested against lighttpd 1.4.23.  To build CyaSSL for use with 
-lighttpd use the following commands from the CyaSSL install dir <CyaSSLDir>:
-
-./configure --disable-shared --enable-opensslExtra --enable-fastmath --without-zlib
-
-make
-make openssl-links
-
-Then to build lighttpd with CyaSSL use the following commands from the
-lighttpd install dir:
-
-./configure --with-openssl --with-openssl-includes=<CyaSSLDir>/include --with-openssl-libs=<CyaSSLDir>/lib LDFLAGS=-lm
-
-make
-
-On some systems you may get a linker error about a duplicate symbol for
-MD5_Init or other MD5 calls.  This seems to be caused by the lighttpd src file
-md5.c, which defines MD5_Init(), and is included in liblightcomp_la-md5.o.
-When liblightcomp is linked with the SSL_LIBs the linker may complain about
-the duplicate symbol.  This can be fixed by editing the lighttpd src file md5.c
-and adding this line to the beginning of the file:
-
-#if 0
-
-and this line to the end of the file
-
-#endif
-
-Then from the lighttpd src dir do a:
-
-make clean
-make
-
-
-If you get link errors about undefined symbols more than likely the actual
-OpenSSL libraries are found by the linker before the CyaSSL openssl-links that
-point to the CyaSSL library, causing the linker confusion.  This can be fixed
-by editing the Makefile in the lighttpd src directory and changing the line:
-
-SSL_LIB = -lssl -lcrypto
-
-to
-
-SSL_LIB = -lcyassl
-
-Then from the lighttpd src dir do a:
-
-make clean
-make
-
-This should remove any confusion the linker may be having with missing symbols.
-
-For any questions or concerns please contact support@wolfssl.com .
-
-For general build instructions see rc1 below.
-
-******************CyaSSL Release 1.0.6 (8/03/2009)
-
-Release 1.0.6 for CyaSSL adds bug fixes, an improved session cache, and faster
-math with a huge code option.
-
-The session cache now defaults to a client mode, also good for embedded servers.
-For servers not under heavy load (less than 200 new sessions per minute), define
-BIG_SESSION_CACHE.  If the server will be under heavy load, define
-HUGE_SESSION_CACHE.
-
-There is now a fasthugemath option for configure.  This enables fastmath plus
-even faster math by greatly increasing the code size of the math library. Use
-the benchmark utility to compare public key operations.
-
-
-For general build instructions see rc1 below.
-
-******************CyaSSL Release 1.0.3 (5/10/2009)
-
-Release 1.0.3 for CyaSSL adds bug fixes and add increased support for OpenSSL
-compatibility when building other applications.
-
-Release 1.0.3 includes an alpha release of DTLS for both client and servers.
-This is only for testing purposes at this time.  Rebroadcast and reordering
-aren't fully implemented at this time but will be for the next release.
-
-For general build instructions see rc1 below.
-
-******************CyaSSL Release 1.0.2 (4/3/2009)
-
-Release 1.0.2 for CyaSSL adds bug fixes for a couple I/O issues.  Some systems
-will send a SIGPIPE on socket recv() at any time and this should be handled by
-the application by turning off SIGPIPE through setsockopt() or returning from
-the handler.
-
-Release 1.0.2 includes an alpha release of DTLS for both client and servers.
-This is only for testing purposes at this time.  Rebroadcast and reordering
-aren't fully implemented at this time but will be for the next release.
-
-For general build instructions see rc1 below.
-
-*****************CyaSSL Release Candidate 3 rc3-1.0.0 (2/25/2009)
-
-
-Release Candidate 3 for CyaSSL 1.0.0 adds bug fixes and adds a project file for
-iPhone development with Xcode.  cyassl-iphone.xcodeproj is located in the root
-directory.  This release also includes a fix for supporting other
-implementations that bundle multiple messages at the record layer, this was
-lost when cyassl i/o was re-implemented but is now fixed.
-
-For general build instructions see rc1 below.
-
-*****************CyaSSL Release Candidate 2 rc2-1.0.0 (1/21/2009)
-
-
-Release Candidate 2 for CyaSSL 1.0.0 adds bug fixes and adds two new stream
-ciphers along with their respective cipher suites.  CyaSSL adds support for
-HC-128 and RABBIT stream ciphers.  The new suites are:
-
-TLS_RSA_WITH_HC_128_SHA
-TLS_RSA_WITH_RABBIT_SHA
-
-And the corresponding cipher names are
-
-HC128-SHA
-RABBIT-SHA
-
-CyaSSL also adds support for building with devkitPro for PPC by changing the
-library proper to use libogc.  The examples haven't been changed yet but if
-there's interest they can be.  Here's an example ./configure to build CyaSSL
-for devkitPro:
-
-./configure --disable-shared CC=/pathTo/devkitpro/devkitPPC/bin/powerpc-gekko-gcc --host=ppc --without-zlib --enable-singleThreaded RANLIB=/pathTo/devkitpro/devkitPPC/bin/powerpc-gekko-ranlib CFLAGS="-DDEVKITPRO -DGEKKO"
-
-For linking purposes you'll need
-
-LDFLAGS="-g -mrvl -mcpu=750 -meabi -mhard-float -Wl,-Map,$(notdir $@).map"
-
-For general build instructions see rc1 below.
-
-
-********************CyaSSL Release Candidate 1 rc1-1.0.0 (12/17/2008)
-
-
-Release Candidate 1 for CyaSSL 1.0.0 contains major internal changes.  Several
-areas have optimization improvements, less dynamic memory use, and the I/O
-strategy has been refactored to allow alternate I/O handling or Library use.
-Many thanks to Thierry Fournier for providing these ideas and most of the work.
-
-Because of these changes, this release is only a candidate since some problems
-are probably inevitable on some platform with some I/O use.  Please report any
-problems and we'll try to resolve them as soon as possible.  You can contact us
-at support@wolfssl.com or todd@wolfssl.com.
-
-Using TomsFastMath by passing --enable-fastmath to ./configure now uses assembly
-on some platforms.  This is new so please report any problems as every compiler,
-mode, OS combination hasn't been tested.  On ia32 all of the registers need to
-be available so be sure to pass these options to CFLAGS:
-
-CFLAGS="-O3 -fomit-frame-pointer"
-
-OS X will also need -mdynamic-no-pic added to CFLAGS
-
-Also if you're building in shared mode for ia32 you'll need to pass options to
-LDFLAGS as well on OS X:
-
-LDFLAGS=-Wl,-read_only_relocs,warning
-
-This gives warnings for some symbols but seems to work.
-
-
---To build on Linux, Solaris, *BSD, Mac OS X, or Cygwin:
-
-    ./configure
-    make
-
-    from the ./testsuite/ directory run ./testsuite 
-
-to make a debug build:
-
-    ./configure --enable-debug --disable-shared
-    make
-
-
-
---To build on Win32
-
-Choose (Re)Build All from the project workspace
-
-Run the testsuite program
-
-
-
-
-
-*************************CyaSSL version 0.9.9 (7/25/2008) 
-
-This release of CyaSSL adds bug fixes, Pre-Shared Keys, over-rideable memory
-handling, and optionally TomsFastMath.  Thanks to Moisè¾¿s Guimarées for the
-work on TomsFastMath.
-
-To optionally use TomsFastMath pass --enable-fastmath to ./configure
-Or define USE_FAST_MATH in each project from CyaSSL for MSVC.
-
-Please use the benchmark routine before and after to see the performance
-difference, on some platforms the gains will be little but RSA encryption
-always seems to be faster.  On x86-64 machines with GCC the normal math library
-may outperform the fast one when using CFLAGS=-m64 because TomsFastMath can't
-yet use -m64 because of GCCs inability to do 128bit division.
-
-     **** UPDATE GCC 4.2.1 can now do 128bit division ***
-
-See notes below (0.2.0) for complete build instructions.
-
-
-****************CyaSSL version 0.9.8 (5/7/2008) 
-
-This release of CyaSSL adds bug fixes, client side Diffie-Hellman, and better
-socket handling.
-
-See notes below (0.2.0) for complete build instructions.
-
-
-****************CyaSSL version 0.9.6 (1/31/2008) 
-
-This release of CyaSSL adds bug fixes, increased session management, and a fix
-for gnutls.
-
-See notes below (0.2.0) for complete build instructions.
-
-
-****************CyaSSL version 0.9.0 (10/15/2007) 
-
-This release of CyaSSL adds bug fixes, MSVC 2005 support, GCC 4.2 support, 
-IPV6 support and test, and new test certificates.
-
-See notes below (0.2.0) for complete build instructions.
-
-
-****************CyaSSL version 0.8.0 (1/10/2007) 
-
-This release of CyaSSL adds increased socket support, for non-blocking writes,
-connects, and interrupted system calls.
-
-See notes below (0.2.0) for complete build instructions.
-
-
-****************CyaSSL version 0.6.3 (10/30/2006) 
-
-This release of CyaSSL adds debug logging to stderr to aid in the debugging of
-CyaSSL on systems that may not provide the best support.
-
-If CyaSSL is built with debugging support then you need to call
-CyaSSL_Debugging_ON() to turn logging on.
-
-On Unix use ./configure --enable-debug
-
-On Windows define DEBUG_CYASSL when building CyaSSL
-
-
-To turn logging back off call CyaSSL_Debugging_OFF()
-
-See notes below (0.2.0) for complete build instructions.
-
-
-*****************CyaSSL version 0.6.2 (10/29/2006) 
-
-This release of CyaSSL adds TLS 1.1.
-
-Note that CyaSSL has certificate verification on by default, unlike OpenSSL.
-To emulate OpenSSL behavior, you must call SSL_CTX_set_verify() with
-SSL_VERIFY_NONE.  In order to have full security you should never do this, 
-provide CyaSSL with the proper certificates to eliminate impostors and call
-CyaSSL_check_domain_name() to prevent man in the middle attacks.
-
-See notes below (0.2.0) for build instructions.
-
-*****************CyaSSL version 0.6.0 (10/25/2006) 
-
-This release of CyaSSL adds more SSL functions, better autoconf, nonblocking
-I/O for accept, connect, and read.  There is now an --enable-small configure
-option that turns off TLS, AES, DES3, HMAC, and ERROR_STRINGS, see configure.in
-for the defines.  Note that TLS requires HMAC and AES requires TLS.
-
-See notes below (0.2.0) for build instructions.
-
-
-*****************CyaSSL version 0.5.5 (09/27/2006) 
-
-This mini release of CyaSSL adds better input processing through buffered input
-and big message support.  Added SSL_pending() and some sanity checks on user
-settings.
-
-See notes below (0.2.0) for build instructions.
-
-
-*****************CyaSSL version 0.5.0 (03/27/2006) 
-
-This release of CyaSSL adds AES support and minor bug fixes. 
-
-See notes below (0.2.0) for build instructions.
-
-
-*****************CyaSSL version 0.4.0 (03/15/2006)
-
-This release of CyaSSL adds TLSv1 client/server support and libtool. 
-
-See notes below for build instructions.
-
-
-*****************CyaSSL version 0.3.0 (02/26/2006)
-
-This release of CyaSSL adds SSLv3 server support and session resumption. 
-
-See notes below for build instructions.
-
-
-*****************CyaSSL version 0.2.0 (02/19/2006)
-
-
-This is the first release of CyaSSL and its crypt brother, CTaoCrypt.  CyaSSL
-is written in ANSI C with the idea of a small code size, footprint, and memory
-usage in mind.  CTaoCrypt can be as small as 32K, and the current client
-version of CyaSSL can be as small as 12K.
-
-
-The first release of CTaoCrypt supports MD5, SHA-1, 3DES, ARC4, Big Integer
-Support, RSA, ASN parsing, and basic x509 (en/de)coding.
-
-The first release of CyaSSL supports normal client RSA mode SSLv3 connections
-with support for SHA-1 and MD5 digests.  Ciphers include 3DES and RC4.
-
-
---To build on Linux, Solaris, *BSD, Mac OS X, or Cygwin:
-
-    ./configure
-    make
-
-    from the ./testsuite/ directory run ./testsuite 
-
-to make a debug build:
-
-    ./configure --enable-debug --disable-shared
-    make
-
-
-
---To build on Win32
-
-Choose (Re)Build All from the project workspace
-
-Run the testsuite program
-
-
-
-*** The next release of CyaSSL will support a server and more OpenSSL
-compatibility functions.
-
-
-Please send questions or comments to todd@wolfssl.com
-
+[TLS 1.3](https://www.wolfssl.com/docs/tls13/)
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/cyassl/ctaocrypt/settings.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/cyassl/ctaocrypt/settings.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/cyassl/ctaocrypt/settings.h	(revision 372)
@@ -151,14 +151,18 @@
 #endif
 
-#ifdef CYASSL_MICROCHIP_PIC32MZ
-    #define CYASSL_PIC32MZ_CE
-    #define CYASSL_PIC32MZ_CRYPT
-    #define HAVE_AES_ENGINE
-    #define CYASSL_PIC32MZ_RNG
-    /* #define CYASSL_PIC32MZ_HASH */
+#if defined(CYASSL_MICROCHIP_PIC32MZ) || defined(WOLFSSL_MICROCHIP_PIC32MZ)
+    #ifndef NO_PIC32MZ_CRYPT
+        #define WOLFSSL_PIC32MZ_CRYPT
+    #endif
+    #ifndef NO_PIC32MZ_RNG
+        #define WOLFSSL_PIC32MZ_RNG
+    #endif
+    #ifndef NO_PIC32MZ_HASH
+        #define WOLFSSL_PIC32MZ_HASH
+    #endif
+
     #define CYASSL_AES_COUNTER
     #define HAVE_AESGCM
     #define NO_BIG_INT
-
 #endif
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/cyassl/ssl.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/cyassl/ssl.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/cyassl/ssl.h	(revision 372)
@@ -445,5 +445,4 @@
 #define CyaSSL_CTX_use_PrivateKey_file      wolfSSL_CTX_use_PrivateKey_file
 #define CyaSSL_CTX_use_certificate_file     wolfSSL_CTX_use_certificate_file
-#define CyaSSL_CTX_use_PrivateKey_buffer    wolfSSL_CTX_use_PrivateKey_buffer
 #define CyaSSL_CTX_use_PrivateKey_buffer    wolfSSL_CTX_use_PrivateKey_buffer
 #define CyaSSL_CTX_use_certificate_buffer   wolfSSL_CTX_use_certificate_buffer
@@ -487,5 +486,4 @@
 #define CyaDTLSv1_2_server_method         wolfDTLSv1_2_server_method
 #define CyaSSL_set_group_messages         wolfSSL_set_group_messages
-#define CyaSSL_set_using_nonblock         wolfSSL_set_using_nonblock
 #define CyaSSL_CTX_set_cipher_list        wolfSSL_CTX_set_cipher_list
 #define CyaSSL_CTX_set_group_messages     wolfSSL_CTX_set_group_messages
@@ -500,6 +498,6 @@
 
 #define CyaSSL_accept_ex              wolfSSL_accept_ex
-#define CyaSSL_SetIORecv              wolfSSL_SetIORecv
-#define CyaSSL_SetIOSend              wolfSSL_SetIOSend
+#define CyaSSL_SetIORecv              wolfSSL_CTX_SetIORecv
+#define CyaSSL_SetIOSend              wolfSSL_CTX_SetIOSend
 #define CyaSSL_connect_ex             wolfSSL_connect_ex
 #define CyaSSL_CTX_SetCACb            wolfSSL_CTX_SetCACb
@@ -625,4 +623,5 @@
 #define CyaSSL_dtls_got_timeout         wolfSSL_dtls_got_timeout
 #define CyaSSL_dtls_get_current_timeout wolfSSL_dtls_get_current_timeout
+#define CyaSSL_set_using_nonblock       wolfSSL_dtls_set_using_nonblock
 
 /* Certificate Manager */
@@ -659,5 +658,4 @@
 
 /* OpenSSL Compatibility Layer */
-#define CyaSSL_PemCertToDer               wolfSSL_PemCertToDer
 #define CyaSSL_get_sessionID              wolfSSL_get_sessionID
 #define CyaSSL_get_peer_count             wolfSSL_get_peer_count
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/crl.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/crl.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/crl.c	(revision 372)
@@ -50,6 +50,8 @@
 {
     WOLFSSL_ENTER("InitCRL");
-
+    if(cm != NULL)
     crl->heap = cm->heap;
+    else
+        crl->heap = NULL;
     crl->cm = cm;
     crl->crlList = NULL;
@@ -154,5 +156,4 @@
 
     WOLFSSL_ENTER("FreeCRL");
-
     if (crl->monitors[0].path)
         XFREE(crl->monitors[0].path, crl->heap, DYNAMIC_TYPE_CRL_MONITOR);
@@ -248,4 +249,6 @@
             #endif /* NO_SKID */
                 if (ca == NULL) {
+                    XFREE(sig, crl->heap, DYNAMIC_TYPE_CRL_ENTRY);
+                    XFREE(tbs, crl->heap, DYNAMIC_TYPE_CRL_ENTRY);
                     WOLFSSL_MSG("Did NOT find CRL issuer CA");
                     return ASN_CRL_NO_SIGNER_E;
@@ -301,5 +304,5 @@
             if (doNextDate) {
             #ifndef NO_ASN_TIME
-                if (!ValidateDate(crle->nextDate,crle->nextDateFormat, AFTER)) {
+                if (!XVALIDATE_DATE(crle->nextDate,crle->nextDateFormat, AFTER)) {
                     WOLFSSL_MSG("CRL next date is no longer valid");
                     ret = ASN_AFTER_DATE_E;
@@ -372,4 +375,5 @@
             WOLFSSL_MSG("Issuing missing CRL callback");
             url[0] = '\0';
+            if (cert->extCrlInfo) {
             if (cert->extCrlInfoSz < (int)sizeof(url) -1 ) {
                 XMEMCPY(url, cert->extCrlInfo, cert->extCrlInfoSz);
@@ -378,4 +382,5 @@
             else  {
                 WOLFSSL_MSG("CRL url too long");
+            }
             }
 
@@ -441,9 +446,6 @@
 
     if (type == WOLFSSL_FILETYPE_PEM) {
-        int eccKey = 0;   /* not used */
-        EncryptedInfo info;
-        info.ctx = NULL;
-
-        ret = PemToDer(buff, sz, CRL_TYPE, &der, NULL, &info, &eccKey);
+    #ifdef WOLFSSL_PEM_TO_DER
+        ret = PemToDer(buff, sz, CRL_TYPE, &der, NULL, NULL, NULL);
         if (ret == 0) {
             myBuffer = der->buffer;
@@ -455,4 +457,7 @@
             return -1;
         }
+    #else
+        ret = NOT_COMPILED_IN;
+    #endif
     }
 
@@ -488,4 +493,32 @@
 }
 
+#if defined(OPENSSL_EXTRA) && defined(HAVE_CRL)
+int wolfSSL_X509_STORE_add_crl(WOLFSSL_X509_STORE *store, WOLFSSL_X509_CRL *newcrl)
+{
+    CRL_Entry   *crle;
+    WOLFSSL_CRL *crl;
+
+    WOLFSSL_ENTER("wolfSSL_X509_STORE_add_crl");
+    if (store == NULL || newcrl == NULL)
+        return BAD_FUNC_ARG;
+
+    crl = store->crl;
+    crle = newcrl->crlList;
+
+    if (wc_LockMutex(&crl->crlLock) != 0)
+    {
+        WOLFSSL_MSG("wc_LockMutex failed");
+        return BAD_MUTEX_E;
+    }
+    crle->next = crl->crlList;
+    crl->crlList = crle;
+    newcrl->crlList = NULL;
+    wc_UnLockMutex(&crl->crlLock);
+
+    WOLFSSL_LEAVE("wolfSSL_X509_STORE_add_crl", WOLFSSL_SUCCESS);
+    
+    return WOLFSSL_SUCCESS;
+}
+#endif
 
 #ifdef HAVE_CRL_MONITOR
@@ -739,5 +772,5 @@
 
 #ifndef max
-    static INLINE int max(int a, int b)
+    static WC_INLINE int max(int a, int b)
     {
         return a > b ? a : b;
@@ -1013,6 +1046,5 @@
         pathBuf = (char*)XMALLOC(pathLen+1, crl->heap,DYNAMIC_TYPE_CRL_MONITOR);
         if (pathBuf) {
-            XSTRNCPY(pathBuf, path, pathLen);
-            pathBuf[pathLen] = '\0'; /* Null Terminate */
+            XSTRNCPY(pathBuf, path, pathLen+1);
 
             if (type == WOLFSSL_FILETYPE_PEM) {
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/internal.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/internal.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/internal.c	(revision 372)
@@ -28,4 +28,10 @@
 #include <wolfssl/wolfcrypt/settings.h>
 
+/*
+ * WOLFSSL_SMALL_CERT_VERIFY:
+ *     Verify the certificate signature without using DecodedCert. Doubles up
+ *     on some code but allows smaller dynamic memory usage.
+ */
+
 #ifndef WOLFCRYPT_ONLY
 
@@ -39,4 +45,7 @@
     #define WOLFSSL_MISC_INCLUDED
     #include <wolfcrypt/src/misc.c>
+#endif
+#if defined(OPENSSL_EXTRA) && defined(WOLFCRYPT_HAVE_SRP) && !defined(NO_SHA)
+    #include <wolfssl/wolfcrypt/srp.h>
 #endif
 
@@ -82,4 +91,6 @@
     #error Cannot use both secure-renegotiation and renegotiation-indication
 #endif
+
+#ifndef WOLFSSL_NO_TLS12
 
 #ifndef NO_WOLFSSL_CLIENT
@@ -101,5 +112,6 @@
 #ifndef NO_WOLFSSL_SERVER
     static int DoClientKeyExchange(WOLFSSL* ssl, byte* input, word32*, word32);
-    #if !defined(NO_RSA) || defined(HAVE_ECC)
+    #if (!defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519)) && \
+                                                !defined(WOLFSSL_NO_CLIENT_AUTH)
         static int DoCertificateVerify(WOLFSSL* ssl, byte*, word32*, word32);
     #endif
@@ -109,8 +121,9 @@
 #endif
 
+#endif /* !WOLFSSL_NO_TLS12 */
 
 #ifdef WOLFSSL_DTLS
-    static INLINE int DtlsCheckWindow(WOLFSSL* ssl);
-    static INLINE int DtlsUpdateWindow(WOLFSSL* ssl);
+    static WC_INLINE int DtlsCheckWindow(WOLFSSL* ssl);
+    static WC_INLINE int DtlsUpdateWindow(WOLFSSL* ssl);
 #endif
 
@@ -129,4 +142,7 @@
 
 
+#ifndef WOLFSSL_NO_TLS12
+#if !defined(NO_WOLFSSL_SERVER) || !defined(NO_WOLFSSL_CLIENT)
+
 /* Server random bytes for TLS v1.3 described downgrade protection mechanism. */
 static const byte tls13Downgrade[7] = {
@@ -135,10 +151,13 @@
 #define TLS13_DOWNGRADE_SZ  sizeof(tls13Downgrade)
 
-
-#ifndef NO_OLD_TLS
+#endif /* !NO_WOLFSSL_SERVER || !NO_WOLFSSL_CLIENT */
+
+#if !defined(NO_OLD_TLS) && !defined(WOLFSSL_AEAD_ONLY)
 static int SSL_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz,
-                    int content, int verify);
-
-#endif
+                    int padSz, int content, int verify);
+
+#endif
+
+#endif /* !WOLFSSL_NO_TLS12 */
 
 #ifdef HAVE_QSH
@@ -160,6 +179,8 @@
     if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor >=TLSv1_2_MINOR)
         return 1;
+#ifdef WOLFSSL_DTLS
     if (ssl->version.major == DTLS_MAJOR && ssl->version.minor <= DTLSv1_2_MINOR)
         return 1;
+#endif
 
     return 0;
@@ -171,6 +192,5 @@
 }
 
-
-static INLINE int IsEncryptionOn(WOLFSSL* ssl, int isSend)
+static WC_INLINE int IsEncryptionOn(WOLFSSL* ssl, int isSend)
 {
     (void)isSend;
@@ -186,7 +206,8 @@
 
 
+#if defined(WOLFSSL_DTLS) || !defined(WOLFSSL_NO_TLS12)
 /* If SCTP is not enabled returns the state of the dtls option.
  * If SCTP is enabled returns dtls && !sctp. */
-static INLINE int IsDtlsNotSctpMode(WOLFSSL* ssl)
+static WC_INLINE int IsDtlsNotSctpMode(WOLFSSL* ssl)
 {
     int result = ssl->options.dtls;
@@ -200,4 +221,5 @@
     return result;
 }
+#endif /* DTLS || !WOLFSSL_NO_TLS12 */
 
 
@@ -524,6 +546,11 @@
 #endif
     exp[idx++] = sz;
+#ifndef WOLFSSL_AEAD_ONLY
     XMEMCPY(exp + idx, keys->client_write_MAC_secret, sz); idx += sz;
     XMEMCPY(exp + idx, keys->server_write_MAC_secret, sz); idx += sz;
+#else
+    XMEMSET(exp + idx, 0, sz); idx += sz;
+    XMEMSET(exp + idx, 0, sz); idx += sz;
+#endif
 
     sz         = ssl->specs.key_size;
@@ -682,12 +709,19 @@
 #endif
     sz = exp[idx++];
-    if (sz > MAX_DIGEST_SIZE || sz + idx > len) {
+#ifndef WOLFSSL_AEAD_ONLY
+    if (sz > sizeof(keys->client_write_MAC_secret) || sz + idx > len) {
         return BUFFER_E;
     }
     XMEMCPY(keys->client_write_MAC_secret, exp + idx, sz); idx += sz;
     XMEMCPY(keys->server_write_MAC_secret, exp + idx, sz); idx += sz;
+#else
+    if (sz + idx > len) {
+        return BUFFER_E;
+    }
+    idx += sz; idx += sz;
+#endif
 
     sz = exp[idx++];
-    if (sz > AES_256_KEY_SIZE || sz + idx > len) {
+    if (sz > sizeof(keys->client_write_key) || sz + idx > len) {
         return BUFFER_E;
     }
@@ -696,5 +730,5 @@
 
     sz = exp[idx++];
-    if (sz > MAX_WRITE_IV_SZ || sz + idx > len) {
+    if (sz > sizeof(keys->client_write_IV) || sz + idx > len) {
         return BUFFER_E;
     }
@@ -705,5 +739,5 @@
 
     sz = exp[idx++];
-    if (sz > AEAD_MAX_IMP_SZ || sz + idx > len) {
+    if (sz > sizeof(keys->aead_enc_imp_IV) || sz + idx > len) {
         return BUFFER_E;
     }
@@ -741,6 +775,8 @@
 #ifndef NO_DH
     c16toa(options->minDhKeySz, exp + idx); idx += OPAQUE16_LEN;
+    c16toa(options->maxDhKeySz, exp + idx); idx += OPAQUE16_LEN;
     c16toa(options->dhKeySz, exp + idx);    idx += OPAQUE16_LEN;
 #else
+    c16toa(zero, exp + idx); idx += OPAQUE16_LEN;
     c16toa(zero, exp + idx); idx += OPAQUE16_LEN;
     c16toa(zero, exp + idx); idx += OPAQUE16_LEN;
@@ -904,6 +940,8 @@
 #ifndef NO_DH
     ato16(exp + idx, &(options->minDhKeySz)); idx += OPAQUE16_LEN;
+    ato16(exp + idx, &(options->maxDhKeySz)); idx += OPAQUE16_LEN;
     ato16(exp + idx, &(options->dhKeySz));    idx += OPAQUE16_LEN;
 #else
+    idx += OPAQUE16_LEN;
     idx += OPAQUE16_LEN;
     idx += OPAQUE16_LEN;
@@ -1312,6 +1350,7 @@
     }
 
-    /* do not allow stream ciphers with DTLS */
-    if (ssl->specs.cipher_type == stream) {
+    /* do not allow stream ciphers with DTLS, except for NULL cipher */
+    if (ssl->specs.cipher_type == stream &&
+        ssl->specs.bulk_cipher_algorithm != wolfssl_cipher_null) {
         WOLFSSL_MSG("Can not import stream ciphers for DTLS");
         return SANITY_CIPHER_E;
@@ -1331,4 +1370,49 @@
 }
 
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
+int InitSSL_Side(WOLFSSL* ssl, word16 side)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    /* set side */
+    ssl->options.side = side;
+
+    /* reset options that are side specific */
+#ifdef HAVE_NTRU
+    if (ssl->options.side == WOLFSSL_CLIENT_END) {
+        ssl->options.haveNTRU = 1;      /* always on client side */
+                                        /* server can turn on by loading key */
+    }
+#endif
+#ifdef HAVE_ECC
+    if (ssl->options.side == WOLFSSL_CLIENT_END) {
+        ssl->options.haveECDSAsig  = 1; /* always on client side */
+        ssl->options.haveECC = 1;       /* server turns on with ECC key cert */
+        ssl->options.haveStaticECC = 1; /* server can turn on by loading key */
+    }
+#elif defined(HAVE_ED25519)
+    if (ssl->options.side == WOLFSSL_CLIENT_END) {
+        ssl->options.haveECDSAsig  = 1; /* always on client side */
+        ssl->options.haveECC  = 1;      /* server turns on with ECC key cert */
+    }
+#endif
+
+#if defined(HAVE_EXTENDED_MASTER) && !defined(NO_WOLFSSL_CLIENT)
+    if (ssl->options.side == WOLFSSL_CLIENT_END) {
+        if ((ssl->ctx->method->version.major == SSLv3_MAJOR) &&
+             (ssl->ctx->method->version.minor >= TLSv1_MINOR)) {
+            ssl->options.haveEMS = 1;
+        }
+    #ifdef WOLFSSL_DTLS
+        if (ssl->ctx->method->version.major == DTLS_MAJOR)
+            ssl->options.haveEMS = 1;
+    #endif /* WOLFSSL_DTLS */
+    }
+#endif /* HAVE_EXTENDED_MASTER && !NO_WOLFSSL_CLIENT */
+
+    return InitSSL_Suites(ssl);
+}
+#endif /* OPENSSL_EXTRA || WOLFSSL_EITHER_SIDE */
 
 /* Initialize SSL context, return 0 on success */
@@ -1343,5 +1427,5 @@
     ctx->heap     = ctx;        /* defaults to self */
     ctx->timeout  = WOLFSSL_SESSION_TIMEOUT;
-    ctx->minDowngrade = TLSv1_MINOR;     /* current default */
+    ctx->minDowngrade = WOLFSSL_MIN_DOWNGRADE; /* current default: TLSv1_MINOR */
 
     if (wc_InitMutex(&ctx->countMutex) < 0) {
@@ -1353,4 +1437,5 @@
 #ifndef NO_DH
     ctx->minDhKeySz  = MIN_DHKEY_SZ;
+    ctx->maxDhKeySz  = MAX_DHKEY_SZ;
 #endif
 #ifndef NO_RSA
@@ -1363,4 +1448,5 @@
 #ifdef OPENSSL_EXTRA
     ctx->verifyDepth = MAX_CHAIN_DEPTH;
+    ctx->cbioFlag = WOLFSSL_CBIO_NONE;
 #endif
 
@@ -1378,4 +1464,13 @@
             #endif
         #endif
+    #elif defined WOLFSSL_UIP
+        ctx->CBIORecv = uIPReceive;
+        ctx->CBIOSend = uIPSend;
+        #ifdef WOLFSSL_DTLS
+        if (method->version.major == DTLS_MAJOR) {
+            ctx->CBIOSendTo = uIPSendTo;
+            ctx->CBIORecvFrom = uIPRecvFrom;
+        }
+        #endif
     #else
         ctx->CBIORecv = EmbedReceive;
@@ -1397,16 +1492,24 @@
     ctx->CBIORecv = NetX_Receive;
     ctx->CBIOSend = NetX_Send;
+#elif defined(WOLFSSL_APACHE_MYNEWT) && !defined(WOLFSSL_LWIP)
+    ctx->CBIORecv = Mynewt_Receive;
+    ctx->CBIOSend = Mynewt_Send;
 #endif
 
 #ifdef HAVE_NTRU
     if (method->side == WOLFSSL_CLIENT_END)
-        ctx->haveNTRU = 1;           /* always on cliet side */
+        ctx->haveNTRU = 1;           /* always on client side */
                                      /* server can turn on by loading key */
 #endif
 #ifdef HAVE_ECC
     if (method->side == WOLFSSL_CLIENT_END) {
-        ctx->haveECDSAsig  = 1;        /* always on cliet side */
+        ctx->haveECDSAsig  = 1;        /* always on client side */
         ctx->haveECC  = 1;             /* server turns on with ECC key cert */
         ctx->haveStaticECC = 1;        /* server can turn on by loading key */
+    }
+#elif defined(HAVE_ED25519)
+    if (method->side == WOLFSSL_CLIENT_END) {
+        ctx->haveECDSAsig  = 1;        /* always on client side */
+        ctx->haveECC  = 1;             /* server turns on with ECC key cert */
     }
 #endif
@@ -1457,4 +1560,5 @@
 
     ctx->heap = heap; /* wolfSSL_CTX_load_static_memory sets */
+    ctx->verifyDepth = MAX_CHAIN_DEPTH;
 
     return ret;
@@ -1474,10 +1578,15 @@
 
     XFREE(ctx->method, ctx->heap, DYNAMIC_TYPE_METHOD);
-    if (ctx->suites)
+    ctx->method = NULL;
+    if (ctx->suites) {
         XFREE(ctx->suites, ctx->heap, DYNAMIC_TYPE_SUITES);
+        ctx->suites = NULL;
+    }
 
 #ifndef NO_DH
     XFREE(ctx->serverDH_G.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+    ctx->serverDH_G.buffer = NULL;
     XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+    ctx->serverDH_P.buffer = NULL;
 #endif /* !NO_DH */
 
@@ -1486,4 +1595,5 @@
         wc_FreeRng(ctx->rng);
         XFREE(ctx->rng, ctx->heap, DYNAMIC_TYPE_RNG);
+        ctx->rng = NULL;
     }
 #endif /* SINGLE_THREADED */
@@ -1496,18 +1606,24 @@
             FreeX509(ctx->ourCert);
             XFREE(ctx->ourCert, ctx->heap, DYNAMIC_TYPE_X509);
+            ctx->ourCert = NULL;
         }
     #endif /* KEEP_OUR_CERT */
     FreeDer(&ctx->certChain);
     wolfSSL_CertManagerFree(ctx->cm);
+    ctx->cm = NULL;
     #ifdef OPENSSL_EXTRA
+	/* ctx->cm was free'd so cm of x509 store should now be NULL */
+        if (ctx->x509_store_pt != NULL) {
+            ctx->x509_store_pt->cm = NULL;
+        }
+        wolfSSL_X509_STORE_free(ctx->x509_store_pt);
         while (ctx->ca_names != NULL) {
             WOLFSSL_STACK *next = ctx->ca_names->next;
             wolfSSL_X509_NAME_free(ctx->ca_names->data.name);
-            XFREE(ctx->ca_names->data.name, NULL, DYNAMIC_TYPE_OPENSSL);
             XFREE(ctx->ca_names, NULL, DYNAMIC_TYPE_OPENSSL);
             ctx->ca_names = next;
         }
     #endif
-    #if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+    #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
         while (ctx->x509Chain != NULL) {
             WOLFSSL_STACK *next = ctx->x509Chain->next;
@@ -1536,4 +1652,5 @@
             FreeOcspRequest(ctx->chainOcspRequest[i]);
             XFREE(ctx->chainOcspRequest[i], ctx->heap, DYNAMIC_TYPE_OCSP_REQUEST);
+            ctx->chainOcspRequest[i] = NULL;
         }
     }
@@ -1542,5 +1659,10 @@
 
 #endif /* HAVE_TLS_EXTENSIONS */
-
+#ifdef OPENSSL_EXTRA
+    if(ctx->alpn_cli_protos) {
+        XFREE((void *)ctx->alpn_cli_protos, NULL, DYNAMIC_TYPE_OPENSSL);
+        ctx->alpn_cli_protos = NULL;
+    }
+#endif
 #ifdef WOLFSSL_STATIC_MEMORY
     if (ctx->heap != NULL) {
@@ -1622,5 +1744,5 @@
     ssl->decrypt.chacha = NULL;
 #endif
-#ifdef HAVE_POLY1305
+#if defined(HAVE_POLY1305) && defined(HAVE_ONE_TIME_AUTH)
     ssl->auth.poly1305 = NULL;
 #endif
@@ -1681,5 +1803,5 @@
     XFREE(ssl->decrypt.chacha, ssl->heap, DYNAMIC_TYPE_CIPHER);
 #endif
-#ifdef HAVE_POLY1305
+#if defined(HAVE_POLY1305) && defined(HAVE_ONE_TIME_AUTH)
     XFREE(ssl->auth.poly1305, ssl->heap, DYNAMIC_TYPE_CIPHER);
 #endif
@@ -1693,4 +1815,6 @@
 void InitCipherSpecs(CipherSpecs* cs)
 {
+    XMEMSET(cs, 0, sizeof(CipherSpecs));
+
     cs->bulk_cipher_algorithm = INVALID_BYTE;
     cs->cipher_type           = INVALID_BYTE;
@@ -1698,10 +1822,4 @@
     cs->kea                   = INVALID_BYTE;
     cs->sig_algo              = INVALID_BYTE;
-
-    cs->hash_size   = 0;
-    cs->static_ecdh = 0;
-    cs->key_size    = 0;
-    cs->iv_size     = 0;
-    cs->block_size  = 0;
 }
 
@@ -1714,5 +1832,7 @@
     (void)keySz;
 
+#if defined(HAVE_ECC) || defined(HAVE_ED25519)
     if (haveECDSAsig) {
+    #ifdef HAVE_ECC
         #ifdef WOLFSSL_SHA512
             suites->hashSigAlgo[idx++] = sha512_mac;
@@ -1732,4 +1852,5 @@
             suites->hashSigAlgo[idx++] = ecc_dsa_sa_algo;
         #endif
+    #endif
         #ifdef HAVE_ED25519
             suites->hashSigAlgo[idx++] = ED25519_SA_MAJOR;
@@ -1737,4 +1858,5 @@
         #endif
     }
+#endif /* HAVE_ECC || HAVE_ED25519 */
 
     if (haveRSAsig) {
@@ -1742,14 +1864,10 @@
             if (tls1_2) {
             #ifdef WOLFSSL_SHA512
-                if (keySz >= MIN_RSA_SHA512_PSS_BITS) {
                     suites->hashSigAlgo[idx++] = rsa_pss_sa_algo;
                     suites->hashSigAlgo[idx++] = sha512_mac;
-                }
             #endif
             #ifdef WOLFSSL_SHA384
-                if (keySz >= MIN_RSA_SHA384_PSS_BITS) {
                   suites->hashSigAlgo[idx++] = rsa_pss_sa_algo;
                   suites->hashSigAlgo[idx++] = sha384_mac;
-                }
             #endif
             #ifndef NO_SHA256
@@ -1778,11 +1896,13 @@
     }
 
+        #ifdef HAVE_ANON
     if (haveAnon) {
-        #ifdef HAVE_ANON
             suites->hashSigAlgo[idx++] = sha_mac;
             suites->hashSigAlgo[idx++] = anonymous_sa_algo;
-        #endif
-    }
-
+    }
+#endif
+
+    (void)haveAnon;
+    (void)haveECDSAsig;
     suites->hashSigAlgoSz = (word16)idx;
 }
@@ -1810,4 +1930,7 @@
     (void)haveStaticECC;
     (void)haveECC;
+    (void)side;
+    (void)haveRSA;    /* some builds won't read */
+    (void)haveRSAsig; /* non ecc builds won't read */
 
     if (suites == NULL) {
@@ -1819,13 +1942,52 @@
         return;      /* trust user settings, don't override */
 
+#ifdef WOLFSSL_TLS13
+#ifdef BUILD_TLS_AES_128_GCM_SHA256
+    if (tls1_3) {
+        suites->suites[idx++] = TLS13_BYTE;
+        suites->suites[idx++] = TLS_AES_128_GCM_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_AES_256_GCM_SHA384
+    if (tls1_3) {
+        suites->suites[idx++] = TLS13_BYTE;
+        suites->suites[idx++] = TLS_AES_256_GCM_SHA384;
+    }
+#endif
+
+#ifdef BUILD_TLS_CHACHA20_POLY1305_SHA256
+    if (tls1_3) {
+        suites->suites[idx++] = TLS13_BYTE;
+        suites->suites[idx++] = TLS_CHACHA20_POLY1305_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_AES_128_CCM_SHA256
+    if (tls1_3) {
+        suites->suites[idx++] = TLS13_BYTE;
+        suites->suites[idx++] = TLS_AES_128_CCM_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_AES_128_CCM_8_SHA256
+    if (tls1_3) {
+        suites->suites[idx++] = TLS13_BYTE;
+        suites->suites[idx++] = TLS_AES_128_CCM_8_SHA256;
+    }
+#endif
+#endif /* WOLFSSL_TLS13 */
+
+#ifndef WOLFSSL_NO_TLS12
+
+#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_RSA)
     if (side == WOLFSSL_SERVER_END && haveStaticECC) {
         haveRSA = 0;   /* can't do RSA with ECDSA key */
-        (void)haveRSA; /* some builds won't read */
     }
 
     if (side == WOLFSSL_SERVER_END && haveECDSAsig) {
         haveRSAsig = 0;     /* can't have RSA sig if signed by ECDSA */
-        (void)haveRSAsig;   /* non ecc builds won't read */
-    }
+    }
+#endif /* !NO_WOLFSSL_SERVER */
 
 #ifdef WOLFSSL_DTLS
@@ -1842,5 +2004,5 @@
 #ifdef HAVE_RENEGOTIATION_INDICATION
     if (side == WOLFSSL_CLIENT_END) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_EMPTY_RENEGOTIATION_INFO_SCSV;
     }
@@ -1856,5 +2018,5 @@
 #ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
    if (tls && haveNTRU && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_NTRU_RSA_WITH_AES_256_CBC_SHA;
    }
@@ -1863,5 +2025,5 @@
 #ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
     if (tls && haveNTRU && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_NTRU_RSA_WITH_AES_128_CBC_SHA;
     }
@@ -1870,5 +2032,5 @@
 #ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA
     if (!dtls && tls && haveNTRU && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_NTRU_RSA_WITH_RC4_128_SHA;
     }
@@ -1877,45 +2039,8 @@
 #ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA
     if (tls && haveNTRU && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA;
     }
 #endif
-
-#ifdef WOLFSSL_TLS13
-#ifdef BUILD_TLS_AES_128_GCM_SHA256
-    if (tls1_3) {
-        suites->suites[idx++] = TLS13_BYTE;
-        suites->suites[idx++] = TLS_AES_128_GCM_SHA256;
-    }
-#endif
-
-#ifdef BUILD_TLS_AES_256_GCM_SHA384
-    if (tls1_3) {
-        suites->suites[idx++] = TLS13_BYTE;
-        suites->suites[idx++] = TLS_AES_256_GCM_SHA384;
-    }
-#endif
-
-#ifdef BUILD_TLS_CHACHA20_POLY1305_SHA256
-    if (tls1_3) {
-        suites->suites[idx++] = TLS13_BYTE;
-        suites->suites[idx++] = TLS_CHACHA20_POLY1305_SHA256;
-    }
-#endif
-
-#ifdef BUILD_TLS_AES_128_CCM_SHA256
-    if (tls1_3) {
-        suites->suites[idx++] = TLS13_BYTE;
-        suites->suites[idx++] = TLS_AES_128_CCM_SHA256;
-    }
-#endif
-
-#ifdef BUILD_TLS_AES_128_CCM_8_SHA256
-    if (tls1_3) {
-        suites->suites[idx++] = TLS13_BYTE;
-        suites->suites[idx++] = TLS_AES_128_CCM_8_SHA256;
-    }
-#endif
-#endif /* WOLFSSL_TLS13 */
 
 #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
@@ -1949,5 +2074,5 @@
 #ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
     if (tls1_2 && haveDH && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_GCM_SHA384;
     }
@@ -1956,5 +2081,5 @@
 #ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
     if (tls1_2 && haveDH && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_128_GCM_SHA256;
     }
@@ -1963,5 +2088,5 @@
 #ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384
     if (tls1_2 && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_RSA_WITH_AES_256_GCM_SHA384;
     }
@@ -1970,5 +2095,5 @@
 #ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256
     if (tls1_2 && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_RSA_WITH_AES_128_GCM_SHA256;
     }
@@ -2005,6 +2130,20 @@
 #ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384
     if (tls1_2 && haveDH && havePSK) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_DHE_PSK_WITH_AES_256_GCM_SHA384;
+    }
+#endif
+
+#ifdef BUILD_TLS_DH_anon_WITH_AES_128_CBC_SHA
+    if (tls1_2 && haveDH) {
+      suites->suites[idx++] = CIPHER_BYTE;
+      suites->suites[idx++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_DH_anon_WITH_AES_256_GCM_SHA384
+    if (tls1_2 && haveDH) {
+      suites->suites[idx++] = CIPHER_BYTE;
+      suites->suites[idx++] = TLS_DH_anon_WITH_AES_256_GCM_SHA384;
     }
 #endif
@@ -2012,5 +2151,5 @@
 #ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256
     if (tls1_2 && haveDH && havePSK) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_DHE_PSK_WITH_AES_128_GCM_SHA256;
     }
@@ -2019,5 +2158,5 @@
 #ifdef BUILD_TLS_PSK_WITH_AES_256_GCM_SHA384
     if (tls1_2 && havePSK) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_PSK_WITH_AES_256_GCM_SHA384;
     }
@@ -2026,5 +2165,5 @@
 #ifdef BUILD_TLS_PSK_WITH_AES_128_GCM_SHA256
     if (tls1_2 && havePSK) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_PSK_WITH_AES_128_GCM_SHA256;
     }
@@ -2056,5 +2195,5 @@
 #ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
     if (tls && haveDH && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
     }
@@ -2267,5 +2406,5 @@
 #ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
     if (tls && haveDH && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
     }
@@ -2274,5 +2413,5 @@
 #ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
     if (tls && haveDH && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
     }
@@ -2283,5 +2422,5 @@
 #ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
     if (tls && haveDH && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
     }
@@ -2291,5 +2430,5 @@
 #ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
     if (tls && haveDH && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
     }
@@ -2298,5 +2437,5 @@
 #ifdef BUILD_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
     if (tls && haveDH && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
     }
@@ -2305,5 +2444,5 @@
 #ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256
     if (tls && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_RSA_WITH_AES_256_CBC_SHA256;
     }
@@ -2312,5 +2451,5 @@
 #ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256
     if (tls && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
     }
@@ -2319,5 +2458,5 @@
 #ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA
     if (tls && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_RSA_WITH_AES_256_CBC_SHA;
     }
@@ -2326,5 +2465,5 @@
 #ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA
     if (tls && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_RSA_WITH_AES_128_CBC_SHA;
     }
@@ -2362,5 +2501,5 @@
 #ifdef BUILD_TLS_RSA_WITH_NULL_SHA
     if (tls && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_RSA_WITH_NULL_SHA;
     }
@@ -2369,5 +2508,5 @@
 #ifdef BUILD_TLS_RSA_WITH_NULL_SHA256
     if (tls && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_RSA_WITH_NULL_SHA256;
     }
@@ -2376,5 +2515,5 @@
 #ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA
     if (tls && havePSK) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_PSK_WITH_AES_256_CBC_SHA;
     }
@@ -2383,5 +2522,5 @@
 #ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384
     if (tls && haveDH && havePSK) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_DHE_PSK_WITH_AES_256_CBC_SHA384;
     }
@@ -2390,5 +2529,5 @@
 #ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA384
     if (tls && havePSK) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_PSK_WITH_AES_256_CBC_SHA384;
     }
@@ -2397,5 +2536,5 @@
 #ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256
     if (tls && haveDH && havePSK) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_DHE_PSK_WITH_AES_128_CBC_SHA256;
     }
@@ -2404,5 +2543,5 @@
 #ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA256
     if (tls && havePSK) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_PSK_WITH_AES_128_CBC_SHA256;
     }
@@ -2411,5 +2550,5 @@
 #ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA
     if (tls && havePSK) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_PSK_WITH_AES_128_CBC_SHA;
     }
@@ -2488,5 +2627,5 @@
 #ifdef BUILD_TLS_DHE_PSK_WITH_NULL_SHA384
     if (tls && haveDH && havePSK) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_DHE_PSK_WITH_NULL_SHA384;
     }
@@ -2495,5 +2634,5 @@
 #ifdef BUILD_TLS_PSK_WITH_NULL_SHA384
     if (tls && havePSK) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_PSK_WITH_NULL_SHA384;
     }
@@ -2509,5 +2648,5 @@
 #ifdef BUILD_TLS_DHE_PSK_WITH_NULL_SHA256
     if (tls && haveDH && havePSK) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_DHE_PSK_WITH_NULL_SHA256;
     }
@@ -2516,5 +2655,5 @@
 #ifdef BUILD_TLS_PSK_WITH_NULL_SHA256
     if (tls && havePSK) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_PSK_WITH_NULL_SHA256;
     }
@@ -2523,5 +2662,5 @@
 #ifdef BUILD_TLS_PSK_WITH_NULL_SHA
     if (tls && havePSK) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_PSK_WITH_NULL_SHA;
     }
@@ -2530,5 +2669,5 @@
 #ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA
     if (!dtls && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = SSL_RSA_WITH_RC4_128_SHA;
     }
@@ -2537,5 +2676,5 @@
 #ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5
     if (!dtls && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = SSL_RSA_WITH_RC4_128_MD5;
     }
@@ -2544,5 +2683,5 @@
 #ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA
     if (haveRSA ) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = SSL_RSA_WITH_3DES_EDE_CBC_SHA;
     }
@@ -2551,5 +2690,5 @@
 #ifdef BUILD_TLS_RSA_WITH_HC_128_MD5
     if (!dtls && tls && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_RSA_WITH_HC_128_MD5;
     }
@@ -2558,5 +2697,5 @@
 #ifdef BUILD_TLS_RSA_WITH_HC_128_SHA
     if (!dtls && tls && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_RSA_WITH_HC_128_SHA;
     }
@@ -2565,5 +2704,5 @@
 #ifdef BUILD_TLS_RSA_WITH_HC_128_B2B256
     if (!dtls && tls && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_RSA_WITH_HC_128_B2B256;
     }
@@ -2572,5 +2711,5 @@
 #ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256
     if (tls && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_RSA_WITH_AES_128_CBC_B2B256;
     }
@@ -2579,5 +2718,5 @@
 #ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256
     if (tls && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_RSA_WITH_AES_256_CBC_B2B256;
     }
@@ -2586,5 +2725,5 @@
 #ifdef BUILD_TLS_RSA_WITH_RABBIT_SHA
     if (!dtls && tls && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_RSA_WITH_RABBIT_SHA;
     }
@@ -2593,5 +2732,5 @@
 #ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
     if (tls && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_128_CBC_SHA;
     }
@@ -2600,5 +2739,5 @@
 #ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
     if (tls && haveDH && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA;
     }
@@ -2607,5 +2746,5 @@
 #ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
     if (tls && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_256_CBC_SHA;
     }
@@ -2614,5 +2753,5 @@
 #ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
     if (tls && haveDH && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA;
     }
@@ -2621,5 +2760,5 @@
 #ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
     if (tls && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256;
     }
@@ -2628,5 +2767,5 @@
 #ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
     if (tls && haveDH && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256;
     }
@@ -2635,5 +2774,5 @@
 #ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256
     if (tls && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256;
     }
@@ -2642,5 +2781,5 @@
 #ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
     if (tls && haveDH && haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256;
     }
@@ -2649,8 +2788,10 @@
 #ifdef BUILD_SSL_RSA_WITH_IDEA_CBC_SHA
     if (haveRSA) {
-        suites->suites[idx++] = 0;
+        suites->suites[idx++] = CIPHER_BYTE;
         suites->suites[idx++] = SSL_RSA_WITH_IDEA_CBC_SHA;
     }
 #endif
+
+#endif /* !WOLFSSL_NO_TLS12 */
 
     suites->suiteSz = idx;
@@ -2668,5 +2809,5 @@
  * hsType   The signature type.
  */
-static INLINE void DecodeSigAlg(const byte* input, byte* hashAlgo, byte* hsType)
+static WC_INLINE void DecodeSigAlg(const byte* input, byte* hashAlgo, byte* hsType)
 {
     switch (input[0]) {
@@ -2697,5 +2838,8 @@
 #endif /* !NO_WOLFSSL_SERVER || !NO_CERTS */
 
-#if !defined(NO_DH) || defined(HAVE_ECC)
+#ifndef WOLFSSL_NO_TLS12
+#if !defined(NO_WOLFSSL_SERVER) || !defined(NO_WOLFSSL_CLIENT)
+#if !defined(NO_DH) || defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \
+                                       (!defined(NO_RSA) && defined(WC_RSA_PSS))
 
 static enum wc_HashType HashAlgoToType(int hashAlgo)
@@ -2726,7 +2870,9 @@
     return WC_HASH_TYPE_NONE;
 }
+#endif /* !NO_DH || HAVE_ECC || (!NO_RSA && WC_RSA_PSS) */
+#endif /* !NO_WOLFSSL_SERVER || !NO_WOLFSSL_CLIENT */
+#endif /* !WOLFSSL_NO_TLS12 */
 
 #ifndef NO_CERTS
-
 
 void InitX509Name(WOLFSSL_X509_NAME* name, int dynamicFlag)
@@ -2737,8 +2883,11 @@
         name->name        = name->staticName;
         name->dynamicName = 0;
-#ifdef OPENSSL_EXTRA
+        name->sz = 0;
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
         XMEMSET(&name->fullName, 0, sizeof(DecodedName));
         XMEMSET(&name->cnEntry,  0, sizeof(WOLFSSL_X509_NAME_ENTRY));
+        XMEMSET(&name->extra,    0, sizeof(name->extra));
         name->cnEntry.value = &(name->cnEntry.data); /* point to internal data*/
+        name->cnEntry.nid = ASN_COMMON_NAME;
         name->x509 = NULL;
 #endif /* OPENSSL_EXTRA */
@@ -2752,8 +2901,20 @@
         if (name->dynamicName)
             XFREE(name->name, heap, DYNAMIC_TYPE_SUBJECT_CN);
-#ifdef OPENSSL_EXTRA
-        if (name->fullName.fullName != NULL)
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+        {
+            int i;
+            if (name->fullName.fullName != NULL) {
             XFREE(name->fullName.fullName, heap, DYNAMIC_TYPE_X509);
-#endif /* OPENSSL_EXTRA */
+                name->fullName.fullName = NULL;
+            }
+            for (i = 0; i < MAX_NAME_ENTRIES; i++) {
+                /* free ASN1 string data */
+                if (name->extra[i].set && name->extra[i].data.data != NULL) {
+                    XFREE(name->extra[i].data.data, heap, DYNAMIC_TYPE_OPENSSL);
+                }
+            }
+            wolfSSL_ASN1_OBJECT_free(&name->cnEntry.object);
+        }
+#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
     }
     (void)heap;
@@ -2774,38 +2935,5 @@
     InitX509Name(&x509->issuer, 0);
     InitX509Name(&x509->subject, 0);
-    x509->version        = 0;
-    x509->pubKey.buffer  = NULL;
-    x509->sig.buffer     = NULL;
-    x509->derCert        = NULL;
-    x509->altNames       = NULL;
-    x509->altNamesNext   = NULL;
     x509->dynamicMemory  = (byte)dynamicFlag;
-    x509->isCa           = 0;
-#ifdef HAVE_ECC
-    x509->pkCurveOID = 0;
-#endif /* HAVE_ECC */
-#ifdef OPENSSL_EXTRA
-    x509->pathLength     = 0;
-    x509->basicConstSet  = 0;
-    x509->basicConstCrit = 0;
-    x509->basicConstPlSet = 0;
-    x509->subjAltNameSet = 0;
-    x509->subjAltNameCrit = 0;
-    x509->authKeyIdSet   = 0;
-    x509->authKeyIdCrit  = 0;
-    x509->authKeyId      = NULL;
-    x509->authKeyIdSz    = 0;
-    x509->subjKeyIdSet   = 0;
-    x509->subjKeyIdCrit  = 0;
-    x509->subjKeyId      = NULL;
-    x509->subjKeyIdSz    = 0;
-    x509->keyUsageSet    = 0;
-    x509->keyUsageCrit   = 0;
-    x509->keyUsage       = 0;
-    #ifdef WOLFSSL_SEP
-        x509->certPolicySet  = 0;
-        x509->certPolicyCrit = 0;
-    #endif /* WOLFSSL_SEP */
-#endif /* OPENSSL_EXTRA */
 }
 
@@ -2823,5 +2951,5 @@
     FreeDer(&x509->derCert);
     XFREE(x509->sig.buffer, x509->heap, DYNAMIC_TYPE_SIGNATURE);
-    #ifdef OPENSSL_EXTRA
+    #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
         XFREE(x509->authKeyId, x509->heap, DYNAMIC_TYPE_X509_EXT);
         XFREE(x509->subjKeyId, x509->heap, DYNAMIC_TYPE_X509_EXT);
@@ -2832,12 +2960,12 @@
             XFREE(x509->extKeyUsageSrc, x509->heap, DYNAMIC_TYPE_X509_EXT);
         }
-    #endif /* OPENSSL_EXTRA */
+    #endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
     if (x509->altNames)
-        FreeAltNames(x509->altNames, NULL);
+        FreeAltNames(x509->altNames, x509->heap);
 }
 
-#endif /* !NO_DH || HAVE_ECC */
-
-#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519)
+
+#if !defined(NO_WOLFSSL_SERVER) || !defined(NO_WOLFSSL_CLIENT)
+#if !defined(WOLFSSL_NO_TLS12) && !defined(WOLFSSL_NO_CLIENT_AUTH)
 /* Encode the signature algorithm into buffer.
  *
@@ -2846,5 +2974,5 @@
  * output    The buffer to encode into.
  */
-static INLINE void EncodeSigAlg(byte hashAlgo, byte hsType, byte* output)
+static WC_INLINE void EncodeSigAlg(byte hashAlgo, byte hsType, byte* output)
 {
     switch (hsType) {
@@ -2877,5 +3005,8 @@
         /* ED448: 0x0808 */
     }
+    (void)hashAlgo;
+    (void)output;
 }
+
 static void SetDigest(WOLFSSL* ssl, int hashAlgo)
 {
@@ -2907,7 +3038,11 @@
     } /* switch */
 }
-#endif
+#endif /* !WOLFSSL_NO_TLS12 && !WOLFSSL_NO_CLIENT_AUTH */
+#endif /* !NO_WOLFSSL_SERVER || !NO_WOLFSSL_CLIENT */
+#endif /* !NO_CERTS */
 
 #ifndef NO_RSA
+#ifndef WOLFSSL_NO_TLS12
+#if !defined(NO_WOLFSSL_SERVER) || !defined(NO_WOLFSSL_CLIENT)
 static int TypeHash(int hashAlgo)
 {
@@ -2933,4 +3068,6 @@
     return 0;
 }
+#endif /* !NO_WOLFSSL_SERVER && !NO_WOLFSSL_CLIENT */
+#endif /* !WOLFSSL_NO_TLS12 */
 
 #if defined(WC_RSA_PSS)
@@ -2969,12 +3106,19 @@
 int RsaSign(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out,
             word32* outSz, int sigAlgo, int hashAlgo, RsaKey* key,
-            const byte* keyBuf, word32 keySz, void* ctx)
+            DerBuffer* keyBufInfo)
 {
     int ret;
+#ifdef HAVE_PK_CALLBACKS
+    const byte* keyBuf = NULL;
+    word32 keySz = 0;
+
+    if (keyBufInfo) {
+        keyBuf = keyBufInfo->buffer;
+        keySz = keyBufInfo->length;
+    }
+#endif
 
     (void)ssl;
-    (void)keyBuf;
-    (void)keySz;
-    (void)ctx;
+    (void)keyBufInfo;
     (void)sigAlgo;
     (void)hashAlgo;
@@ -2983,5 +3127,5 @@
 
 #ifdef WOLFSSL_ASYNC_CRYPT
-    /* intialize event */
+    /* initialize event */
     ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN);
     if (ret != 0)
@@ -3000,4 +3144,5 @@
     #if defined(HAVE_PK_CALLBACKS)
         if (ssl->ctx->RsaPssSignCb) {
+            void* ctx = wolfSSL_GetRsaPssSignCtx(ssl);
             ret = ssl->ctx->RsaPssSignCb(ssl, in, inSz, out, outSz,
                                          TypeHash(hashAlgo), mgf,
@@ -3015,4 +3160,5 @@
 #if defined(HAVE_PK_CALLBACKS)
     if (ssl->ctx->RsaSignCb) {
+        void* ctx = wolfSSL_GetRsaSignCtx(ssl);
         ret = ssl->ctx->RsaSignCb(ssl, in, inSz, out, outSz, keyBuf, keySz,
                                                                           ctx);
@@ -3041,13 +3187,19 @@
 
 int RsaVerify(WOLFSSL* ssl, byte* in, word32 inSz, byte** out, int sigAlgo,
-              int hashAlgo, RsaKey* key, const byte* keyBuf, word32 keySz,
-              void* ctx)
+              int hashAlgo, RsaKey* key, buffer* keyBufInfo)
 {
     int ret;
+#ifdef HAVE_PK_CALLBACKS
+    const byte* keyBuf = NULL;
+    word32 keySz = 0;
+
+    if (keyBufInfo) {
+        keyBuf = keyBufInfo->buffer;
+        keySz = keyBufInfo->length;
+    }
+#endif
 
     (void)ssl;
-    (void)keyBuf;
-    (void)keySz;
-    (void)ctx;
+    (void)keyBufInfo;
     (void)sigAlgo;
     (void)hashAlgo;
@@ -3056,5 +3208,5 @@
 
 #ifdef WOLFSSL_ASYNC_CRYPT
-    /* intialize event */
+    /* initialize event */
     ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN);
     if (ret != 0)
@@ -3072,4 +3224,5 @@
 #ifdef HAVE_PK_CALLBACKS
         if (ssl->ctx->RsaPssVerifyCb) {
+            void* ctx = wolfSSL_GetRsaPssVerifyCtx(ssl);
             ret = ssl->ctx->RsaPssVerifyCb(ssl, in, inSz, out,
                                            TypeHash(hashAlgo), mgf,
@@ -3084,4 +3237,5 @@
 #ifdef HAVE_PK_CALLBACKS
     if (ssl->ctx->RsaVerifyCb) {
+        void* ctx = wolfSSL_GetRsaVerifyCtx(ssl);
         ret = ssl->ctx->RsaVerifyCb(ssl, in, inSz, out, keyBuf, keySz, ctx);
     }
@@ -3105,11 +3259,23 @@
 
 /* Verify RSA signature, 0 on success */
+/* This function is used to check the sign result */
 int VerifyRsaSign(WOLFSSL* ssl, byte* verifySig, word32 sigSz,
-    const byte* plain, word32 plainSz, int sigAlgo, int hashAlgo, RsaKey* key)
+    const byte* plain, word32 plainSz, int sigAlgo, int hashAlgo, RsaKey* key,
+    DerBuffer* keyBufInfo)
 {
     byte* out = NULL;  /* inline result */
     int   ret;
+#ifdef HAVE_PK_CALLBACKS
+    const byte* keyBuf = NULL;
+    word32 keySz = 0;
+
+    if (keyBufInfo) {
+        keyBuf = keyBufInfo->buffer;
+        keySz = keyBufInfo->length;
+    }
+#endif
 
     (void)ssl;
+    (void)keyBufInfo;
     (void)sigAlgo;
     (void)hashAlgo;
@@ -3117,5 +3283,5 @@
     WOLFSSL_ENTER("VerifyRsaSign");
 
-    if (verifySig == NULL || plain == NULL || key == NULL) {
+    if (verifySig == NULL || plain == NULL) {
         return BAD_FUNC_ARG;
     }
@@ -3127,8 +3293,10 @@
 
 #ifdef WOLFSSL_ASYNC_CRYPT
-    /* intialize event */
+    /* initialize event */
+    if (key) {
     ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN);
     if (ret != 0)
         return ret;
+    }
 #endif
 
@@ -3141,6 +3309,23 @@
         if (ret != 0)
             return ret;
+    #ifdef HAVE_PK_CALLBACKS
+        if (ssl->ctx->RsaPssSignCheckCb) {
+            /* The key buffer includes private/public portion,
+                but only public is used */
+            /* If HSM hardware is checking the signature result you can
+                optionally skip the sign check and return 0 */
+            /* The ctx here is the RsaSignCtx set using wolfSSL_SetRsaSignCtx */
+            void* ctx = wolfSSL_GetRsaPssSignCtx(ssl);
+            ret = ssl->ctx->RsaPssSignCheckCb(ssl, verifySig, sigSz, &out,
+                                           TypeHash(hashAlgo), mgf,
+                                           keyBuf, keySz, ctx);
+        }
+        else
+    #endif /* HAVE_PK_CALLBACKS */
+        {
         ret = wc_RsaPSS_VerifyInline(verifySig, sigSz, &out, hashType, mgf,
                                                                            key);
+        }
+
         if (ret > 0) {
             ret = wc_RsaPSS_CheckPadding(plain, plainSz, out, ret, hashType);
@@ -3150,7 +3335,23 @@
     }
     else
-#endif
+#endif /* WC_RSA_PSS */
+    {
+    #ifdef HAVE_PK_CALLBACKS
+        if (ssl->ctx->RsaSignCheckCb) {
+            /* The key buffer includes private/public portion,
+                but only public is used */
+            /* If HSM hardware is checking the signature result you can
+                optionally skip the sign check and return 0 */
+            /* The ctx here is the RsaSignCtx set using wolfSSL_SetRsaSignCtx */
+            void* ctx = wolfSSL_GetRsaSignCtx(ssl);
+            ret = ssl->ctx->RsaSignCheckCb(ssl, verifySig, sigSz, &out,
+                keyBuf, keySz, ctx);
+        }
+        else
+    #endif /* HAVE_PK_CALLBACKS */
     {
         ret = wc_RsaSSL_VerifyInline(verifySig, sigSz, &out, key);
+        }
+
         if (ret > 0) {
             if (ret != (int)plainSz || !out ||
@@ -3166,5 +3367,5 @@
     /* Handle async pending response */
 #ifdef WOLFSSL_ASYNC_CRYPT
-    if (ret == WC_PENDING_E) {
+    if (key && ret == WC_PENDING_E) {
         ret = wolfSSL_AsyncPush(ssl, &key->asyncDev);
     }
@@ -3176,18 +3377,27 @@
 }
 
+#ifndef WOLFSSL_NO_TLS12
+
 int RsaDec(WOLFSSL* ssl, byte* in, word32 inSz, byte** out, word32* outSz,
-    RsaKey* key, const byte* keyBuf, word32 keySz, void* ctx)
+    RsaKey* key, DerBuffer* keyBufInfo)
 {
     int ret;
+#ifdef HAVE_PK_CALLBACKS
+    const byte* keyBuf = NULL;
+    word32 keySz = 0;
+
+    if (keyBufInfo) {
+        keyBuf = keyBufInfo->buffer;
+        keySz = keyBufInfo->length;
+    }
+#endif
 
     (void)ssl;
-    (void)keyBuf;
-    (void)keySz;
-    (void)ctx;
+    (void)keyBufInfo;
 
     WOLFSSL_ENTER("RsaDec");
 
 #ifdef WOLFSSL_ASYNC_CRYPT
-    /* intialize event */
+    /* initialize event */
     ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN);
     if (ret != 0)
@@ -3197,6 +3407,6 @@
 #ifdef HAVE_PK_CALLBACKS
     if (ssl->ctx->RsaDecCb) {
-            ret = ssl->ctx->RsaDecCb(ssl, in, inSz, out, keyBuf, keySz,
-                                                                    ctx);
+        void* ctx = wolfSSL_GetRsaDecCtx(ssl);
+        ret = ssl->ctx->RsaDecCb(ssl, in, inSz, out, keyBuf, keySz, ctx);
     }
     else
@@ -3230,17 +3440,24 @@
 
 int RsaEnc(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out, word32* outSz,
-    RsaKey* key, const byte* keyBuf, word32 keySz, void* ctx)
+    RsaKey* key, buffer* keyBufInfo)
 {
     int ret;
+#ifdef HAVE_PK_CALLBACKS
+    const byte* keyBuf = NULL;
+    word32 keySz = 0;
+
+    if (keyBufInfo) {
+        keyBuf = keyBufInfo->buffer;
+        keySz = keyBufInfo->length;
+    }
+#endif
 
     (void)ssl;
-    (void)keyBuf;
-    (void)keySz;
-    (void)ctx;
+    (void)keyBufInfo;
 
     WOLFSSL_ENTER("RsaEnc");
 
 #ifdef WOLFSSL_ASYNC_CRYPT
-    /* intialize event */
+    /* initialize event */
     ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN);
     if (ret != 0)
@@ -3250,6 +3467,6 @@
 #ifdef HAVE_PK_CALLBACKS
     if (ssl->ctx->RsaEncCb) {
-            ret = ssl->ctx->RsaEncCb(ssl, in, inSz, out, outSz, keyBuf, keySz,
-                                                                        ctx);
+        void* ctx = wolfSSL_GetRsaEncCtx(ssl);
+        ret = ssl->ctx->RsaEncCb(ssl, in, inSz, out, outSz, keyBuf, keySz, ctx);
     }
     else
@@ -3277,4 +3494,6 @@
 }
 
+#endif /* !WOLFSSL_NO_TLS12 */
+
 #endif /* NO_RSA */
 
@@ -3282,17 +3501,24 @@
 
 int EccSign(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out,
-    word32* outSz, ecc_key* key, byte* keyBuf, word32 keySz, void* ctx)
+    word32* outSz, ecc_key* key, DerBuffer* keyBufInfo)
 {
     int ret;
+#ifdef HAVE_PK_CALLBACKS
+    const byte* keyBuf = NULL;
+    word32 keySz = 0;
+
+    if (keyBufInfo) {
+        keyBuf = keyBufInfo->buffer;
+        keySz = keyBufInfo->length;
+    }
+#endif
 
     (void)ssl;
-    (void)keyBuf;
-    (void)keySz;
-    (void)ctx;
+    (void)keyBufInfo;
 
     WOLFSSL_ENTER("EccSign");
 
 #ifdef WOLFSSL_ASYNC_CRYPT
-    /* intialize event */
+    /* initialize event */
     ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN);
     if (ret != 0)
@@ -3302,4 +3528,5 @@
 #if defined(HAVE_PK_CALLBACKS)
     if (ssl->ctx->EccSignCb) {
+        void* ctx = wolfSSL_GetEccSignCtx(ssl);
         ret = ssl->ctx->EccSignCb(ssl, in, inSz, out, outSz, keyBuf,
             keySz, ctx);
@@ -3324,18 +3551,24 @@
 
 int EccVerify(WOLFSSL* ssl, const byte* in, word32 inSz, const byte* out,
-    word32 outSz, ecc_key* key, byte* keyBuf, word32 keySz,
-    void* ctx)
+    word32 outSz, ecc_key* key, buffer* keyBufInfo)
 {
     int ret;
+#ifdef HAVE_PK_CALLBACKS
+    const byte* keyBuf = NULL;
+    word32 keySz = 0;
+
+    if (keyBufInfo) {
+        keyBuf = keyBufInfo->buffer;
+        keySz = keyBufInfo->length;
+    }
+#endif
 
     (void)ssl;
-    (void)keyBuf;
-    (void)keySz;
-    (void)ctx;
+    (void)keyBufInfo;
 
     WOLFSSL_ENTER("EccVerify");
 
 #ifdef WOLFSSL_ASYNC_CRYPT
-    /* intialize event */
+    /* initialize event */
     ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN);
     if (ret != 0)
@@ -3345,4 +3578,5 @@
 #ifdef HAVE_PK_CALLBACKS
     if (ssl->ctx->EccVerifyCb) {
+        void* ctx = wolfSSL_GetEccVerifyCtx(ssl);
         ret = ssl->ctx->EccVerifyCb(ssl, in, inSz, out, outSz, keyBuf, keySz,
             &ssl->eccVerifyRes, ctx);
@@ -3426,5 +3660,5 @@
 int EccSharedSecret(WOLFSSL* ssl, ecc_key* priv_key, ecc_key* pub_key,
         byte* pubKeyDer, word32* pubKeySz, byte* out, word32* outlen,
-        int side, void* ctx)
+        int side)
 {
     int ret;
@@ -3440,5 +3674,4 @@
     (void)pubKeySz;
     (void)side;
-    (void)ctx;
 
     WOLFSSL_ENTER("EccSharedSecret");
@@ -3456,5 +3689,5 @@
 
 #ifdef WOLFSSL_ASYNC_CRYPT
-    /* intialize event */
+    /* initialize event */
     ret = wolfSSL_AsyncInit(ssl, asyncDev, WC_ASYNC_FLAG_CALL_AGAIN);
     if (ret != 0)
@@ -3464,4 +3697,5 @@
 #ifdef HAVE_PK_CALLBACKS
     if (ssl->ctx->EccSharedSecretCb) {
+        void* ctx = wolfSSL_GetEccSharedSecretCtx(ssl);
         ret = ssl->ctx->EccSharedSecretCb(ssl, otherKey, pubKeyDer,
             pubKeySz, out, outlen, side, ctx);
@@ -3489,9 +3723,10 @@
     int ret = 0;
     int keySz = 0;
+    int ecc_curve = ECC_CURVE_DEF;
 
     WOLFSSL_ENTER("EccMakeKey");
 
 #ifdef WOLFSSL_ASYNC_CRYPT
-    /* intialize event */
+    /* initialize event */
     ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_NONE);
     if (ret != 0)
@@ -3499,4 +3734,5 @@
 #endif
 
+    /* get key size */
     if (peer == NULL) {
         keySz = ssl->eccTempKeySz;
@@ -3506,11 +3742,22 @@
     }
 
+    /* get curve type */
     if (ssl->ecdhCurveOID > 0) {
-        ret = wc_ecc_make_key_ex(ssl->rng, keySz, key,
-                 wc_ecc_get_oid(ssl->ecdhCurveOID, NULL, NULL));
-    }
-    else {
-        ret = wc_ecc_make_key(ssl->rng, keySz, key);
-        if (ret == 0)
+        ecc_curve = wc_ecc_get_oid(ssl->ecdhCurveOID, NULL, NULL);
+    }
+
+#ifdef HAVE_PK_CALLBACKS
+    if (ssl->ctx->EccKeyGenCb) {
+        void* ctx = wolfSSL_GetEccKeyGenCtx(ssl);
+        ret = ssl->ctx->EccKeyGenCb(ssl, key, keySz, ecc_curve, ctx);
+    }
+    else
+#endif
+    {
+        ret = wc_ecc_make_key_ex(ssl->rng, keySz, key, ecc_curve);
+    }
+
+    /* make sure the curve is set for TLS */
+    if (ret == 0 && key->dp) {
             ssl->ecdhCurveOID = key->dp->oidSum;
     }
@@ -3530,4 +3777,41 @@
 
 #ifdef HAVE_ED25519
+/* Check whether the key contains a public key.
+ * If not then pull it out of the leaf certificate.
+ *
+ * ssl  SSL/TLS object.
+ * returns MEMORY_E when unable to allocate memory, a parsing error, otherwise
+ * 0 on success.
+ */
+int Ed25519CheckPubKey(WOLFSSL* ssl)
+{
+    ed25519_key* key = (ed25519_key*)ssl->hsKey;
+    int ret = 0;
+
+    /* Public key required for signing. */
+    if (!key->pubKeySet) {
+        DerBuffer* leaf = ssl->buffers.certificate;
+        DecodedCert* cert = (DecodedCert*)XMALLOC(sizeof(*cert),
+                                     ssl->heap, DYNAMIC_TYPE_DCERT);
+        if (cert == NULL)
+            ret = MEMORY_E;
+
+        if (ret == 0) {
+            InitDecodedCert(cert, leaf->buffer, leaf->length, ssl->heap);
+            ret = DecodeToKey(cert, 0);
+        }
+        if (ret == 0) {
+            ret = wc_ed25519_import_public(cert->publicKey, cert->pubKeySize,
+                                                                           key);
+        }
+        if (cert != NULL) {
+            FreeDecodedCert(cert);
+            XFREE(cert, ssl->heap, DYNAMIC_TYPE_DCERT);
+        }
+    }
+
+    return ret;
+}
+
 /* Sign the data using EdDSA and key using X25519.
  *
@@ -3540,21 +3824,27 @@
  * keySz  The length of the private key data in bytes.
  * ctx    The callback context.
- * returns 0 on succes, otherwise the valus is an error.
+ * returns 0 on success, otherwise the value is an error.
  */
 int Ed25519Sign(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out,
-                word32* outSz, ed25519_key* key, byte* keyBuf, word32 keySz,
-                void* ctx)
+                word32* outSz, ed25519_key* key, DerBuffer* keyBufInfo)
 {
     int ret;
+#ifdef HAVE_PK_CALLBACKS
+    const byte* keyBuf = NULL;
+    word32 keySz = 0;
+
+    if (keyBufInfo) {
+        keyBuf = keyBufInfo->buffer;
+        keySz = keyBufInfo->length;
+    }
+#endif
 
     (void)ssl;
-    (void)keyBuf;
-    (void)keySz;
-    (void)ctx;
+    (void)keyBufInfo;
 
     WOLFSSL_ENTER("Ed25519Sign");
 
 #ifdef WOLFSSL_ASYNC_CRYPT
-    /* intialize event */
+    /* initialize event */
     ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN);
     if (ret != 0)
@@ -3564,4 +3854,5 @@
 #if defined(HAVE_PK_CALLBACKS)
     if (ssl->ctx->Ed25519SignCb) {
+        void* ctx = wolfSSL_GetEd25519SignCtx(ssl);
         ret = ssl->ctx->Ed25519SignCb(ssl, in, inSz, out, outSz, keyBuf,
             keySz, ctx);
@@ -3595,21 +3886,27 @@
  * keySz  The length of the private key data in bytes.
  * ctx    The callback context.
- * returns 0 on succes, otherwise the valus is an error.
+ * returns 0 on success, otherwise the value is an error.
  */
 int Ed25519Verify(WOLFSSL* ssl, const byte* in, word32 inSz, const byte* msg,
-                  word32 msgSz, ed25519_key* key, byte* keyBuf, word32 keySz,
-                  void* ctx)
+                  word32 msgSz, ed25519_key* key, buffer* keyBufInfo)
 {
     int ret;
+#ifdef HAVE_PK_CALLBACKS
+    const byte* keyBuf = NULL;
+    word32 keySz = 0;
+
+    if (keyBufInfo) {
+        keyBuf = keyBufInfo->buffer;
+        keySz = keyBufInfo->length;
+    }
+#endif
 
     (void)ssl;
-    (void)keyBuf;
-    (void)keySz;
-    (void)ctx;
+    (void)keyBufInfo;
 
     WOLFSSL_ENTER("Ed25519Verify");
 
 #ifdef WOLFSSL_ASYNC_CRYPT
-    /* intialize event */
+    /* initialize event */
     ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN);
     if (ret != 0)
@@ -3619,4 +3916,5 @@
 #ifdef HAVE_PK_CALLBACKS
     if (ssl->ctx->Ed25519VerifyCb) {
+        void* ctx = wolfSSL_GetEd25519VerifyCtx(ssl);
         ret = ssl->ctx->Ed25519VerifyCb(ssl, in, inSz, msg, msgSz, keyBuf,
                                         keySz, &ssl->eccVerifyRes, ctx);
@@ -3645,4 +3943,6 @@
 }
 #endif /* HAVE_ED25519 */
+
+#ifndef WOLFSSL_NO_TLS12
 
 #ifdef HAVE_CURVE25519
@@ -3686,5 +3986,5 @@
 static int X25519SharedSecret(WOLFSSL* ssl, curve25519_key* priv_key,
         curve25519_key* pub_key, byte* pubKeyDer, word32* pubKeySz,
-        byte* out, word32* outlen, int side, void* ctx)
+        byte* out, word32* outlen, int side)
 {
     int ret;
@@ -3694,10 +3994,9 @@
     (void)pubKeySz;
     (void)side;
-    (void)ctx;
 
     WOLFSSL_ENTER("X25519SharedSecret");
 
 #ifdef WOLFSSL_ASYNC_CRYPT
-    /* intialize event */
+    /* initialize event */
     ret = wolfSSL_AsyncInit(ssl, &priv_key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN);
     if (ret != 0)
@@ -3711,4 +4010,5 @@
         ret = X25519GetKey(ssl, &otherKey);
         if (ret == 0) {
+            void* ctx = wolfSSL_GetX25519SharedSecretCtx(ssl);
             ret = ssl->ctx->X25519SharedSecretCb(ssl, otherKey, pubKeyDer,
                 pubKeySz, out, outlen, side, ctx);
@@ -3744,5 +4044,5 @@
 
 #ifdef WOLFSSL_ASYNC_CRYPT
-    /* intialize event */
+    /* initialize event */
     ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_NONE);
     if (ret != 0)
@@ -3750,7 +4050,18 @@
 #endif
 
+#ifdef HAVE_PK_CALLBACKS
+    if (ssl->ctx->X25519KeyGenCb) {
+        void* ctx = wolfSSL_GetX25519KeyGenCtx(ssl);
+        ret = ssl->ctx->X25519KeyGenCb(ssl, key, CURVE25519_KEYSIZE, ctx);
+    }
+    else
+#endif
+    {
     ret = wc_curve25519_make_key(ssl->rng, CURVE25519_KEYSIZE, key);
-    if (ret == 0)
+    }
+
+    if (ret == 0) {
         ssl->ecdhCurveOID = ECC_X25519_OID;
+    }
 
     /* Handle async pending response */
@@ -3766,6 +4077,4 @@
 }
 #endif /* HAVE_CURVE25519 */
-
-#endif /* !NO_CERTS */
 
 #if !defined(NO_CERTS) || !defined(NO_PSK)
@@ -3781,5 +4090,5 @@
 
 #ifdef WOLFSSL_ASYNC_CRYPT
-    /* intialize event */
+    /* initialize event */
     ret = wolfSSL_AsyncInit(ssl, &dhKey->asyncDev, WC_ASYNC_FLAG_NONE);
     if (ret != 0)
@@ -3813,5 +4122,5 @@
 
 #ifdef WOLFSSL_ASYNC_CRYPT
-    /* intialize event */
+    /* initialize event */
     ret = wolfSSL_AsyncInit(ssl, &dhKey->asyncDev, WC_ASYNC_FLAG_NONE);
     if (ret != 0)
@@ -3819,5 +4128,18 @@
 #endif
 
-    ret = wc_DhAgree(dhKey, agree, agreeSz, priv, privSz, otherPub, otherPubSz);
+#ifdef HAVE_PK_CALLBACKS
+    if (ssl->ctx->DhAgreeCb) {
+        void* ctx = wolfSSL_GetDhAgreeCtx(ssl);
+
+        WOLFSSL_MSG("Calling DhAgree Callback Function");
+        ret = ssl->ctx->DhAgreeCb(ssl, dhKey, priv, privSz,
+                    otherPub, otherPubSz, agree, agreeSz, ctx);
+    }
+    else
+#endif
+    {
+        ret = wc_DhAgree(dhKey, agree, agreeSz, priv, privSz, otherPub,
+                otherPubSz);
+    }
 
     /* Handle async pending response */
@@ -3835,4 +4157,119 @@
 #endif /* !NO_CERTS || !NO_PSK */
 
+#endif /* !WOLFSSL_NO_TLS12 */
+
+
+#ifdef HAVE_PK_CALLBACKS
+int wolfSSL_CTX_IsPrivatePkSet(WOLFSSL_CTX* ctx)
+{
+    int pkcbset = 0;
+    (void)ctx;
+#if defined(HAVE_ECC) || defined(HAVE_ED25519) || !defined(NO_RSA)
+    if (0
+    #ifdef HAVE_ECC
+        || ctx->EccSignCb != NULL
+    #endif
+    #ifdef HAVE_ED25519
+        || ctx->Ed25519SignCb != NULL
+    #endif
+    #ifndef NO_RSA
+        || ctx->RsaSignCb != NULL
+        || ctx->RsaDecCb != NULL
+        #ifdef WC_RSA_PSS
+        || ctx->RsaPssSignCb != NULL
+        #endif
+    #endif
+    ) {
+        pkcbset = 1;
+    }
+#endif
+    return pkcbset;
+}
+#endif /* HAVE_PK_CALLBACKS */
+
+
+int InitSSL_Suites(WOLFSSL* ssl)
+{
+    int keySz = 0;
+    byte havePSK = 0;
+    byte haveAnon = 0;
+    byte haveRSA = 0;
+    byte haveMcast = 0;
+
+    (void)haveAnon; /* Squash unused var warnings */
+    (void)haveMcast;
+
+    if (!ssl)
+        return BAD_FUNC_ARG;
+
+#ifndef NO_RSA
+    haveRSA = 1;
+#endif
+#ifndef NO_PSK
+    havePSK = (byte)ssl->options.havePSK;
+#endif /* NO_PSK */
+#ifdef HAVE_ANON
+    haveAnon = ssl->options.haveAnon;
+#endif /* HAVE_ANON*/
+#ifdef WOLFSSL_MULTICAST
+    haveMcast = ssl->options.haveMcast;
+#endif /* WOLFSSL_MULTICAST */
+
+#ifdef WOLFSSL_EARLY_DATA
+    if (ssl->options.side == WOLFSSL_SERVER_END)
+        ssl->options.maxEarlyDataSz = ssl->ctx->maxEarlyDataSz;
+#endif
+#if !defined(WOLFSSL_NO_CLIENT_AUTH) && defined(HAVE_ED25519) && \
+                                        !defined(NO_ED25519_CLIENT_AUTH)
+    ssl->options.cacheMessages = ssl->options.side == WOLFSSL_SERVER_END ||
+                                        ssl->buffers.keyType == ed25519_sa_algo;
+#endif
+
+#ifndef NO_CERTS
+    keySz = ssl->buffers.keySz;
+#endif
+
+    /* make sure server has DH parms, and add PSK if there, add NTRU too */
+    if (ssl->options.side == WOLFSSL_SERVER_END) {
+        InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK,
+                   ssl->options.haveDH, ssl->options.haveNTRU,
+                   ssl->options.haveECDSAsig, ssl->options.haveECC,
+                   ssl->options.haveStaticECC, ssl->options.side);
+    }
+    else {
+        InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK,
+                   TRUE, ssl->options.haveNTRU,
+                   ssl->options.haveECDSAsig, ssl->options.haveECC,
+                   ssl->options.haveStaticECC, ssl->options.side);
+    }
+
+#if !defined(NO_CERTS) && !defined(WOLFSSL_SESSION_EXPORT)
+    /* make sure server has cert and key unless using PSK, Anon, or
+     * Multicast. This should be true even if just switching ssl ctx */
+    if (ssl->options.side == WOLFSSL_SERVER_END &&
+            !havePSK && !haveAnon && !haveMcast) {
+
+        /* server certificate must be loaded */
+        if (!ssl->buffers.certificate || !ssl->buffers.certificate->buffer) {
+            WOLFSSL_MSG("Server missing certificate");
+            return NO_PRIVATE_KEY;
+        }
+
+        /* allow no private key if using PK callbacks and CB is set */
+    #ifdef HAVE_PK_CALLBACKS
+        if (wolfSSL_CTX_IsPrivatePkSet(ssl->ctx)) {
+            WOLFSSL_MSG("Using PK for server private key");
+        }
+        else
+    #endif
+        if (!ssl->buffers.key || !ssl->buffers.key->buffer) {
+            WOLFSSL_MSG("Server missing private key");
+            return NO_PRIVATE_KEY;
+        }
+    }
+#endif
+
+    return WOLFSSL_SUCCESS;
+}
 
 /* This function inherits a WOLFSSL_CTX's fields into an SSL object.
@@ -3848,18 +4285,14 @@
 int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup)
 {
-    byte havePSK = 0;
-    byte haveAnon = 0;
+    int ret = WOLFSSL_SUCCESS;
     byte newSSL;
-    byte haveRSA = 0;
-    byte haveMcast = 0;
-
-    (void)haveAnon; /* Squash unused var warnings */
-    (void)haveMcast;
 
     if (!ssl || !ctx)
         return BAD_FUNC_ARG;
 
+#ifndef SINGLE_THREADED
     if (ssl->suites == NULL && !writeDup)
         return BAD_FUNC_ARG;
+#endif
 
     newSSL = ssl->ctx == NULL; /* Assign after null check */
@@ -3870,18 +4303,4 @@
     }
 #endif
-
-
-#ifndef NO_RSA
-    haveRSA = 1;
-#endif
-#ifndef NO_PSK
-    havePSK = ctx->havePSK;
-#endif /* NO_PSK */
-#ifdef HAVE_ANON
-    haveAnon = ctx->haveAnon;
-#endif /* HAVE_ANON*/
-#ifdef WOLFSSL_MULTICAST
-    haveMcast = ctx->haveMcast;
-#endif /* WOLFSSL_MULTICAST */
 
     /* decrement previous CTX reference count if exists.
@@ -3904,10 +4323,13 @@
 #ifdef HAVE_ECC
     ssl->eccTempKeySz = ctx->eccTempKeySz;
+    ssl->ecdhCurveOID = ctx->ecdhCurveOID;
+#endif
+#if defined(HAVE_ECC) || defined(HAVE_ED25519)
     ssl->pkCurveOID = ctx->pkCurveOID;
-    ssl->ecdhCurveOID = ctx->ecdhCurveOID;
 #endif
 
 #ifdef OPENSSL_EXTRA
     ssl->options.mask = ctx->mask;
+    ssl->CBIS         = ctx->CBIS;
 #endif
     ssl->timeout = ctx->timeout;
@@ -3927,4 +4349,8 @@
     ssl->options.client_psk_cb = ctx->client_psk_cb;
     ssl->options.server_psk_cb = ctx->server_psk_cb;
+#ifdef WOLFSSL_TLS13
+    ssl->options.client_psk_tls13_cb = ctx->client_psk_tls13_cb;
+    ssl->options.server_psk_tls13_cb = ctx->server_psk_tls13_cb;
+#endif
 #endif /* NO_PSK */
 #ifdef WOLFSSL_EARLY_DATA
@@ -3938,4 +4364,5 @@
 #ifndef NO_DH
     ssl->options.minDhKeySz = ctx->minDhKeySz;
+    ssl->options.maxDhKeySz = ctx->maxDhKeySz;
 #endif
 #ifndef NO_RSA
@@ -3966,4 +4393,8 @@
 
 #ifndef NO_DH
+    #if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \
+        !defined(HAVE_SELFTEST)
+        ssl->options.dhKeyTested = ctx->dhKeyTested;
+    #endif
     ssl->buffers.serverDH_P = ctx->serverDH_P;
     ssl->buffers.serverDH_G = ctx->serverDH_G;
@@ -3981,4 +4412,10 @@
     ssl->buffers.keySz   = ctx->privateKeySz;
 #endif
+#if !defined(WOLFSSL_NO_CLIENT_AUTH) && defined(HAVE_ED25519) && \
+                                        !defined(NO_ED25519_CLIENT_AUTH)
+    ssl->options.cacheMessages = ssl->options.side == WOLFSSL_SERVER_END ||
+                                        ssl->buffers.keyType == ed25519_sa_algo;
+#endif
+
 
 #ifdef WOLFSSL_ASYNC_CRYPT
@@ -3987,9 +4424,4 @@
 
     if (writeDup == 0) {
-        int keySz = 0;
-#ifndef NO_CERTS
-        keySz = ssl->buffers.keySz;
-#endif
-
 #ifndef NO_PSK
         if (ctx->server_hint[0]) {   /* set in CTX */
@@ -4000,33 +4432,19 @@
 #endif /* NO_PSK */
 
-        if (ctx->suites)
+        if (ctx->suites) {
+#ifndef SINGLE_THREADED
             *ssl->suites = *ctx->suites;
-        else
+#else
+            ssl->suites = ctx->suites;
+#endif
+        }
+        else {
             XMEMSET(ssl->suites, 0, sizeof(Suites));
-
-        /* make sure server has DH parms, and add PSK if there, add NTRU too */
-        if (ssl->options.side == WOLFSSL_SERVER_END)
-            InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK,
-                       ssl->options.haveDH, ssl->options.haveNTRU,
-                       ssl->options.haveECDSAsig, ssl->options.haveECC,
-                       ssl->options.haveStaticECC, ssl->options.side);
-        else
-            InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK,
-                       TRUE, ssl->options.haveNTRU,
-                       ssl->options.haveECDSAsig, ssl->options.haveECC,
-                       ssl->options.haveStaticECC, ssl->options.side);
-
-#if !defined(NO_CERTS) && !defined(WOLFSSL_SESSION_EXPORT)
-        /* make sure server has cert and key unless using PSK, Anon, or
-         * Multicast. This should be true even if just switching ssl ctx */
-        if (ssl->options.side == WOLFSSL_SERVER_END &&
-                !havePSK && !haveAnon && !haveMcast)
-            if (!ssl->buffers.certificate || !ssl->buffers.certificate->buffer
-                || !ssl->buffers.key || !ssl->buffers.key->buffer) {
-                WOLFSSL_MSG("Server missing certificate and/or private key");
-                return NO_PRIVATE_KEY;
-            }
-#endif
-
+            }
+
+        if (ssl->options.side != WOLFSSL_NEITHER_END) {
+            /* Defer initializing suites until accept or connect */
+            ret = InitSSL_Suites(ssl);
+        }
     }  /* writeDup check */
 
@@ -4037,9 +4455,12 @@
 #endif
 
+    ssl->CBIORecv = ctx->CBIORecv;
+    ssl->CBIOSend = ctx->CBIOSend;
 #ifdef OPENSSL_EXTRA
     ssl->readAhead = ctx->readAhead;
 #endif
-
-    return WOLFSSL_SUCCESS;
+    ssl->verifyDepth = ctx->verifyDepth;
+
+    return ret;
 }
 
@@ -4113,4 +4534,10 @@
         wc_Sha512Free(&ssl->hsHashes->hashSha512);
     #endif
+    #if defined(HAVE_ED25519) && !defined(WOLFSSL_NO_CLIENT_AUTH)
+        if (ssl->hsHashes->messages != NULL) {
+            XFREE(ssl->hsHashes->messages, ssl->heap, DYNAMIC_TYPE_HASHES);
+            ssl->hsHashes->messages = NULL;
+         }
+    #endif
 
         XFREE(ssl->hsHashes, ssl->heap, DYNAMIC_TYPE_HASHES);
@@ -4233,5 +4660,5 @@
     ssl->buffers.outputBuffer.bufferSize  = STATIC_BUFFER_LEN;
 
-#if defined(KEEP_PEER_CERT) || defined(GOAHEAD_WS)
+#ifdef KEEP_PEER_CERT
     InitX509(&ssl->peerCert, 0, ssl->heap);
 #endif
@@ -4247,4 +4674,11 @@
     ssl->IOCB_ReadCtx  = &ssl->nxCtx;  /* default NetX IO ctx, same for read */
     ssl->IOCB_WriteCtx = &ssl->nxCtx;  /* and write */
+#elif defined(WOLFSSL_APACHE_MYNEWT) && !defined(WOLFSSL_LWIP)
+    ssl->mnCtx = mynewt_ctx_new();
+    if(!ssl->mnCtx) {
+        return MEMORY_E;
+    }
+    ssl->IOCB_ReadCtx  = ssl->mnCtx;  /* default Mynewt IO ctx, same for read */
+    ssl->IOCB_WriteCtx = ssl->mnCtx;  /* and write */
 #endif
 
@@ -4260,4 +4694,10 @@
     ssl->encrypt.state = CIPHER_STATE_BEGIN;
     ssl->decrypt.state = CIPHER_STATE_BEGIN;
+#ifndef NO_DH
+    #if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \
+        !defined(HAVE_SELFTEST)
+        ssl->options.dhDoKeyTest = 1;
+    #endif
+#endif
 
 #ifdef WOLFSSL_DTLS
@@ -4276,9 +4716,11 @@
 #endif
 
+#ifndef WOLFSSL_AEAD_ONLY
     #ifndef NO_OLD_TLS
         ssl->hmac = SSL_hmac; /* default to SSLv3 */
-    #else
+    #elif !defined(WOLFSSL_NO_TLS12)
         ssl->hmac = TLS_hmac;
     #endif
+#endif
 
 
@@ -4298,4 +4740,9 @@
         ssl->options.postHandshakeAuth = ctx->postHandshakeAuth;
     #endif
+
+    if (ctx->numGroups > 0) {
+        XMEMCPY(ssl->group, ctx->group, sizeof(*ctx->group) * ctx->numGroups);
+        ssl->numGroups = ctx->numGroups;
+    }
 #endif
 
@@ -4306,5 +4753,5 @@
 #ifdef HAVE_ALPN
     ssl->alpn_client_list = NULL;
-    #if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+    #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
         ssl->alpnSelect    = ctx->alpnSelect;
         ssl->alpnSelectArg = ctx->alpnSelectArg;
@@ -4321,4 +4768,11 @@
     ssl->alert_history.last_tx.code  = -1;
     ssl->alert_history.last_tx.level = -1;
+
+#ifdef OPENSSL_EXTRA
+    /* copy over application session context ID */
+    ssl->sessionCtxSz = ctx->sessionCtxSz;
+    XMEMCPY(ssl->sessionCtx, ctx->sessionCtx, ctx->sessionCtxSz);
+    ssl->cbioFlag = ctx->cbioFlag;
+#endif
 
     InitCiphers(ssl);
@@ -4336,4 +4790,5 @@
         }
         XMEMSET(ssl->arrays, 0, sizeof(Arrays));
+#if defined(WOLFSSL_TLS13) || defined(WOLFSSL_SNIFFER)
         ssl->arrays->preMasterSecret = (byte*)XMALLOC(ENCRYPT_LEN, ssl->heap,
             DYNAMIC_TYPE_SECRET);
@@ -4342,5 +4797,10 @@
         }
         XMEMSET(ssl->arrays->preMasterSecret, 0, ENCRYPT_LEN);
-
+#endif
+
+#ifdef SINGLE_THREADED
+        if (ctx->suites == NULL)
+#endif
+        {
         /* suites */
         ssl->suites = (Suites*)XMALLOC(sizeof(Suites), ssl->heap,
@@ -4351,4 +4811,5 @@
         }
     }
+    }
 
     /* Initialize SSL with the appropriate fields from it's ctx */
@@ -4387,8 +4848,10 @@
     }
 
+#ifdef HAVE_WRITE_DUP
     if (writeDup) {
         /* all done */
         return 0;
     }
+#endif
 
     /* hsHashes */
@@ -4434,4 +4897,15 @@
         for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++)
             ssl->keys.peerSeq[i].peerId = INVALID_PEER_ID;
+    }
+#endif
+
+#ifdef HAVE_SECURE_RENEGOTIATION
+    if (ssl->options.side == WOLFSSL_CLIENT_END) {
+    /* use secure renegotiation by default (not recommend) */
+    #ifdef WOLFSSL_SECURE_RENEGOTIATION_ON_BY_DEFAULT
+        ret = wolfSSL_UseSecureRenegotiation(ssl);
+        if (ret != WOLFSSL_SUCCESS)
+            return ret;
+    #endif
     }
 #endif
@@ -4598,8 +5072,11 @@
 }
 
-#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_CURVE25519)
+#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \
+    defined(HAVE_CURVE25519)
 static int ReuseKey(WOLFSSL* ssl, int type, void* pKey)
 {
     int ret = 0;
+
+    (void)ssl;
 
     switch (type) {
@@ -4691,4 +5168,7 @@
         XFREE(ssl->rng, ssl->heap, DYNAMIC_TYPE_RNG);
     }
+#ifdef SINGLE_THREADED
+    if (ssl->suites != ssl->ctx->suites)
+#endif
     XFREE(ssl->suites, ssl->heap, DYNAMIC_TYPE_SUITES);
     FreeHandshakeHashes(ssl);
@@ -4697,4 +5177,11 @@
     /* clear keys struct after session */
     ForceZero(&ssl->keys, sizeof(Keys));
+
+#ifdef WOLFSSL_TLS13
+    if (ssl->options.tls1_3) {
+        ForceZero(&ssl->clientSecret, sizeof(ssl->clientSecret));
+        ForceZero(&ssl->serverSecret, sizeof(ssl->serverSecret));
+    }
+#endif
 
 #ifndef NO_DH
@@ -4706,5 +5193,5 @@
     XFREE(ssl->buffers.serverDH_Pub.buffer, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
     /* parameters (p,g) may be owned by ctx */
-    if (ssl->buffers.weOwnDH || ssl->options.side == WOLFSSL_CLIENT_END) {
+    if (ssl->buffers.weOwnDH) {
         XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
         XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
@@ -4741,5 +5228,5 @@
 #endif
 #endif /* WOLFSSL_DTLS */
-#if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS)
+#ifdef OPENSSL_EXTRA
     if (ssl->biord != ssl->biowr)        /* only free write if different */
         wolfSSL_BIO_free(ssl->biowr);
@@ -4754,21 +5241,28 @@
     FreeKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->peerEccDsaKey);
     ssl->peerEccDsaKeyPresent = 0;
+#endif
+#if defined(HAVE_ECC) || defined(HAVE_CURVE25519)
+    {
+        int dtype;
+    #ifdef HAVE_ECC
+        dtype = DYNAMIC_TYPE_ECC;
+    #endif
 #ifdef HAVE_CURVE25519
-    if (!ssl->peerX25519KeyPresent &&
-            ssl->eccTempKeyPresent != DYNAMIC_TYPE_CURVE25519)
-#endif /* HAVE_CURVE25519 */
+    #ifdef HAVE_ECC
+        if (ssl->peerX25519KeyPresent ||
+                              ssl->eccTempKeyPresent == DYNAMIC_TYPE_CURVE25519)
+    #endif /* HAVE_ECC */
     {
-        FreeKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->eccTempKey);
+            dtype = DYNAMIC_TYPE_CURVE25519;
+    }
+    #endif /* HAVE_CURVE25519 */
+        FreeKey(ssl, dtype, (void**)&ssl->eccTempKey);
         ssl->eccTempKeyPresent = 0;
     }
+#endif /* HAVE_ECC || HAVE_CURVE25519 */
 #ifdef HAVE_CURVE25519
-    else {
-        FreeKey(ssl, DYNAMIC_TYPE_CURVE25519, (void**)&ssl->eccTempKey);
-        ssl->eccTempKeyPresent = 0;
-    }
     FreeKey(ssl, DYNAMIC_TYPE_CURVE25519, (void**)&ssl->peerX25519Key);
     ssl->peerX25519KeyPresent = 0;
 #endif
-#endif /* HAVE_ECC */
 #ifdef HAVE_ED25519
     FreeKey(ssl, DYNAMIC_TYPE_ED25519, (void**)&ssl->peerEd25519Key);
@@ -4800,9 +5294,15 @@
 #endif
 #endif /* HAVE_TLS_EXTENSIONS */
+#if defined(WOLFSSL_APACHE_MYNEWT) && !defined(WOLFSSL_LWIP)
+    if (ssl->mnCtx) {
+        mynewt_ctx_clear(ssl->mnCtx);
+        ssl->mnCtx = NULL;
+    }
+#endif
 #ifdef HAVE_NETX
     if (ssl->nxCtx.nxPacket)
         nx_packet_release(ssl->nxCtx.nxPacket);
 #endif
-#if defined(KEEP_PEER_CERT) || defined(GOAHEAD_WS)
+#ifdef KEEP_PEER_CERT
     FreeX509(&ssl->peerCert);
 #endif
@@ -4842,4 +5342,5 @@
         WOLFSSL_HEAP_HINT* ssl_hint = (WOLFSSL_HEAP_HINT*)ssl->heap;
         WOLFSSL_HEAP*      ctx_heap;
+        void* heap = ssl->ctx ? ssl->ctx->heap : ssl->heap;
 
         ctx_heap = ssl_hint->memory;
@@ -4861,7 +5362,7 @@
         /* check if tracking stats */
         if (ctx_heap->flag & WOLFMEM_TRACK_STATS) {
-            XFREE(ssl_hint->stats, ssl->ctx->heap, DYNAMIC_TYPE_SSL);
-        }
-        XFREE(ssl->heap, ssl->ctx->heap, DYNAMIC_TYPE_SSL);
+            XFREE(ssl_hint->stats, heap, DYNAMIC_TYPE_SSL);
+        }
+        XFREE(ssl->heap, heap, DYNAMIC_TYPE_SSL);
     #ifdef WOLFSSL_HEAP_TEST
     }
@@ -4886,5 +5387,12 @@
         ShrinkInputBuffer(ssl, NO_FORCED_FREE);
 
+#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
+    if (!ssl->options.tls1_3)
+#endif
+    {
     /* suites */
+#ifdef SINGLE_THREADED
+        if (ssl->suites != ssl->ctx->suites)
+#endif
     XFREE(ssl->suites, ssl->heap, DYNAMIC_TYPE_SUITES);
     ssl->suites = NULL;
@@ -4892,7 +5400,19 @@
     /* hsHashes */
     FreeHandshakeHashes(ssl);
+    }
 
     /* RNG */
-    if (ssl->specs.cipher_type == stream || ssl->options.tls1_1 == 0) {
+    if (ssl->options.tls1_1 == 0
+#ifndef WOLFSSL_AEAD_ONLY
+        || ssl->specs.cipher_type == stream
+#endif
+#if defined(WOLFSSL_TLS13)
+    #if !defined(WOLFSSL_POST_HANDSHAKE_AUTH)
+        || ssl->options.tls1_3
+    #elif !defined(HAVE_SESSION_TICKET)
+        || (ssl->options.tls1_3 && ssl->options.side == WOLFSSL_SERVER_END)
+    #endif
+#endif
+    ) {
         if (ssl->options.weOwnRng) {
             wc_FreeRng(ssl->rng);
@@ -4913,8 +5433,16 @@
 #endif
 
+#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) && \
+                                                    defined(HAVE_SESSION_TICKET)
+    if (!ssl->options.tls1_3)
+#endif
     /* arrays */
     if (ssl->options.saveArrays == 0)
         FreeArrays(ssl, 1);
 
+#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
+    if (!ssl->options.tls1_3 || ssl->options.side == WOLFSSL_CLIENT_END)
+#endif
+    {
 #ifndef NO_RSA
     /* peerRsaKey */
@@ -4922,26 +5450,42 @@
     ssl->peerRsaKeyPresent = 0;
 #endif
+#ifdef HAVE_ECC
+        FreeKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->peerEccDsaKey);
+        ssl->peerEccDsaKeyPresent = 0;
+#endif /* HAVE_ECC */
+#ifdef HAVE_ED25519
+        FreeKey(ssl, DYNAMIC_TYPE_ED25519, (void**)&ssl->peerEd25519Key);
+        ssl->peerEd25519KeyPresent = 0;
+#endif /* HAVE_ED25519 */
+    }
 
 #ifdef HAVE_ECC
     FreeKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->peerEccKey);
     ssl->peerEccKeyPresent = 0;
-    FreeKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->peerEccDsaKey);
-    ssl->peerEccDsaKeyPresent = 0;
+#endif
+#if defined(HAVE_ECC) || defined(HAVE_CURVE25519)
+    {
+        int dtype;
+    #ifdef HAVE_ECC
+        dtype = DYNAMIC_TYPE_ECC;
+    #endif
 #ifdef HAVE_CURVE25519
-    if (ssl->ecdhCurveOID != ECC_X25519_OID)
-#endif /* HAVE_CURVE25519 */
+    #ifdef HAVE_ECC
+        if (ssl->peerX25519KeyPresent ||
+                              ssl->eccTempKeyPresent == DYNAMIC_TYPE_CURVE25519)
+    #endif /* HAVE_ECC */
     {
-        FreeKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->eccTempKey);
+            dtype = DYNAMIC_TYPE_CURVE25519;
+    }
+    #endif /* HAVE_CURVE25519 */
+        FreeKey(ssl, dtype, (void**)&ssl->eccTempKey);
         ssl->eccTempKeyPresent = 0;
     }
+#endif /* HAVE_ECC || HAVE_CURVE25519 */
 #ifdef HAVE_CURVE25519
-    else {
-        FreeKey(ssl, DYNAMIC_TYPE_CURVE25519, (void**)&ssl->eccTempKey);
-        ssl->eccTempKeyPresent = 0;
-    }
     FreeKey(ssl, DYNAMIC_TYPE_CURVE25519, (void**)&ssl->peerX25519Key);
     ssl->peerX25519KeyPresent = 0;
-#endif /* HAVE_CURVE25519 */
-#endif /* HAVE_ECC */
+#endif
+
 #ifndef NO_DH
     if (ssl->buffers.serverDH_Priv.buffer) {
@@ -4954,5 +5498,5 @@
     ssl->buffers.serverDH_Pub.buffer = NULL;
     /* parameters (p,g) may be owned by ctx */
-    if (ssl->buffers.weOwnDH || ssl->options.side == WOLFSSL_CLIENT_END) {
+    if (ssl->buffers.weOwnDH) {
         XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
         ssl->buffers.serverDH_G.buffer = NULL;
@@ -4961,8 +5505,13 @@
     }
 #endif /* !NO_DH */
+
 #ifndef NO_CERTS
     wolfSSL_UnloadCertsKeys(ssl);
 #endif
 #ifdef HAVE_PK_CALLBACKS
+#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
+    if (!ssl->options.tls1_3 || ssl->options.side == WOLFSSL_CLIENT_END)
+#endif
+    {
     #ifdef HAVE_ECC
         XFREE(ssl->buffers.peerEccDsaKey.buffer, ssl->heap, DYNAMIC_TYPE_ECC);
@@ -4978,4 +5527,5 @@
         ssl->buffers.peerEd25519Key.buffer = NULL;
     #endif
+    }
 #endif /* HAVE_PK_CALLBACKS */
 
@@ -4991,4 +5541,11 @@
         ssl->session.ticketLen = 0;
     }
+#endif
+
+#if defined(HAVE_TLS_EXTENSIONS) && !defined(HAVE_SNI) && \
+                    !defined(HAVE_ALPN) && !defined(WOLFSSL_POST_HANDSHAKE_AUTH)
+    /* Some extensions need to be kept for post-handshake querying. */
+    TLSX_FreeAll(ssl->extensions, ssl->heap);
+    ssl->extensions = NULL;
 #endif
 
@@ -5022,5 +5579,5 @@
 {
     if (ssl->ctx) {
-        FreeSSL_Ctx(ssl->ctx); /* will decrement and free underyling CTX if 0 */
+        FreeSSL_Ctx(ssl->ctx); /* will decrement and free underlying CTX if 0 */
     }
     SSL_ResourceFree(ssl);
@@ -5029,8 +5586,10 @@
 }
 
-
-#if !defined(NO_OLD_TLS) || defined(HAVE_CHACHA) || defined(HAVE_AESCCM) \
-    || defined(HAVE_AESGCM) || defined(WOLFSSL_DTLS)
-static INLINE void GetSEQIncrement(WOLFSSL* ssl, int verify, word32 seq[2])
+#if !defined(NO_OLD_TLS) || defined(WOLFSSL_DTLS) || \
+    ((defined(HAVE_CHACHA) || defined(HAVE_AESCCM) || defined(HAVE_AESGCM)) \
+     && defined(HAVE_AEAD))
+
+#if defined(WOLFSSL_DTLS) || !defined(WOLFSSL_NO_TLS12)
+static WC_INLINE void GetSEQIncrement(WOLFSSL* ssl, int verify, word32 seq[2])
 {
     if (verify) {
@@ -5051,8 +5610,9 @@
     }
 }
+#endif /* WOLFSSL_DTLS || !WOLFSSL_NO_TLS12 */
 
 
 #ifdef WOLFSSL_DTLS
-static INLINE void DtlsGetSEQ(WOLFSSL* ssl, int order, word32 seq[2])
+static WC_INLINE void DtlsGetSEQ(WOLFSSL* ssl, int order, word32 seq[2])
 {
     if (order == PREV_ORDER) {
@@ -5098,5 +5658,5 @@
 }
 
-static INLINE void DtlsSEQIncrement(WOLFSSL* ssl, int order)
+static WC_INLINE void DtlsSEQIncrement(WOLFSSL* ssl, int order)
 {
     word32 seq;
@@ -5126,6 +5686,6 @@
 #endif /* WOLFSSL_DTLS */
 
-
-static INLINE void WriteSEQ(WOLFSSL* ssl, int verifyOrder, byte* out)
+#if defined(WOLFSSL_DTLS) || !defined(WOLFSSL_NO_TLS12)
+static WC_INLINE void WriteSEQ(WOLFSSL* ssl, int verifyOrder, byte* out)
 {
     word32 seq[2] = {0, 0};
@@ -5143,6 +5703,7 @@
     c32toa(seq[1], out + OPAQUE32_LEN);
 }
-#endif
-
+#endif /* WOLFSSL_DTLS || !WOLFSSL_NO_TLS12 */
+#endif /* !NO_OLD_TLS || WOLFSSL_DTLS ||
+        *     ((HAVE_CHACHA || HAVE_AESCCM || HAVE_AESGCM) && HAVE_AEAD) */
 
 #ifdef WOLFSSL_DTLS
@@ -5254,5 +5815,5 @@
         }
 
-        /* if no mesage data, just return */
+        /* if no message data, just return */
         if (fragSz == 0)
             return 0;
@@ -5615,4 +6176,6 @@
 }
 
+#ifndef WOLFSSL_NO_TLS12
+
 ProtocolVersion MakeDTLSv1_2(void)
 {
@@ -5623,4 +6186,6 @@
     return pv;
 }
+
+#endif /* !WOLFSSL_NO_TLS12 */
 
 #endif /* WOLFSSL_DTLS */
@@ -5786,16 +6351,67 @@
     }
 
+#elif defined(WOLFSSL_NUCLEUS_1_2)
+
+    #define NU_TICKS_PER_SECOND 100
+
+    word32 LowResTimer(void)
+    {
+        /* returns number of 10ms ticks, so 100 ticks/sec */
+        return NU_Retrieve_Clock() / NU_TICKS_PER_SECOND;
+    }
+#elif defined(WOLFSSL_APACHE_MYNEWT)
+
+    #include "os/os_time.h"
+    word32 LowResTimer(void)
+    {
+        word32 now;
+        struct os_timeval tv;
+        os_gettimeofday(&tv, NULL);
+        now = (word32)tv.tv_sec;
+        return now;
+    }
+
 #else
     /* Posix style time */
+    #ifndef USER_TIME
     #include <time.h>
+    #endif
 
     word32 LowResTimer(void)
     {
-        return (word32)time(0);
-    }
-
-
-#endif
-
+        return (word32)XTIME(0);
+    }
+#endif
+#if !defined(WOLFSSL_NO_CLIENT_AUTH) && defined(HAVE_ED25519) && \
+                                                !defined(NO_ED25519_CLIENT_AUTH)
+/* Store the message for use with CertificateVerify using Ed25519.
+ *
+ * ssl   SSL/TLS object.
+ * data  Message to store.
+ * sz    Size of message to store.
+ * returns MEMORY_E if not able to reallocate, otherwise 0.
+ */
+static int Ed25519Update(WOLFSSL* ssl, const byte* data, int sz)
+{
+    int   ret = 0;
+    byte* msgs;
+
+    if (ssl->options.cacheMessages) {
+        msgs = (byte*)XREALLOC(ssl->hsHashes->messages,
+                                                ssl->hsHashes->length + sz,
+                                                ssl->heap, DYNAMIC_TYPE_HASHES);
+        if (msgs == NULL)
+            ret = MEMORY_E;
+        if (ret == 0) {
+            ssl->hsHashes->messages = msgs;
+            XMEMCPY(msgs + ssl->hsHashes->length, data, sz);
+            ssl->hsHashes->prevLen = ssl->hsHashes->length;
+            ssl->hsHashes->length += sz;
+        }
+    }
+
+    return ret;
+}
+#endif /* HAVE_ED25519 && !WOLFSSL_NO_CLIENT_AUTH */
 
 #ifndef NO_CERTS
@@ -5839,4 +6455,10 @@
             return ret;
 #endif
+    #if !defined(WOLFSSL_NO_CLIENT_AUTH) && defined(HAVE_ED25519) && \
+                                                !defined(NO_ED25519_CLIENT_AUTH)
+        ret = Ed25519Update(ssl, output, sz);
+        if (ret != 0)
+            return ret;
+    #endif
     }
 
@@ -5890,4 +6512,10 @@
             return ret;
 #endif
+    #if !defined(WOLFSSL_NO_CLIENT_AUTH) && defined(HAVE_ED25519) && \
+                                                !defined(NO_ED25519_CLIENT_AUTH)
+        ret = Ed25519Update(ssl, adj, sz);
+        if (ret != 0)
+            return ret;
+    #endif
     }
 
@@ -5943,4 +6571,10 @@
             return ret;
 #endif
+    #if !defined(WOLFSSL_NO_CLIENT_AUTH) && defined(HAVE_ED25519) && \
+                                                !defined(NO_ED25519_CLIENT_AUTH)
+        ret = Ed25519Update(ssl, adj, sz);
+        if (ret != 0)
+            return ret;
+    #endif
     }
 
@@ -5962,6 +6596,11 @@
     rl->pvMajor = ssl->version.major;       /* type and version same in each */
 #ifdef WOLFSSL_TLS13
-    if (IsAtLeastTLSv1_3(ssl->version))
+    if (IsAtLeastTLSv1_3(ssl->version)) {
+#ifdef WOLFSSL_TLS13_DRAFT_18
         rl->pvMinor = TLSv1_MINOR;
+#else
+        rl->pvMinor = TLSv1_2_MINOR;
+#endif
+    }
     else
 #endif
@@ -5993,4 +6632,6 @@
 
 
+#if !defined(WOLFSSL_NO_TLS12) || (defined(HAVE_SESSION_TICKET) && \
+                                                    !defined(NO_WOLFSSL_SERVER))
 /* add handshake header for message */
 static void AddHandShakeHeader(byte* output, word32 length,
@@ -6005,4 +6646,7 @@
     /* handshake header */
     hs = (HandShakeHeader*)output;
+    if (hs == NULL)
+        return;
+
     hs->type = type;
     c32to24(length, hs->length);         /* type and length same for each */
@@ -6020,5 +6664,4 @@
 }
 
-
 /* add both headers for handshake message */
 static void AddHeaders(byte* output, word32 length, byte type, WOLFSSL* ssl)
@@ -6037,6 +6680,8 @@
     AddHandShakeHeader(output + outputAdj, length, 0, length, type, ssl);
 }
-
-
+#endif /* !WOLFSSL_NO_TLS12 || (HAVE_SESSION_TICKET && !NO_WOLFSSL_SERVER) */
+
+
+#ifndef WOLFSSL_NO_TLS12
 #ifndef NO_CERTS
 static void AddFragHeaders(byte* output, word32 fragSz, word32 fragOffset,
@@ -6058,12 +6703,13 @@
 }
 #endif /* NO_CERTS */
+#endif /* !WOLFSSL_NO_TLS12 */
 
 
 /* return bytes received, -1 on error */
-static int Receive(WOLFSSL* ssl, byte* buf, word32 sz)
+static int wolfSSLReceive(WOLFSSL* ssl, byte* buf, word32 sz)
 {
     int recvd;
 
-    if (ssl->ctx->CBIORecv == NULL) {
+    if (ssl->CBIORecv == NULL) {
         WOLFSSL_MSG("Your IO Recv callback is null, please set");
         return -1;
@@ -6071,5 +6717,5 @@
 
 retry:
-    recvd = ssl->ctx->CBIORecv(ssl, (char *)buf, (int)sz, ssl->IOCB_ReadCtx);
+    recvd = ssl->CBIORecv(ssl, (char *)buf, (int)sz, ssl->IOCB_ReadCtx);
     if (recvd < 0)
         switch (recvd) {
@@ -6099,4 +6745,7 @@
                             XSTRNCPY(ssl->timeoutInfo.timeoutName,
                                     "recv() timeout", MAX_TIMEOUT_NAME_SZ);
+                            ssl->timeoutInfo.timeoutName[
+                                MAX_TIMEOUT_NAME_SZ] = '\0';
+
                             WOLFSSL_MSG("Got our timeout");
                             return WANT_READ;
@@ -6110,6 +6759,6 @@
                 return -1;
 
+                #ifdef WOLFSSL_DTLS
             case WOLFSSL_CBIO_ERR_TIMEOUT:
-                #ifdef WOLFSSL_DTLS
                 if (IsDtlsNotSctpMode(ssl) &&
                     !ssl->options.handShakeDone &&
@@ -6119,6 +6768,6 @@
                     goto retry;
                 }
-                #endif
                 return -1;
+            #endif
 
             default:
@@ -6171,5 +6820,5 @@
 int SendBuffered(WOLFSSL* ssl)
 {
-    if (ssl->ctx->CBIOSend == NULL) {
+    if (ssl->CBIOSend == NULL) {
         WOLFSSL_MSG("Your IO Send callback is null, please set");
         return SOCKET_ERROR_E;
@@ -6185,5 +6834,5 @@
 
     while (ssl->buffers.outputBuffer.length > 0) {
-        int sent = ssl->ctx->CBIOSend(ssl,
+        int sent = ssl->CBIOSend(ssl,
                                       (char*)ssl->buffers.outputBuffer.buffer +
                                       ssl->buffers.outputBuffer.idx,
@@ -6210,4 +6859,7 @@
                                 XSTRNCPY(ssl->timeoutInfo.timeoutName,
                                         "send() timeout", MAX_TIMEOUT_NAME_SZ);
+                                ssl->timeoutInfo.timeoutName[
+                                    MAX_TIMEOUT_NAME_SZ] = '\0';
+
                                 WOLFSSL_MSG("Got our timeout");
                                 return WANT_WRITE;
@@ -6247,5 +6899,5 @@
 
 /* Grow the output buffer */
-static INLINE int GrowOutputBuffer(WOLFSSL* ssl, int size)
+static WC_INLINE int GrowOutputBuffer(WOLFSSL* ssl, int size)
 {
     byte* tmp;
@@ -6444,5 +7096,10 @@
     if (rh->pvMajor != ssl->version.major ||
         (rh->pvMinor != ssl->version.minor &&
-         (!IsAtLeastTLSv1_3(ssl->version) || rh->pvMinor != TLSv1_MINOR)))
+#ifdef WOLFSSL_TLS13_DRAFT_18
+         (!IsAtLeastTLSv1_3(ssl->version) || rh->pvMinor != TLSv1_MINOR)
+#else
+         (!IsAtLeastTLSv1_3(ssl->version) || rh->pvMinor != TLSv1_2_MINOR)
+#endif
+        ))
 #endif
     {
@@ -6494,5 +7151,5 @@
 }
 
-
+#ifndef WOLFSSL_NO_TLS12
 static int GetHandShakeHeader(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
                               byte *type, word32 *size, word32 totalSz)
@@ -6510,5 +7167,5 @@
     return 0;
 }
-
+#endif
 
 #ifdef WOLFSSL_DTLS
@@ -6669,31 +7326,13 @@
 #endif
 
+#ifndef WOLFSSL_NO_TLS12
+
 /* Finished doesn't support SHA512, not SHA512 cipher suites yet */
 static int BuildFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender)
 {
     int ret = 0;
-#ifdef WOLFSSL_SHA384
-#ifdef WOLFSSL_SMALL_STACK
-    wc_Sha384* sha384;
-#else
-    wc_Sha384 sha384[1];
-#endif /* WOLFSSL_SMALL_STACK */
-#endif /* WOLFSSL_SHA384 */
 
     if (ssl == NULL)
         return BAD_FUNC_ARG;
-
-#ifdef WOLFSSL_SHA384
-#ifdef WOLFSSL_SMALL_STACK
-    sha384 = (wc_Sha384*)XMALLOC(sizeof(wc_Sha384), ssl->heap, DYNAMIC_TYPE_HASHCTX);
-    if (sha384 == NULL)
-        return MEMORY_E;
-#endif /* WOLFSSL_SMALL_STACK */
-#endif /* WOLFSSL_SHA384 */
-
-    /* store current states, building requires get_digest which resets state */
-#ifdef WOLFSSL_SHA384
-    sha384[0] = ssl->hsHashes->hashSha384;
-#endif
 
 #ifndef NO_TLS
@@ -6711,21 +7350,10 @@
 #endif
 
-    /* restore */
-    if (IsAtLeastTLSv1_2(ssl)) {
-    #ifdef WOLFSSL_SHA384
-        ssl->hsHashes->hashSha384 = sha384[0];
-    #endif
-    }
-
-#ifdef WOLFSSL_SHA384
-#ifdef WOLFSSL_SMALL_STACK
-    XFREE(sha384, ssl->heap, DYNAMIC_TYPE_HASHCTX);
-#endif
-#endif
-
     return ret;
 }
 
-
+#endif /* WOLFSSL_NO_TLS12 */
+
+#if !defined(NO_WOLFSSL_SERVER) || !defined(NO_WOLFSSL_CLIENT)
     /* cipher requirements */
     enum {
@@ -6747,8 +7375,12 @@
     {
 
+        (void)requirement;
+
+#ifndef WOLFSSL_NO_TLS12
+
+#ifdef HAVE_CHACHA
         if (first == CHACHA_BYTE) {
 
         switch (second) {
-
         case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 :
             if (requirement == REQUIRES_RSA)
@@ -6804,4 +7436,5 @@
             }
         }
+#endif /* HAVE_CHACHA */
 
         /* ECC extensions */
@@ -6809,5 +7442,5 @@
 
         switch (second) {
-
+#ifdef HAVE_ECC
 #ifndef NO_RSA
         case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA :
@@ -6835,5 +7468,5 @@
                 return 1;
             break;
-#endif
+    #endif /* !NO_DES3 */
 
 #ifndef NO_RC4
@@ -6849,5 +7482,5 @@
                 return 1;
             break;
-#endif
+    #endif /* !NO_RC4 */
 #endif /* NO_RSA */
 
@@ -6862,5 +7495,5 @@
                 return 1;
             break;
-#endif
+    #endif /* !NO_DES3  */
 #ifndef NO_RC4
         case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA :
@@ -6873,5 +7506,5 @@
                 return 1;
             break;
-#endif
+    #endif /* !NO_RC4 */
 #ifndef NO_RSA
         case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA :
@@ -6886,5 +7519,5 @@
                 return 1;
             break;
-#endif
+    #endif /* !NO_RSA */
 
         case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA :
@@ -6927,6 +7560,8 @@
                 return 1;
             break;
+#endif /* HAVE_ECC */
 
 #ifndef NO_RSA
+    #ifdef HAVE_ECC
         case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 :
             if (requirement == REQUIRES_RSA)
@@ -6952,5 +7587,6 @@
                 return 1;
             break;
-
+    #endif /* HAVE_ECC */
+    #ifdef HAVE_AESCCM
         case TLS_RSA_WITH_AES_128_CCM_8 :
         case TLS_RSA_WITH_AES_256_CCM_8 :
@@ -6960,4 +7596,6 @@
                 return 1;
             break;
+    #endif /* HAVE_AESCCM */
+    #ifdef HAVE_ECC
 
         case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 :
@@ -6974,6 +7612,8 @@
                 return 1;
             break;
-#endif
-
+    #endif /* HAVE_ECC */
+#endif /* !NO_RSA */
+
+#ifdef HAVE_ECC
         case TLS_ECDHE_ECDSA_WITH_AES_128_CCM :
         case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 :
@@ -6996,5 +7636,7 @@
                 return 1;
             break;
-
+#endif /* HAVE_ECC */
+
+#ifndef NO_PSK
         case TLS_PSK_WITH_AES_128_CCM:
         case TLS_PSK_WITH_AES_256_CCM:
@@ -7012,5 +7654,6 @@
                 return 1;
             break;
-
+#endif /* !NO_PSK */
+#ifdef HAVE_ECC
         case TLS_ECDHE_ECDSA_WITH_NULL_SHA :
             if (requirement == REQUIRES_ECC)
@@ -7027,5 +7670,5 @@
                 return 1;
             break;
-
+#endif /* HAVE_ECC */
         default:
             WOLFSSL_MSG("Unsupported cipher suite, CipherRequires ECC");
@@ -7033,4 +7676,6 @@
         }   /* switch */
         }   /* if     */
+
+#endif /* !WOLFSSL_NO_TLS12 */
 
         /* Distinct TLS v1.3 cipher suites with cipher and digest only. */
@@ -7054,4 +7699,6 @@
         }
 
+#ifndef WOLFSSL_NO_TLS12
+
         if (first != ECC_BYTE && first != CHACHA_BYTE &&
             first != TLS13_BYTE) {   /* normal suites */
@@ -7059,4 +7706,5 @@
 
 #ifndef NO_RSA
+    #ifndef NO_RC4
         case SSL_RSA_WITH_RC4_128_SHA :
             if (requirement == REQUIRES_RSA)
@@ -7068,4 +7716,5 @@
                 return 1;
             break;
+    #endif /* NO_RC4 */
 
         case SSL_RSA_WITH_3DES_EDE_CBC_SHA :
@@ -7074,8 +7723,10 @@
             break;
 
+    #ifdef HAVE_NTRU
         case TLS_NTRU_RSA_WITH_RC4_128_SHA :
             if (requirement == REQUIRES_NTRU)
                 return 1;
             break;
+    #endif /* HAVE_NTRU */
 
         case TLS_RSA_WITH_AES_128_CBC_SHA :
@@ -7089,8 +7740,10 @@
             break;
 
+    #ifdef HAVE_NTRU
         case TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA :
             if (requirement == REQUIRES_NTRU)
                 return 1;
             break;
+    #endif /* HAVE_NTRU */
 
         case TLS_RSA_WITH_AES_256_CBC_SHA :
@@ -7099,8 +7752,10 @@
             break;
 
+    #ifdef HAVE_NTRU
         case TLS_NTRU_RSA_WITH_AES_128_CBC_SHA :
             if (requirement == REQUIRES_NTRU)
                 return 1;
             break;
+    #endif /* HAVE_NTRU */
 
         case TLS_RSA_WITH_AES_256_CBC_SHA256 :
@@ -7115,15 +7770,20 @@
             break;
 
+    #ifdef HAVE_NTRU
         case TLS_NTRU_RSA_WITH_AES_256_CBC_SHA :
             if (requirement == REQUIRES_NTRU)
                 return 1;
             break;
-
+    #endif /* HAVE_NTRU */
+
+    #ifdef HAVE_IDEA
         case SSL_RSA_WITH_IDEA_CBC_SHA :
             if (requirement == REQUIRES_RSA)
                 return 1;
             break;
-#endif
-
+    #endif /* HAVE_IDEA */
+#endif /* !NO_RSA */
+
+#ifndef NO_PSK
         case TLS_PSK_WITH_AES_128_GCM_SHA256 :
         case TLS_PSK_WITH_AES_256_GCM_SHA384 :
@@ -7150,4 +7810,5 @@
                 return 1;
             break;
+#endif /* NO_PSK */
 
 #ifndef NO_RSA
@@ -7180,4 +7841,5 @@
             break;
 
+#ifndef NO_HC128
         case TLS_RSA_WITH_HC_128_MD5 :
             if (requirement == REQUIRES_RSA)
@@ -7194,5 +7856,7 @@
                 return 1;
             break;
-
+#endif /* NO_HC128 */
+
+#ifdef HAVE_BLAKE2
         case TLS_RSA_WITH_AES_128_CBC_B2B256:
         case TLS_RSA_WITH_AES_256_CBC_B2B256:
@@ -7200,9 +7864,12 @@
                 return 1;
             break;
-
+#endif /* HAVE_BLAKE2 */
+
+#ifndef NO_RABBIT
         case TLS_RSA_WITH_RABBIT_SHA :
             if (requirement == REQUIRES_RSA)
                 return 1;
             break;
+#endif /* !NO_RABBIT */
 
         case TLS_RSA_WITH_AES_128_GCM_SHA256 :
@@ -7220,4 +7887,5 @@
             break;
 
+#ifdef HAVE_CAMELLIA
         case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA :
         case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA :
@@ -7239,4 +7907,5 @@
                 return 1;
             break;
+#endif /* HAVE_CAMELLIA */
 
         case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
@@ -7254,4 +7923,8 @@
                 return 1;
             break;
+        case TLS_DH_anon_WITH_AES_256_GCM_SHA384:
+            if (requirement == REQUIRES_DHE)
+                return 1;
+            break;
 #endif
 #ifdef WOLFSSL_MULTICAST
@@ -7266,6 +7939,10 @@
         }  /* if ECC / Normal suites else */
 
+#endif /* !WOLFSSL_NO_TLS12 */
+
         return 0;
     }
+
+#endif /* !NO_WOLFSSL_SERVER && !NO_WOLFSSL_CLIENT */
 
 
@@ -7280,4 +7957,5 @@
 int MatchDomainName(const char* pattern, int len, const char* str)
 {
+    int ret = 0;
     char p, s;
 
@@ -7288,5 +7966,5 @@
 
         p = (char)XTOLOWER((unsigned char)*pattern++);
-        if (p == 0)
+        if (p == '\0')
             break;
 
@@ -7312,12 +7990,16 @@
         }
 
-        if (*str != '\0')
+
+        if (len > 0) {
             str++;
-
-        if (len > 0)
             len--;
     }
-
-    return *str == '\0';
+    }
+
+    if (*str == '\0' && len == 0) {
+        ret = 1; /* success */
+    }
+
+    return ret;
 }
 
@@ -7337,5 +8019,5 @@
         WOLFSSL_MSG("\tindividual AltName check");
 
-        if (MatchDomainName(altName->name,(int)XSTRLEN(altName->name), domain)){
+        if (MatchDomainName(altName->name, altName->len, domain)){
             match = 1;
             break;
@@ -7374,6 +8056,5 @@
         WOLFSSL_MSG("\tindividual AltName check");
 
-        if (MatchDomainName(altName->name, (int)XSTRLEN(altName->name),
-                            domain)) {
+        if (MatchDomainName(altName->name, altName->len, domain)) {
             match = 1;
             *checkCN = 0;
@@ -7437,6 +8118,9 @@
 #endif
 
-#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS)
+#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS) || \
+    defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
 /* Copy parts X509 needs from Decoded cert, 0 on success */
+/* The same DecodedCert cannot be copied to WOLFSSL_X509 twice otherwise the
+ * altNames pointers could be free'd by second x509 still active by first */
 int CopyDecodedToX509(WOLFSSL_X509* x509, DecodedCert* dCert)
 {
@@ -7452,5 +8136,5 @@
     x509->issuer.name[ASN_NAME_MAX - 1] = '\0';
     x509->issuer.sz = (int)XSTRLEN(x509->issuer.name) + 1;
-#ifdef OPENSSL_EXTRA
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
     if (dCert->issuerName.fullName != NULL) {
         XMEMCPY(&x509->issuer.fullName,
@@ -7464,10 +8148,10 @@
     }
     x509->issuer.x509 = x509;
-#endif /* OPENSSL_EXTRA */
+#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
 
     XSTRNCPY(x509->subject.name, dCert->subject, ASN_NAME_MAX);
     x509->subject.name[ASN_NAME_MAX - 1] = '\0';
     x509->subject.sz = (int)XSTRLEN(x509->subject.name) + 1;
-#ifdef OPENSSL_EXTRA
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
     if (dCert->subjectName.fullName != NULL) {
         XMEMCPY(&x509->subject.fullName,
@@ -7480,13 +8164,17 @@
     }
     x509->subject.x509 = x509;
-#endif /* OPENSSL_EXTRA */
-#ifdef WOLFSSL_NGINX
-    XMEMCPY(x509->subject.raw, dCert->subjectRaw, dCert->subjectRawLen);
-    x509->subject.rawLen = dCert->subjectRawLen;
+#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX)
+    x509->subject.rawLen = min(dCert->subjectRawLen, sizeof(x509->subject.raw));
+    XMEMCPY(x509->subject.raw, dCert->subjectRaw, x509->subject.rawLen);
+#ifdef WOLFSSL_CERT_EXT
+    x509->issuer.rawLen = min(dCert->issuerRawLen, sizeof(x509->issuer.raw));
+    XMEMCPY(x509->issuer.raw, dCert->issuerRaw, x509->issuer.rawLen);
+#endif
 #endif
 
     XMEMCPY(x509->serial, dCert->serial, EXTERNAL_SERIAL_SIZE);
     x509->serialSz = dCert->serialSz;
-    if (dCert->subjectCNLen < ASN_NAME_MAX) {
+    if (dCert->subjectCN && dCert->subjectCNLen < ASN_NAME_MAX) {
         XMEMCPY(x509->subjectCN, dCert->subjectCN, dCert->subjectCNLen);
         x509->subjectCN[dCert->subjectCNLen] = '\0';
@@ -7575,6 +8263,44 @@
     x509->altNamesNext   = x509->altNames;  /* index hint */
 
+#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \
+    !defined(IGNORE_NAME_CONSTRAINTS)
+    /* add copies of alternate emails from dCert to X509 */
+    if (dCert->altEmailNames != NULL) {
+        DNS_entry* cur = dCert->altEmailNames;
+
+        while (cur != NULL) {
+            if (cur->type == ASN_RFC822_TYPE) {
+                DNS_entry* dnsEntry;
+                int strLen = cur->len;
+
+                dnsEntry = (DNS_entry*)XMALLOC(sizeof(DNS_entry), x509->heap,
+                                        DYNAMIC_TYPE_ALTNAME);
+                if (dnsEntry == NULL) {
+                    WOLFSSL_MSG("\tOut of Memory");
+                    return MEMORY_E;
+                }
+
+                dnsEntry->type = ASN_RFC822_TYPE;
+                dnsEntry->name = (char*)XMALLOC(strLen + 1, x509->heap,
+                                         DYNAMIC_TYPE_ALTNAME);
+                if (dnsEntry->name == NULL) {
+                    WOLFSSL_MSG("\tOut of Memory");
+                    XFREE(dnsEntry, x509->heap, DYNAMIC_TYPE_ALTNAME);
+                    return MEMORY_E;
+                }
+                dnsEntry->len = strLen;
+                XMEMCPY(dnsEntry->name, cur->name, strLen);
+                dnsEntry->name[strLen] = '\0';
+
+                dnsEntry->next = x509->altNames;
+                x509->altNames = dnsEntry;
+            }
+            cur = cur->next;
+        }
+    }
+#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
+
     x509->isCa = dCert->isCA;
-#ifdef OPENSSL_EXTRA
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
     x509->pathLength = dCert->pathLength;
     x509->keyUsage = dCert->extKeyUsage;
@@ -7657,6 +8383,6 @@
         }
     #endif /* WOLFSSL_CERT_EXT */
-#endif /* OPENSSL_EXTRA */
-#ifdef HAVE_ECC
+#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
+#if defined(HAVE_ECC) || defined(HAVE_ED25519)
     x509->pkCurveOID = dCert->pkCurveOID;
 #endif /* HAVE_ECC */
@@ -7666,19 +8392,158 @@
 
 #endif /* KEEP_PEER_CERT || SESSION_CERTS */
+
+#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \
+     (defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) && !defined(WOLFSSL_NO_TLS12))
+static int ProcessCSR(WOLFSSL* ssl, byte* input, word32* inOutIdx,
+                      word32 status_length)
+{
+    int ret = 0;
+    OcspRequest* request;
+
+    #ifdef WOLFSSL_SMALL_STACK
+        CertStatus* status;
+        OcspResponse* response;
+    #else
+        CertStatus status[1];
+        OcspResponse response[1];
+    #endif
+
+    do {
+        #ifdef HAVE_CERTIFICATE_STATUS_REQUEST
+            if (ssl->status_request) {
+                request = (OcspRequest*)TLSX_CSR_GetRequest(ssl->extensions);
+                ssl->status_request = 0;
+                break;
+            }
+        #endif
+
+        #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
+            if (ssl->status_request_v2) {
+                request = (OcspRequest*)TLSX_CSR2_GetRequest(ssl->extensions,
+                                                          WOLFSSL_CSR2_OCSP, 0);
+                ssl->status_request_v2 = 0;
+                break;
+            }
+        #endif
+
+        return BUFFER_ERROR;
+    } while(0);
+
+    if (request == NULL)
+        return BAD_CERTIFICATE_STATUS_ERROR; /* not expected */
+
+    #ifdef WOLFSSL_SMALL_STACK
+        status = (CertStatus*)XMALLOC(sizeof(CertStatus), ssl->heap,
+                                                      DYNAMIC_TYPE_OCSP_STATUS);
+        response = (OcspResponse*)XMALLOC(sizeof(OcspResponse), ssl->heap,
+                                                     DYNAMIC_TYPE_OCSP_REQUEST);
+
+        if (status == NULL || response == NULL) {
+            if (status)
+                XFREE(status, NULL, DYNAMIC_TYPE_OCSP_STATUS);
+            if (response)
+                XFREE(response, NULL, DYNAMIC_TYPE_OCSP_REQUEST);
+
+            return MEMORY_ERROR;
+        }
+    #endif
+
+    InitOcspResponse(response, status, input +*inOutIdx, status_length);
+
+    if (OcspResponseDecode(response, ssl->ctx->cm, ssl->heap, 0) != 0)
+        ret = BAD_CERTIFICATE_STATUS_ERROR;
+    else if (CompareOcspReqResp(request, response) != 0)
+        ret = BAD_CERTIFICATE_STATUS_ERROR;
+    else if (response->responseStatus != OCSP_SUCCESSFUL)
+        ret = BAD_CERTIFICATE_STATUS_ERROR;
+    else if (response->status->status == CERT_REVOKED)
+        ret = OCSP_CERT_REVOKED;
+    else if (response->status->status != CERT_GOOD)
+        ret = BAD_CERTIFICATE_STATUS_ERROR;
+
+    *inOutIdx += status_length;
+
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(status,   ssl->heap, DYNAMIC_TYPE_OCSP_STATUS);
+        XFREE(response, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
+    #endif
+
+    return ret;
+}
+#endif
+
+
+
+#ifdef HAVE_PK_CALLBACKS
+
+#ifdef HAVE_ECC
+    static int SigPkCbEccVerify(const unsigned char* sig, unsigned int sigSz,
+       const unsigned char* hash, unsigned int hashSz,
+       const unsigned char* keyDer, unsigned int keySz,
+       int* result, void* ctx)
+    {
+        int ret = NOT_COMPILED_IN;
+        WOLFSSL* ssl = (WOLFSSL*)ctx;
+
+        if (ssl && ssl->ctx->EccVerifyCb) {
+            ret = ssl->ctx->EccVerifyCb(ssl, sig, sigSz, hash, hashSz,
+                keyDer, keySz, result, ssl->EccVerifyCtx);
+        }
+        return ret;
+    }
+#endif
+#ifndef NO_RSA
+    static int SigPkCbRsaVerify(unsigned char* sig, unsigned int sigSz,
+       unsigned char** out, const unsigned char* keyDer, unsigned int keySz,
+       void* ctx)
+    {
+        int ret = NOT_COMPILED_IN;
+        WOLFSSL* ssl = (WOLFSSL*)ctx;
+
+        if (ssl && ssl->ctx->RsaVerifyCb) {
+            ret = ssl->ctx->RsaVerifyCb(ssl, sig, sigSz, out, keyDer, keySz,
+                ssl->RsaVerifyCtx);
+        }
+        return ret;
+    }
+#endif
+
+int InitSigPkCb(WOLFSSL* ssl, SignatureCtx* sigCtx)
+{
+    if (ssl == NULL || sigCtx == NULL)
+        return BAD_FUNC_ARG;
+
+    /* only setup the verify callback if a PK is set */
+#ifdef HAVE_ECC
+    if (ssl->ctx->EccVerifyCb) {
+        sigCtx->pkCbEcc = SigPkCbEccVerify;
+        sigCtx->pkCtxEcc = ssl;
+    }
+#endif
+#ifndef NO_RSA
+    /* only setup the verify callback if a PK is set */
+    if (ssl->ctx->RsaVerifyCb) {
+        sigCtx->pkCbRsa = SigPkCbRsaVerify;
+        sigCtx->pkCtxRsa = ssl;
+    }
+#endif
+
+    return 0;
+}
+
+#endif /* HAVE_PK_CALLBACKS */
+
 
 typedef struct ProcPeerCertArgs {
     buffer*      certs;
 #ifdef WOLFSSL_TLS13
-    buffer*      exts; /* extentions */
+    buffer*      exts; /* extensions */
 #endif
     DecodedCert* dCert;
-    char*  domain;
     word32 idx;
     word32 begin;
     int    totalCerts; /* number of certs in certs buffer */
     int    count;
-    int    dCertInit;
     int    certIdx;
-    int    fatal;
     int    lastErr;
 #ifdef WOLFSSL_ALT_CERT_CHAINS
@@ -7688,11 +8553,204 @@
     byte   ctxSz;
 #endif
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+    char   untrustedDepth;
+#endif
+    word16 fatal:1;
+    word16 verifyErr:1;
+    word16 dCertInit:1;
 #ifdef WOLFSSL_TRUST_PEER_CERT
-    byte haveTrustPeer; /* was cert verified by loaded trusted peer cert */
-#endif
-#ifdef OPENSSL_EXTRA
-    char   untrustedDepth;
+    word16 haveTrustPeer:1; /* was cert verified by loaded trusted peer cert */
 #endif
 } ProcPeerCertArgs;
+
+/* WOLFSSL_ALWAYS_VERIFY_CB: Use verify callback for success or failure cases */
+/* WOLFSSL_VERIFY_CB_ALL_CERTS: Issue callback for all intermediate certificates */
+
+/* Callback is issued for certificate presented in TLS Certificate (11) packet.
+ * The intermediates are done first then peer leaf cert last. Use the
+ * store->error_depth member to determine index (0=peer, >1 intermediates)
+ */
+
+static int DoVerifyCallback(WOLFSSL* ssl, int ret, ProcPeerCertArgs* args)
+{
+    int verify_ok = 0, alertWhy = 0, use_cb = 0;
+
+    /* Determine return code and alert reason */
+    if (ret != 0) {
+        alertWhy = bad_certificate;
+        if (ret == ASN_AFTER_DATE_E ||
+            ret == ASN_BEFORE_DATE_E) {
+            alertWhy = certificate_expired;
+    }
+    }
+    else {
+        verify_ok = 1;
+    }
+
+    /* Determine if verify callback should be used */
+    if (ret != 0) {
+        if (!ssl->options.verifyNone) {
+            use_cb = 1; /* always report errors */
+        }
+    }
+#ifdef WOLFSSL_ALWAYS_VERIFY_CB
+    /* always use verify callback on peer leaf cert */
+    if (args->certIdx == 0) {
+        use_cb = 1;
+    }
+#endif
+#ifdef WOLFSSL_VERIFY_CB_ALL_CERTS
+    /* perform verify callback on other intermediate certs (not just peer) */
+    if (args->certIdx > 0) {
+        use_cb = 1;
+}
+#endif
+
+    /* if verify callback has been set */
+    if (use_cb && ssl->verifyCallback) {
+    #ifdef WOLFSSL_SMALL_STACK
+        WOLFSSL_X509_STORE_CTX* store;
+        #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+        WOLFSSL_X509* x509;
+        #endif
+        char* domain = NULL;
+#else
+        WOLFSSL_X509_STORE_CTX store[1];
+        #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+        WOLFSSL_X509           x509[1];
+#endif
+        char domain[ASN_NAME_MAX];
+#endif
+
+    #ifdef WOLFSSL_SMALL_STACK
+        store = (WOLFSSL_X509_STORE_CTX*)XMALLOC(
+            sizeof(WOLFSSL_X509_STORE_CTX), ssl->heap, DYNAMIC_TYPE_X509_STORE);
+        if (store == NULL) {
+            return MEMORY_E;
+        }
+        #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+        x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), ssl->heap,
+            DYNAMIC_TYPE_X509);
+        if (x509 == NULL) {
+            XFREE(store, ssl->heap, DYNAMIC_TYPE_X509);
+            return MEMORY_E;
+    }
+#endif
+        domain = (char*)XMALLOC(ASN_NAME_MAX, ssl->heap, DYNAMIC_TYPE_STRING);
+        if (domain == NULL) {
+            XFREE(store, ssl->heap, DYNAMIC_TYPE_X509);
+            #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+            XFREE(x509, ssl->heap, DYNAMIC_TYPE_X509);
+    #endif
+            return MEMORY_E;
+    }
+    #endif /* WOLFSSL_SMALL_STACK */
+
+        XMEMSET(store, 0, sizeof(WOLFSSL_X509_STORE_CTX));
+    #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+        XMEMSET(x509, 0, sizeof(WOLFSSL_X509));
+        #endif
+        domain[0] = '\0';
+
+        /* build subject CN as string to return in store */
+        if (args->dCertInit && args->dCert && args->dCert->subjectCN) {
+            int subjectCNLen = args->dCert->subjectCNLen;
+            if (subjectCNLen > ASN_NAME_MAX-1)
+                subjectCNLen = ASN_NAME_MAX-1;
+            if (subjectCNLen > 0) {
+                XMEMCPY(domain, args->dCert->subjectCN, subjectCNLen);
+                domain[subjectCNLen] = '\0';
+            }
+        }
+
+        store->error = ret;
+        store->error_depth = args->certIdx;
+        store->discardSessionCerts = 0;
+        store->domain = domain;
+        store->userCtx = ssl->verifyCbCtx;
+        store->certs = args->certs;
+        store->totalCerts = args->totalCerts;
+        store->ex_data = ssl;
+
+    #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+        if (ssl->ctx->x509_store_pt != NULL) {
+            store->store = ssl->ctx->x509_store_pt;
+        }
+        else {
+            store->store = &ssl->ctx->x509_store;
+        }
+    #endif
+    #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+        #ifdef KEEP_PEER_CERT
+        if (args->certIdx == 0) {
+            store->current_cert = &ssl->peerCert; /* use existing X509 */
+        }
+        else
+        #endif
+        {
+            InitX509(x509, 0, ssl->heap);
+            if (CopyDecodedToX509(x509, args->dCert) == 0) {
+                store->current_cert = x509;
+            }
+        }
+    #endif
+    #ifdef SESSION_CERTS
+        store->sesChain = &ssl->session.chain;
+    #endif
+        /* non-zero return code indicates failure override */
+        if (ssl->verifyCallback(verify_ok, store)) {
+            if (ret != 0) {
+                WOLFSSL_MSG("Verify callback overriding error!");
+                ret = 0;
+            }
+        }
+        else {
+            /* induce error if one not present */
+            if (ret == 0) {
+                ret = VERIFY_CERT_ERROR;
+            }
+
+            /* mark as verify error */
+            args->verifyErr = 1;
+        }
+    #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+        if (args->certIdx > 0)
+            FreeX509(x509);
+    #endif
+    #if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)
+        wolfSSL_sk_X509_free(store->chain);
+        store->chain = NULL;
+    #endif
+    #ifdef SESSION_CERTS
+        if (store->discardSessionCerts) {
+            WOLFSSL_MSG("Verify callback requested discard sess certs");
+            ssl->session.chain.count = 0;
+        #ifdef WOLFSSL_ALT_CERT_CHAINS
+            ssl->session.altChain.count = 0;
+        #endif
+        }
+    #endif /* SESSION_CERTS */
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(domain, ssl->heap, DYNAMIC_TYPE_STRING);
+        #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+        XFREE(x509, ssl->heap, DYNAMIC_TYPE_X509);
+        #endif
+        XFREE(store, ssl->heap, DYNAMIC_TYPE_X509_STORE);
+    #endif
+    }
+
+    if (ret != 0) {
+        if (!ssl->options.verifyNone) {
+            /* handle failure */
+            SendAlert(ssl, alert_fatal, alertWhy); /* try to send */
+            ssl->options.isClosed = 1;
+        }
+
+        /* Report SSL error */
+        ssl->error = ret;
+    }
+
+    return ret;
+}
 
 static void FreeProcPeerCertArgs(WOLFSSL* ssl, void* pArgs)
@@ -7702,8 +8760,4 @@
     (void)ssl;
 
-    if (args->domain) {
-        XFREE(args->domain, ssl->heap, DYNAMIC_TYPE_STRING);
-        args->domain = NULL;
-    }
     if (args->certs) {
         XFREE(args->certs, ssl->heap, DYNAMIC_TYPE_DER);
@@ -7729,9 +8783,13 @@
                      word32 totalSz)
 {
-    int ret = 0;
+    int ret = 0, sigRet = 0;
 #ifdef WOLFSSL_ASYNC_CRYPT
     ProcPeerCertArgs* args = (ProcPeerCertArgs*)ssl->async.args;
     typedef char args_test[sizeof(ssl->async.args) >= sizeof(*args) ? 1 : -1];
     (void)sizeof(args_test);
+#elif defined(WOLFSSL_NONBLOCK_OCSP)
+    ProcPeerCertArgs* args = ssl->nonblockarg;
+#elif defined(WOLFSSL_SMALL_STACK)
+    ProcPeerCertArgs* args = NULL;
 #else
     ProcPeerCertArgs  args[1];
@@ -7753,4 +8811,19 @@
     }
     else
+#elif defined(WOLFSSL_NONBLOCK_OCSP)
+    if (args == NULL) {
+        args = (ProcPeerCertArgs*)XMALLOC(
+            sizeof(ProcPeerCertArgs), ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        if (args == NULL) {
+            ERROR_OUT(MEMORY_E, exit_ppc);
+        }
+    }
+    if (ssl->nonblockarg == NULL) /* new args */
+#elif defined(WOLFSSL_SMALL_STACK)
+    args = (ProcPeerCertArgs*)XMALLOC(
+        sizeof(ProcPeerCertArgs), ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (args == NULL) {
+        ERROR_OUT(MEMORY_E, exit_ppc);
+    }
 #endif
     {
@@ -7763,4 +8836,6 @@
     #ifdef WOLFSSL_ASYNC_CRYPT
         ssl->async.freeArgs = FreeProcPeerCertArgs;
+    #elif defined(WOLFSSL_NONBLOCK_OCSP)
+        ssl->nonblockarg = args;
     #endif
     }
@@ -7774,5 +8849,5 @@
         #ifdef WOLFSSL_CALLBACKS
             if (ssl->hsInfoOn)
-                AddPacketName("Certificate", &ssl->handShakeInfo);
+                AddPacketName(ssl, "Certificate");
             if (ssl->toInfoOn)
                 AddLateName("Certificate", &ssl->timeoutInfo);
@@ -7842,4 +8917,12 @@
 
             /* allocate buffer for certs */
+        #ifdef OPENSSL_EXTRA
+            args->certs = (buffer*)XMALLOC(sizeof(buffer) *
+                    (ssl->verifyDepth + 1), ssl->heap, DYNAMIC_TYPE_DER);
+            if (args->certs == NULL) {
+                ERROR_OUT(MEMORY_E, exit_ppc);
+            }
+            XMEMSET(args->certs, 0, sizeof(buffer) * (ssl->verifyDepth + 1));
+        #else
             args->certs = (buffer*)XMALLOC(sizeof(buffer) * MAX_CHAIN_DEPTH,
                                             ssl->heap, DYNAMIC_TYPE_DER);
@@ -7848,5 +8931,5 @@
             }
             XMEMSET(args->certs, 0, sizeof(buffer) * MAX_CHAIN_DEPTH);
-
+        #endif /* OPENSSL_EXTRA */
             /* Certificate List */
             if ((args->idx - args->begin) + OPAQUE24_LEN > totalSz) {
@@ -7855,5 +8938,5 @@
             c24to32(input + args->idx, &listSz);
             args->idx += OPAQUE24_LEN;
-            if (listSz > MAX_RECORD_SIZE) {
+            if (listSz > MAX_CERTIFICATE_SZ) {
                 ERROR_OUT(BUFFER_ERROR, exit_ppc);
             }
@@ -7868,10 +8951,15 @@
                 word32 certSz;
 
-                if (args->totalCerts >= MAX_CHAIN_DEPTH) {
                 #ifdef OPENSSL_EXTRA
+                if (args->totalCerts > ssl->verifyDepth) {
                     ssl->peerVerifyRet = X509_V_ERR_CERT_CHAIN_TOO_LONG;
-                #endif
                     ERROR_OUT(MAX_CHAIN_ERROR, exit_ppc);
                 }
+            #else
+                if (args->totalCerts >= ssl->verifyDepth ||
+                        args->totalCerts >= MAX_CHAIN_DEPTH) {
+                    ERROR_OUT(MAX_CHAIN_ERROR, exit_ppc);
+                }
+            #endif
 
                 if ((args->idx - args->begin) + OPAQUE24_LEN > totalSz) {
@@ -7913,4 +9001,8 @@
                     args->idx += extSz;
                     listSz -= extSz + OPAQUE16_LEN;
+                    ret = TLSX_Parse(ssl, args->exts[args->totalCerts].buffer,
+                        args->exts[args->totalCerts].length, certificate, NULL);
+                    if (ret < 0)
+                        return ret;
                 }
             #endif
@@ -7924,4 +9016,5 @@
 
             args->dCertInit = 0;
+#ifndef WOLFSSL_SMALL_CERT_VERIFY
             args->dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), ssl->heap,
                                                        DYNAMIC_TYPE_DCERT);
@@ -7929,4 +9022,5 @@
                 ERROR_OUT(MEMORY_E, exit_ppc);
             }
+#endif
 
             /* Advance state and proceed */
@@ -7947,4 +9041,15 @@
 
                     if (!args->dCertInit) {
+#ifdef WOLFSSL_SMALL_CERT_VERIFY
+                        if (args->dCert == NULL) {
+                            args->dCert = (DecodedCert*)XMALLOC(
+                                                 sizeof(DecodedCert), ssl->heap,
+                                                 DYNAMIC_TYPE_DCERT);
+                            if (args->dCert == NULL) {
+                                ERROR_OUT(MEMORY_E, exit_ppc);
+                            }
+                        }
+#endif
+
                         InitDecodedCert(args->dCert,
                             cert->buffer, cert->length, ssl->heap);
@@ -7954,11 +9059,13 @@
                     #endif
                         args->dCertInit = 1;
+                    #ifdef HAVE_PK_CALLBACKS
+                        ret = InitSigPkCb(ssl, &args->dCert->sigCtx);
+                        if (ret != 0)
+                            goto exit_ppc;
+                    #endif
                     }
 
                     ret = ParseCertRelative(args->dCert, CERT_TYPE, 0,
                                                             ssl->ctx->cm);
-                    if (ret != 0 && ret != WC_PENDING_E)
-                        goto exit_ppc;
-
                 #ifdef WOLFSSL_ASYNC_CRYPT
                     if (ret == WC_PENDING_E) {
@@ -7968,4 +9075,6 @@
                     }
                 #endif
+                    if (ret != 0)
+                        goto exit_ppc;
 
                 #ifndef NO_SKID
@@ -8015,4 +9124,15 @@
 
                     if (!args->dCertInit) {
+#ifdef WOLFSSL_SMALL_CERT_VERIFY
+                        if (args->dCert == NULL) {
+                            args->dCert = (DecodedCert*)XMALLOC(
+                                                 sizeof(DecodedCert), ssl->heap,
+                                                 DYNAMIC_TYPE_DCERT);
+                            if (args->dCert == NULL) {
+                                ERROR_OUT(MEMORY_E, exit_ppc);
+                            }
+                        }
+#endif
+
                         InitDecodedCert(args->dCert,
                             cert->buffer, cert->length, ssl->heap);
@@ -8022,11 +9142,13 @@
                     #endif
                         args->dCertInit = 1;
+                    #ifdef HAVE_PK_CALLBACKS
+                        ret = InitSigPkCb(ssl, &args->dCert->sigCtx);
+                        if (ret != 0)
+                            goto exit_ppc;
+                    #endif
                     }
 
                     ret = ParseCertRelative(args->dCert, CERT_TYPE, 0,
                                                                   ssl->ctx->cm);
-                    if (ret != 0 && ret != WC_PENDING_E) {
-                        goto exit_ppc;
-                    }
                 #ifdef WOLFSSL_ASYNC_CRYPT
                     if (ret == WC_PENDING_E) {
@@ -8036,4 +9158,7 @@
                     }
                 #endif
+                    if (ret != 0) {
+                        goto exit_ppc;
+                    }
 
                 #ifndef NO_SKID
@@ -8044,4 +9169,5 @@
                     if (!AlreadySigner(ssl->ctx->cm, subjectHash))
                         args->untrustedDepth = 1;
+
                     FreeDecodedCert(args->dCert);
                     args->dCertInit = 0;
@@ -8061,5 +9187,32 @@
                     cert = &args->certs[args->certIdx];
 
+#ifdef WOLFSSL_SMALL_CERT_VERIFY
+                    sigRet = 0;
+
+                    if (!ssl->options.verifyNone) {
+                        if (args->dCert != NULL) {
+                            if (args->dCertInit) {
+                                FreeDecodedCert(args->dCert);
+                                args->dCertInit = 0;
+                            }
+                            XFREE(args->dCert, ssl->heap, DYNAMIC_TYPE_DCERT);
+                            args->dCert = NULL;
+                        }
+                        sigRet = CheckCertSignature(cert->buffer, cert->length,
+                                                       ssl->heap, ssl->ctx->cm);
+                    }
+#endif
                     if (!args->dCertInit) {
+#ifdef WOLFSSL_SMALL_CERT_VERIFY
+                        if (args->dCert == NULL) {
+                            args->dCert = (DecodedCert*)XMALLOC(
+                                                 sizeof(DecodedCert), ssl->heap,
+                                                 DYNAMIC_TYPE_DCERT);
+                            if (args->dCert == NULL) {
+                                ERROR_OUT(MEMORY_E, exit_ppc);
+                            }
+                        }
+#endif
+
                         InitDecodedCert(args->dCert,
                             cert->buffer, cert->length, ssl->heap);
@@ -8069,10 +9222,31 @@
                     #endif
                         args->dCertInit = 1;
+                    #ifdef HAVE_PK_CALLBACKS
+                        ret = InitSigPkCb(ssl, &args->dCert->sigCtx);
+                        if (ret != 0)
+                            goto exit_ppc;
+                    #endif
                     }
 
+                    /* check if returning from non-blocking OCSP */
+                #ifdef WOLFSSL_NONBLOCK_OCSP
+                    if (args->lastErr != OCSP_WANT_READ)
+                    {
+                #endif
+
+#ifndef WOLFSSL_SMALL_CERT_VERIFY
+                    sigRet = ParseCertRelative(args->dCert, CERT_TYPE,
+                                    !ssl->options.verifyNone, ssl->ctx->cm);
+#else
                     ret = ParseCertRelative(args->dCert, CERT_TYPE,
-                                    !ssl->options.verifyNone, ssl->ctx->cm);
+                             !ssl->options.verifyNone ? VERIFY_NAME : NO_VERIFY,
+                             ssl->ctx->cm);
+                    if (ret != 0) {
+                        sigRet = ret;
+                        ret = 0;
+                    }
+#endif
                 #ifdef WOLFSSL_ASYNC_CRYPT
-                    if (ret == WC_PENDING_E) {
+                    if (sigRet == WC_PENDING_E) {
                         ret = wolfSSL_AsyncPush(ssl,
                             args->dCert->sigCtx.asyncDev);
@@ -8098,5 +9272,5 @@
                                     WOLFSSL_MSG(
                                         "RSA key size in cert chain error");
-                                    ret = RSA_KEY_SIZE_E;
+                                    sigRet = RSA_KEY_SIZE_E;
                                 }
                                 break;
@@ -8109,5 +9283,5 @@
                                     WOLFSSL_MSG(
                                         "ECC key size in cert chain error");
-                                    ret = ECC_KEY_SIZE_E;
+                                    sigRet = ECC_KEY_SIZE_E;
                                 }
                                 break;
@@ -8120,5 +9294,5 @@
                                     WOLFSSL_MSG(
                                         "ECC key size in cert chain error");
-                                    ret = ECC_KEY_SIZE_E;
+                                    sigRet = ECC_KEY_SIZE_E;
                                 }
                                 break;
@@ -8132,11 +9306,11 @@
                     } /* if (!ssl->options.verifyNone) */
 
-                    if (ret == 0 && args->dCert->isCA == 0) {
+                    if (sigRet == 0 && args->dCert->isCA == 0) {
                         WOLFSSL_MSG("Chain cert is not a CA, not adding as one");
                     }
-                    else if (ret == 0 && ssl->options.verifyNone) {
+                    else if (sigRet == 0 && ssl->options.verifyNone) {
                         WOLFSSL_MSG("Chain cert not verified by option, not adding as CA");
                     }
-                    else if (ret == 0 && !AlreadySigner(ssl->ctx->cm, subjectHash)) {
+                    else if (sigRet == 0 && !AlreadySigner(ssl->ctx->cm, subjectHash)) {
                         DerBuffer* add = NULL;
                         ret = AllocDer(&add, cert->length, CA_TYPE, ssl->heap);
@@ -8148,7 +9322,7 @@
                         XMEMCPY(add->buffer, cert->buffer, cert->length);
 
-                    #ifdef WOLFSSL_NGINX
+                    #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX)
                         if (args->certIdx > args->untrustedDepth)
-                            args->untrustedDepth = args->certIdx + 1;
+                            args->untrustedDepth = (char)args->certIdx + 1;
                     #endif
 
@@ -8166,4 +9340,5 @@
 
                             /* clear last CA fail since CA cert was validated */
+                            if (!args->verifyErr)
                             args->lastCaErr = 0;
 
@@ -8175,16 +9350,6 @@
                     #endif
                     }
-                    else if (ret != 0) {
+                    else if (sigRet != 0) {
                         WOLFSSL_MSG("Failed to verify CA from chain");
-                    #ifdef WOLFSSL_ALT_CERT_CHAINS
-                        if (args->lastCaErr == 0) {
-                            /* store CA error and proceed to next cert */
-                            args->lastCaErr = ret;
-                            ret = 0;
-                        }
-                        else {
-                            args->lastErr = args->lastCaErr;
-                        }
-                    #endif
                     #ifdef OPENSSL_EXTRA
                         ssl->peerVerifyRet = X509_V_ERR_INVALID_CA;
@@ -8195,6 +9360,13 @@
                     }
 
+                #ifdef WOLFSSL_NONBLOCK_OCSP
+                    }
+                    else {
+                        args->lastErr = 0; /* clear last error */
+                    }
+                #endif
+
             #if defined(HAVE_OCSP) || defined(HAVE_CRL)
-                    if (ret == 0) {
+                    if (ret == 0 && sigRet == 0) {
                         int doCrlLookup = 1;
                 #ifdef HAVE_OCSP
@@ -8211,7 +9383,7 @@
                             ret = CheckCertOCSP_ex(ssl->ctx->cm->ocsp,
                                                     args->dCert, NULL, ssl);
-                        #ifdef WOLFSSL_ASYNC_CRYPT
-                            /* non-blocking socket re-entry requires async */
-                            if (ret == WANT_READ) {
+                        #ifdef WOLFSSL_NONBLOCK_OCSP
+                            if (ret == OCSP_WANT_READ) {
+                                args->lastErr = ret;
                                 goto exit_ppc;
                             }
@@ -8231,7 +9403,7 @@
                             WOLFSSL_MSG("Doing Non Leaf CRL check");
                             ret = CheckCertCRL(ssl->ctx->cm->crl, args->dCert);
-                        #ifdef WOLFSSL_ASYNC_CRYPT
-                            /* non-blocking socket re-entry requires async */
-                            if (ret == WANT_READ) {
+                        #ifdef WOLFSSL_NONBLOCK_OCSP
+                            if (ret == OCSP_WANT_READ) {
+                                args->lastErr = ret;
                                 goto exit_ppc;
                             }
@@ -8243,10 +9415,27 @@
                 #endif /* HAVE_CRL */
                         (void)doCrlLookup;
+
+                        if (ret != 0)
+                            sigRet = ret;
                     }
             #endif /* HAVE_OCSP || HAVE_CRL */
 
-                    if (ret != 0 && args->lastErr == 0) {
-                        args->lastErr = ret;   /* save error from last time */
-                        ret = 0; /* reset error */
+                    /* Do verify callback */
+                    sigRet = DoVerifyCallback(ssl, sigRet, args);
+
+                    /* Handle error codes */
+                #ifdef WOLFSSL_ALT_CERT_CHAINS
+                    if (args->lastCaErr == 0) {
+                        /* capture CA error and proceed to next cert */
+                        args->lastCaErr = sigRet;
+                        sigRet = 0;
+                    }
+                    else {
+                        args->lastErr = args->lastCaErr;
+                    }
+                #endif
+                    if (sigRet != 0 && args->lastErr == 0) {
+                        args->lastErr = sigRet;  /* save error from last time */
+                        sigRet = 0; /* reset error */
                     }
 
@@ -8257,4 +9446,6 @@
             } /* if (count > 0) */
 
+            if (sigRet != 0)
+                ret = sigRet;
             /* Check for error */
             if (ret != 0) {
@@ -8276,5 +9467,29 @@
                 cert = &args->certs[args->certIdx];
 
+#ifdef WOLFSSL_SMALL_CERT_VERIFY
+                sigRet = 0;
+
+                if (!ssl->options.verifyNone) {
+                    if (args->dCert != NULL) {
+                        if (args->dCertInit) {
+                            FreeDecodedCert(args->dCert);
+                            args->dCertInit = 0;
+                        }
+                        XFREE(args->dCert, ssl->heap, DYNAMIC_TYPE_DCERT);
+                        args->dCert = NULL;
+                    }
+                    sigRet = CheckCertSignature(cert->buffer, cert->length,
+                                                       ssl->heap, ssl->ctx->cm);
+                }
+#endif
                 if (!args->dCertInit) {
+                    if (args->dCert == NULL) {
+                        args->dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert),
+                                                 ssl->heap, DYNAMIC_TYPE_DCERT);
+                        if (args->dCert == NULL) {
+                            ERROR_OUT(MEMORY_E, exit_ppc);
+                        }
+                    }
+
                     InitDecodedCert(args->dCert,
                         cert->buffer, cert->length, ssl->heap);
@@ -8284,4 +9499,9 @@
                 #endif
                     args->dCertInit = 1;
+                #ifdef HAVE_PK_CALLBACKS
+                    ret = InitSigPkCb(ssl, &args->dCert->sigCtx);
+                    if (ret != 0)
+                        goto exit_ppc;
+                #endif
                 }
 
@@ -8291,8 +9511,18 @@
                 {
                     /* only parse if not already present in dCert from above */
+#ifndef WOLFSSL_SMALL_CERT_VERIFY
+                    sigRet = ParseCertRelative(args->dCert, CERT_TYPE,
+                                    !ssl->options.verifyNone, ssl->ctx->cm);
+#else
                     ret = ParseCertRelative(args->dCert, CERT_TYPE,
-                                    !ssl->options.verifyNone, ssl->ctx->cm);
+                             !ssl->options.verifyNone ? VERIFY_NAME : NO_VERIFY,
+                             ssl->ctx->cm);
+                    if (ret != 0) {
+                        sigRet = ret;
+                        ret = 0;
+                    }
+#endif
                 #ifdef WOLFSSL_ASYNC_CRYPT
-                    if (ret == WC_PENDING_E) {
+                    if (sigRet == WC_PENDING_E) {
                         ret = wolfSSL_AsyncPush(ssl,
                             args->dCert->sigCtx.asyncDev);
@@ -8302,5 +9532,5 @@
                 }
 
-                if (ret == 0) {
+                if (sigRet == 0) {
                     WOLFSSL_MSG("Verified Peer's cert");
                 #ifdef OPENSSL_EXTRA
@@ -8313,9 +9543,25 @@
                     }
                 #endif /* SESSION_CERTS && WOLFSSL_ALT_CERT_CHAINS */
+
+                    /* check if fatal error */
+                    if (args->verifyErr) {
+                        args->fatal = 1;
+                        if (sigRet == 0) {
+                            sigRet = args->lastErr;
+                        }
+                    #ifdef WOLFSSL_ALT_CERT_CHAINS
+                        if (sigRet == 0) {
+                            sigRet = args->lastCaErr;
+                        }
+                    #endif
+                    }
+                    else {
                     args->fatal = 0;
                 }
-                else if (ret == ASN_PARSE_E || ret == BUFFER_E) {
+                }
+                else if (sigRet == ASN_PARSE_E || sigRet == BUFFER_E) {
                     WOLFSSL_MSG("Got Peer cert ASN PARSE or BUFFER ERROR");
                 #ifdef OPENSSL_EXTRA
+                    SendAlert(ssl, alert_fatal, bad_certificate);
                     ssl->peerVerifyRet = X509_V_ERR_CERT_REJECTED;
                 #endif
@@ -8330,9 +9576,13 @@
                         WOLFSSL_MSG(
                             "\tCallback override available, will continue");
-                        args->fatal = 0;
+                        /* check if fatal error */
+                        args->fatal = (args->verifyErr) ? 1 : 0;
                     }
                     else {
                         WOLFSSL_MSG("\tNo callback override available, fatal");
                         args->fatal = 1;
+                    #ifdef OPENSSL_EXTRA
+                        SendAlert(ssl, alert_fatal, bad_certificate);
+                    #endif
                     }
                 }
@@ -8350,5 +9600,5 @@
                                 "Peer sent different cert during scr, fatal");
                             args->fatal = 1;
-                            ret   = SCR_DIFFERENT_CERT_E;
+                            sigRet   = SCR_DIFFERENT_CERT_E;
                         }
                     }
@@ -8361,5 +9611,21 @@
                 }
             #endif /* HAVE_SECURE_RENEGOTIATION */
-
+            } /* if (count > 0) */
+
+            if (sigRet != 0)
+                ret = sigRet;
+            /* Check for error */
+            if (args->fatal && ret != 0) {
+                goto exit_ppc;
+            }
+
+            /* Advance state and proceed */
+            ssl->options.asyncState = TLS_ASYNC_VERIFY;
+        } /* case TLS_ASYNC_DO */
+        FALL_THROUGH;
+
+        case TLS_ASYNC_VERIFY:
+        {
+            if (args->count > 0) {
             #if defined(HAVE_OCSP) || defined(HAVE_CRL)
                 if (args->fatal == 0) {
@@ -8372,4 +9638,19 @@
                                                     args->dCert, ssl->heap);
                             doLookup = 0;
+                        #ifdef WOLFSSL_TLS13
+                            if (ssl->options.tls1_3) {
+                                TLSX* ext = TLSX_Find(ssl->extensions,
+                                                           TLSX_STATUS_REQUEST);
+                                if (ext != NULL) {
+                                    word32 idx = 0;
+                                    CertificateStatusRequest* csr =
+                                           (CertificateStatusRequest*)ext->data;
+                                    ret = ProcessCSR(ssl, csr->response.buffer,
+                                                    &idx, csr->response.length);
+                                    if (ret < 0)
+                                        goto exit_ppc;
+                                }
+                            }
+                        #endif
                         }
                 #endif /* HAVE_CERTIFICATE_STATUS_REQUEST */
@@ -8388,7 +9669,6 @@
                         ret = CheckCertOCSP_ex(ssl->ctx->cm->ocsp,
                                                     args->dCert, NULL, ssl);
-                    #ifdef WOLFSSL_ASYNC_CRYPT
-                        /* non-blocking socket re-entry requires async */
-                        if (ret == WANT_READ) {
+                    #ifdef WOLFSSL_NONBLOCK_OCSP
+                        if (ret == OCSP_WANT_READ) {
                             goto exit_ppc;
                         }
@@ -8409,7 +9689,6 @@
                         WOLFSSL_MSG("Doing Leaf CRL check");
                         ret = CheckCertCRL(ssl->ctx->cm->crl, args->dCert);
-                    #ifdef WOLFSSL_ASYNC_CRYPT
-                        /* non-blocking socket re-entry requires async */
-                        if (ret == WANT_READ) {
+                    #ifdef WOLFSSL_NONBLOCK_OCSP
+                        if (ret == OCSP_WANT_READ) {
                             goto exit_ppc;
                         }
@@ -8433,10 +9712,21 @@
                     int copyRet = CopyDecodedToX509(&ssl->peerCert,
                                                                 args->dCert);
-                    if (copyRet == MEMORY_E)
+                    if (copyRet == MEMORY_E) {
                         args->fatal = 1;
                 }
+                }
             #endif /* KEEP_PEER_CERT */
 
             #ifndef IGNORE_KEY_EXTENSIONS
+                #if defined(OPENSSL_EXTRA)
+                  /* when compatibility layer is turned on and no verify is
+                   * set then ignore the certificate key extension */
+                    if (args->dCert->extKeyUsageSet &&
+                          args->dCert->extKeyUsageCrit == 0 &&
+                          ssl->options.verifyNone) {
+                        WOLFSSL_MSG("Not verifying certificate key usage");
+                    }
+                    else
+                #endif
                 if (args->dCert->extKeyUsageSet) {
                     if ((ssl->specs.kea == rsa_kea) &&
@@ -8454,4 +9744,14 @@
                 }
 
+                #if defined(OPENSSL_EXTRA)
+                    /* when compatibility layer is turned on and no verify is
+                     * set then ignore the certificate key extension */
+                    if (args->dCert->extExtKeyUsageSet &&
+                            args->dCert->extExtKeyUsageCrit == 0 &&
+                          ssl->options.verifyNone) {
+                                WOLFSSL_MSG("Not verifying certificate ext key usage");
+                    }
+                    else
+                #endif
                 if (args->dCert->extExtKeyUsageSet) {
                     if (ssl->options.side == WOLFSSL_CLIENT_END) {
@@ -8475,4 +9775,5 @@
                     ssl->error = ret;
                 #ifdef OPENSSL_EXTRA
+                    SendAlert(ssl, alert_fatal, bad_certificate);
                     ssl->peerVerifyRet = X509_V_ERR_CERT_REJECTED;
                 #endif
@@ -8481,35 +9782,29 @@
 
                 ssl->options.havePeerCert = 1;
-            } /* if (count > 0) */
-
-            /* Check for error */
-            if (args->fatal && ret != 0) {
-                goto exit_ppc;
-            }
-
-            /* Advance state and proceed */
-            ssl->options.asyncState = TLS_ASYNC_VERIFY;
-        } /* case TLS_ASYNC_DO */
-        FALL_THROUGH;
-
-        case TLS_ASYNC_VERIFY:
-        {
-            if (args->count > 0) {
-                args->domain = (char*)XMALLOC(ASN_NAME_MAX, ssl->heap,
-                                                    DYNAMIC_TYPE_STRING);
-                if (args->domain == NULL) {
-                    ERROR_OUT(MEMORY_E, exit_ppc);
+
+                if (!ssl->options.verifyNone && ssl->buffers.domainName.buffer) {
+                #ifndef WOLFSSL_ALLOW_NO_CN_IN_SAN
+                    /* Per RFC 5280 section 4.2.1.6, "Whenever such identities
+                     * are to be bound into a certificate, the subject
+                     * alternative name extension MUST be used." */
+                    if (args->dCert->altNames) {
+                        if (CheckAltNames(args->dCert,
+                                (char*)ssl->buffers.domainName.buffer) == 0 ) {
+                            WOLFSSL_MSG("DomainName match on alt names failed");
+                            /* try to get peer key still */
+                            ret = DOMAIN_NAME_MISMATCH;
                 }
-
-                /* store for callback use */
-                if (args->dCert->subjectCNLen < ASN_NAME_MAX) {
-                    XMEMCPY(args->domain, args->dCert->subjectCN, args->dCert->subjectCNLen);
-                    args->domain[args->dCert->subjectCNLen] = '\0';
                 }
                 else {
-                    args->domain[0] = '\0';
+                        if (MatchDomainName(
+                                 args->dCert->subjectCN,
+                                 args->dCert->subjectCNLen,
+                                 (char*)ssl->buffers.domainName.buffer) == 0) {
+                            WOLFSSL_MSG("DomainName match on common name failed");
+                            ret = DOMAIN_NAME_MISMATCH;
                 }
-
-                if (!ssl->options.verifyNone && ssl->buffers.domainName.buffer) {
+                    }
+                #else /* WOLFSSL_ALL_NO_CN_IN_SAN */
+                    /* Old behavior. */
                     if (MatchDomainName(args->dCert->subjectCN,
                                 args->dCert->subjectCNLen,
@@ -8524,4 +9819,5 @@
                         }
                     }
+                #endif /* WOLFSSL_ALL_NO_CN_IN_SAN */
                 }
 
@@ -8599,6 +9895,7 @@
                     case ECDSAk:
                     {
-                        int curveId;
                         int keyRet = 0;
+                        word32 idx = 0;
+
                         if (ssl->peerEccDsaKey == NULL) {
                             /* alloc/init on demand */
@@ -8611,9 +9908,8 @@
                         }
 
-                        curveId = wc_ecc_get_oid(args->dCert->keyOID, NULL, NULL);
                         if (keyRet != 0 ||
-                            wc_ecc_import_x963_ex(args->dCert->publicKey,
-                                    args->dCert->pubKeySize, ssl->peerEccDsaKey,
-                                                            curveId) != 0) {
+                            wc_EccPublicKeyDecode(args->dCert->publicKey, &idx,
+                                                ssl->peerEccDsaKey,
+                                                args->dCert->pubKeySize) != 0) {
                             ret = PEER_KEY_ERROR;
                         }
@@ -8697,17 +9993,10 @@
                         break;
                     }
-                #endif /* HAVE_ECC */
+                #endif /* HAVE_ED25519 */
                     default:
                         break;
                 }
 
-                FreeDecodedCert(args->dCert);
-                args->dCertInit = 0;
-
-                /* release since we don't need it anymore */
-                if (args->dCert) {
-                    XFREE(args->dCert, ssl->heap, DYNAMIC_TYPE_DCERT);
-                    args->dCert = NULL;
-                }
+                /* args->dCert free'd in function cleanup after callback */
             } /* if (count > 0) */
 
@@ -8724,17 +10013,4 @@
         case TLS_ASYNC_FINALIZE:
         {
-        #ifdef WOLFSSL_SMALL_STACK
-            WOLFSSL_X509_STORE_CTX* store = (WOLFSSL_X509_STORE_CTX*)XMALLOC(
-                                    sizeof(WOLFSSL_X509_STORE_CTX), ssl->heap,
-                                                    DYNAMIC_TYPE_X509_STORE);
-            if (store == NULL) {
-                ERROR_OUT(MEMORY_E, exit_ppc);
-            }
-        #else
-            WOLFSSL_X509_STORE_CTX  store[1];
-        #endif
-
-            XMEMSET(store, 0, sizeof(WOLFSSL_X509_STORE_CTX));
-
             /* load last error */
             if (args->lastErr != 0 && ret == 0) {
@@ -8748,97 +10024,7 @@
             }
         #endif
-            if (ret != 0) {
-                if (!ssl->options.verifyNone) {
-                    int why = bad_certificate;
-
-                    if (ret == ASN_AFTER_DATE_E || ret == ASN_BEFORE_DATE_E) {
-                        why = certificate_expired;
-                    }
-                    if (ssl->verifyCallback) {
-                        int ok;
-
-                        store->error = ret;
-                        store->error_depth = args->totalCerts;
-                        store->discardSessionCerts = 0;
-                        store->domain = args->domain;
-                        store->userCtx = ssl->verifyCbCtx;
-                        store->certs = args->certs;
-                        store->totalCerts = args->totalCerts;
-                    #ifdef KEEP_PEER_CERT
-                        if (ssl->peerCert.subject.sz > 0)
-                            store->current_cert = &ssl->peerCert;
-                        else
-                            store->current_cert = NULL;
-                    #else
-                        store->current_cert = NULL;
-                    #endif /* KEEP_PEER_CERT */
-                    #if defined(HAVE_EX_DATA) || defined(HAVE_FORTRESS)
-                        store->ex_data = ssl;
-                    #endif
-                        ok = ssl->verifyCallback(0, store);
-                        if (ok) {
-                            WOLFSSL_MSG("Verify callback overriding error!");
-                            ret = 0;
-                        }
-                    #ifdef SESSION_CERTS
-                        if (store->discardSessionCerts) {
-                            WOLFSSL_MSG("Verify callback requested discard sess certs");
-                            ssl->session.chain.count = 0;
-                        #ifdef WOLFSSL_ALT_CERT_CHAINS
-                            ssl->session.altChain.count = 0;
-                        #endif
-                        }
-                    #endif /* SESSION_CERTS */
-                    }
-                    if (ret != 0) {
-                        SendAlert(ssl, alert_fatal, why);   /* try to send */
-                        ssl->options.isClosed = 1;
-                    }
-                }
-                ssl->error = ret;
-            }
-        #ifdef WOLFSSL_ALWAYS_VERIFY_CB
-            else {
-                if (ssl->verifyCallback) {
-                    int ok;
-
-                    store->error = ret;
-                #ifdef WOLFSSL_WPAS
-                    store->error_depth = 0;
-                #else
-                    store->error_depth = args->totalCerts;
-                #endif
-                    store->discardSessionCerts = 0;
-                    store->domain = args->domain;
-                    store->userCtx = ssl->verifyCbCtx;
-                    store->certs = args->certs;
-                    store->totalCerts = args->totalCerts;
-                #ifdef KEEP_PEER_CERT
-                    if (ssl->peerCert.subject.sz > 0)
-                        store->current_cert = &ssl->peerCert;
-                    else
-                        store->current_cert = NULL;
-                #endif
-                    store->ex_data = ssl;
-
-                    ok = ssl->verifyCallback(1, store);
-                    if (!ok) {
-                        WOLFSSL_MSG("Verify callback overriding valid certificate!");
-                        ret = -1;
-                        SendAlert(ssl, alert_fatal, bad_certificate);
-                        ssl->options.isClosed = 1;
-                    }
-                #ifdef SESSION_CERTS
-                    if (store->discardSessionCerts) {
-                        WOLFSSL_MSG("Verify callback requested discard sess certs");
-                        ssl->session.chain.count = 0;
-                    #ifdef WOLFSSL_ALT_CERT_CHAINS
-                        ssl->session.altChain.count = 0;
-                    #endif
-                    }
-                #endif /* SESSION_CERTS */
-                }
-            }
-        #endif /* WOLFSSL_ALWAYS_VERIFY_CB */
+
+            /* Do verify callback */
+            ret = DoVerifyCallback(ssl, ret, args);
 
             if (ssl->options.verifyNone &&
@@ -8856,7 +10042,4 @@
             }
 
-        #ifdef WOLFSSL_SMALL_STACK
-            XFREE(store, ssl->heap, DYNAMIC_TYPE_X509_STORE);
-        #endif
             /* Advance state and proceed */
             ssl->options.asyncState = TLS_ASYNC_END;
@@ -8880,14 +10063,24 @@
     WOLFSSL_LEAVE("ProcessPeerCerts", ret);
 
-#ifdef WOLFSSL_ASYNC_CRYPT
-    if (ret == WC_PENDING_E || ret == WANT_READ) {
-        /* Mark message as not recevied so it can process again */
+
+#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLFSSL_NONBLOCK_OCSP)
+    if (ret == WC_PENDING_E || ret == OCSP_WANT_READ) {
+        /* Mark message as not received so it can process again */
         ssl->msgsReceived.got_certificate = 0;
 
         return ret;
     }
-#endif /* WOLFSSL_ASYNC_CRYPT */
+#endif /* WOLFSSL_ASYNC_CRYPT || WOLFSSL_NONBLOCK_OCSP */
 
     FreeProcPeerCertArgs(ssl, args);
+
+#if defined(WOLFSSL_ASYNC_CRYPT)
+#elif defined(WOLFSSL_NONBLOCK_OCSP)
+    XFREE(args, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    ssl->nonblockarg = NULL;
+#elif defined(WOLFSSL_SMALL_STACK)
+    XFREE(args, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
     FreeKeyExchange(ssl);
 
@@ -8895,10 +10088,36 @@
 }
 
+#ifndef WOLFSSL_NO_TLS12
+
+/* handle processing of certificate (11) */
 static int DoCertificate(WOLFSSL* ssl, byte* input, word32* inOutIdx,
                                                                 word32 size)
 {
-    return ProcessPeerCerts(ssl, input, inOutIdx, size);
+    int ret;
+
+    WOLFSSL_START(WC_FUNC_CERTIFICATE_DO);
+    WOLFSSL_ENTER("DoCertificate");
+
+#ifdef SESSION_CERTS
+    /* Reset the session cert chain count in case the session resume failed. */
+    ssl->session.chain.count = 0;
+    #ifdef WOLFSSL_ALT_CERT_CHAINS
+        ssl->session.altChain.count = 0;
+    #endif
+#endif /* SESSION_CERTS */
+
+    ret = ProcessPeerCerts(ssl, input, inOutIdx, size);
+
+#ifdef OPENSSL_EXTRA
+    ssl->options.serverState = SERVER_CERT_COMPLETE;
+#endif
+
+    WOLFSSL_LEAVE("DoCertificate", ret);
+    WOLFSSL_END(WC_FUNC_CERTIFICATE_DO);
+
+    return ret;
 }
 
+/* handle processing of certificate_status (22) */
 static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx,
                                                                     word32 size)
@@ -8908,4 +10127,7 @@
     word32 status_length;
 
+    WOLFSSL_START(WC_FUNC_CERTIFICATE_STATUS_DO);
+    WOLFSSL_ENTER("DoCertificateStatus");
+
     if (size < ENUM_LEN + OPAQUE24_LEN)
         return BUFFER_ERROR;
@@ -8925,6 +10147,16 @@
 
         /* WOLFSSL_CSR_OCSP overlaps with WOLFSSL_CSR2_OCSP */
-        case WOLFSSL_CSR2_OCSP: {
+        case WOLFSSL_CSR2_OCSP:
+            ret = ProcessCSR(ssl, input, inOutIdx, status_length);
+            break;
+
+    #endif
+
+    #if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
+
+        case WOLFSSL_CSR2_OCSP_MULTI: {
             OcspRequest* request;
+            word32 list_length = status_length;
+            byte   idx = 0;
 
             #ifdef WOLFSSL_SMALL_STACK
@@ -8937,85 +10169,4 @@
 
             do {
-                #ifdef HAVE_CERTIFICATE_STATUS_REQUEST
-                    if (ssl->status_request) {
-                        request = (OcspRequest*)TLSX_CSR_GetRequest(
-                                                               ssl->extensions);
-                        ssl->status_request = 0;
-                        break;
-                    }
-                #endif
-
-                #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
-                    if (ssl->status_request_v2) {
-                        request = (OcspRequest*)TLSX_CSR2_GetRequest(
-                                               ssl->extensions, status_type, 0);
-                        ssl->status_request_v2 = 0;
-                        break;
-                    }
-                #endif
-
-                return BUFFER_ERROR;
-            } while(0);
-
-            if (request == NULL)
-                return BAD_CERTIFICATE_STATUS_ERROR; /* not expected */
-
-            #ifdef WOLFSSL_SMALL_STACK
-                status = (CertStatus*)XMALLOC(sizeof(CertStatus), ssl->heap,
-                                                       DYNAMIC_TYPE_OCSP_STATUS);
-                response = (OcspResponse*)XMALLOC(sizeof(OcspResponse), ssl->heap,
-                                                       DYNAMIC_TYPE_OCSP_REQUEST);
-
-                if (status == NULL || response == NULL) {
-                    if (status)
-                        XFREE(status, NULL, DYNAMIC_TYPE_OCSP_STATUS);
-                    if (response)
-                        XFREE(response, NULL, DYNAMIC_TYPE_OCSP_REQUEST);
-
-                    return MEMORY_ERROR;
-                }
-            #endif
-
-            InitOcspResponse(response, status, input +*inOutIdx, status_length);
-
-            if (OcspResponseDecode(response, ssl->ctx->cm, ssl->heap, 0) != 0)
-                ret = BAD_CERTIFICATE_STATUS_ERROR;
-            else if (CompareOcspReqResp(request, response) != 0)
-                ret = BAD_CERTIFICATE_STATUS_ERROR;
-            else if (response->responseStatus != OCSP_SUCCESSFUL)
-                ret = BAD_CERTIFICATE_STATUS_ERROR;
-            else if (response->status->status == CERT_REVOKED)
-                ret = OCSP_CERT_REVOKED;
-            else if (response->status->status != CERT_GOOD)
-                ret = BAD_CERTIFICATE_STATUS_ERROR;
-
-            *inOutIdx += status_length;
-
-            #ifdef WOLFSSL_SMALL_STACK
-                XFREE(status,   ssl->heap, DYNAMIC_TYPE_OCSP_STATUS);
-                XFREE(response, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
-            #endif
-
-        }
-        break;
-
-    #endif
-
-    #if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
-
-        case WOLFSSL_CSR2_OCSP_MULTI: {
-            OcspRequest* request;
-            word32 list_length = status_length;
-            byte   idx = 0;
-
-            #ifdef WOLFSSL_SMALL_STACK
-                CertStatus* status;
-                OcspResponse* response;
-            #else
-                CertStatus status[1];
-                OcspResponse response[1];
-            #endif
-
-            do {
                 if (ssl->status_request_v2) {
                     ssl->status_request_v2 = 0;
@@ -9105,9 +10256,21 @@
         SendAlert(ssl, alert_fatal, bad_certificate_status_response);
 
+    if (IsEncryptionOn(ssl, 0)) {
+        if (*inOutIdx + ssl->keys.padSz > size)
+            return BUFFER_E;
+        *inOutIdx += ssl->keys.padSz;
+    }
+
+    WOLFSSL_LEAVE("DoCertificateStatus", ret);
+    WOLFSSL_END(WC_FUNC_CERTIFICATE_STATUS_DO);
+
     return ret;
 }
 
+#endif /* !WOLFSSL_NO_TLS12 */
+
 #endif /* !NO_CERTS */
 
+#ifndef WOLFSSL_NO_TLS12
 
 static int DoHelloRequest(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
@@ -9116,4 +10279,7 @@
     (void)input;
 
+    WOLFSSL_START(WC_FUNC_HELLO_REQUEST_DO);
+    WOLFSSL_ENTER("DoHelloRequest");
+
     if (size) /* must be 0 */
         return BUFFER_ERROR;
@@ -9134,4 +10300,6 @@
     else if (ssl->secure_renegotiation && ssl->secure_renegotiation->enabled) {
         ssl->secure_renegotiation->startScr = 1;
+        WOLFSSL_LEAVE("DoHelloRequest", 0);
+        WOLFSSL_END(WC_FUNC_HELLO_REQUEST_DO);
         return 0;
     }
@@ -9148,4 +10316,7 @@
     word32 finishedSz = (ssl->options.tls ? TLS_FINISHED_SZ : FINISHED_SZ);
 
+    WOLFSSL_START(WC_FUNC_FINISHED_DO);
+    WOLFSSL_ENTER("DoFinished");
+
     if (finishedSz != size)
         return BUFFER_ERROR;
@@ -9156,5 +10327,5 @@
 
     #ifdef WOLFSSL_CALLBACKS
-        if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo);
+        if (ssl->hsInfoOn) AddPacketName(ssl, "Finished");
         if (ssl->toInfoOn) AddLateName("Finished", &ssl->timeoutInfo);
     #endif
@@ -9176,4 +10347,5 @@
             XMEMCPY(ssl->secure_renegotiation->client_verify_data,
                     input + *inOutIdx, TLS_FINISHED_SZ);
+        ssl->secure_renegotiation->verifySet = 1;
     }
 #endif
@@ -9184,5 +10356,14 @@
     if (ssl->options.side == WOLFSSL_CLIENT_END) {
         ssl->options.serverState = SERVER_FINISHED_COMPLETE;
+#ifdef OPENSSL_EXTRA
+		ssl->cbmode = SSL_CB_MODE_WRITE;
+		ssl->options.clientState = CLIENT_FINISHED_COMPLETE;
+#endif
         if (!ssl->options.resuming) {
+#ifdef OPENSSL_EXTRA
+			if (ssl->CBIS != NULL) {
+				ssl->CBIS(ssl, SSL_CB_CONNECT_LOOP, SSL_SUCCESS);
+			}
+#endif
             ssl->options.handShakeState = HANDSHAKE_DONE;
             ssl->options.handShakeDone  = 1;
@@ -9191,9 +10372,21 @@
     else {
         ssl->options.clientState = CLIENT_FINISHED_COMPLETE;
+#ifdef OPENSSL_EXTRA
+        ssl->cbmode = SSL_CB_MODE_READ;
+        ssl->options.serverState = SERVER_FINISHED_COMPLETE;
+#endif
         if (ssl->options.resuming) {
+#ifdef OPENSSL_EXTRA
+			if (ssl->CBIS != NULL) {
+				ssl->CBIS(ssl, SSL_CB_ACCEPT_LOOP, SSL_SUCCESS);
+			}
+#endif
             ssl->options.handShakeState = HANDSHAKE_DONE;
             ssl->options.handShakeDone  = 1;
         }
     }
+
+    WOLFSSL_LEAVE("DoFinished", 0);
+    WOLFSSL_END(WC_FUNC_FINISHED_DO);
 
     return 0;
@@ -9524,4 +10717,26 @@
                   (ssl->keys.encryptionOn ? ssl->keys.padSz : 0);
 
+#if !defined(WOLFSSL_NO_SERVER) && \
+    defined(HAVE_SECURE_RENEGOTIATION) && \
+    defined(HAVE_SERVER_RENEGOTIATION_INFO)
+    if (ssl->options.handShakeDone && type == client_hello &&
+            ssl->secure_renegotiation &&
+            ssl->secure_renegotiation->enabled)
+    {
+        WOLFSSL_MSG("Reset handshake state");
+        XMEMSET(&ssl->msgsReceived, 0, sizeof(MsgsReceived));
+        ssl->options.serverState = NULL_STATE;
+        ssl->options.clientState = NULL_STATE;
+        ssl->options.connectState = CONNECT_BEGIN;
+        ssl->options.acceptState = ACCEPT_FIRST_REPLY_DONE;
+        ssl->options.handShakeState = NULL_STATE;
+        ssl->secure_renegotiation->cache_status = SCR_CACHE_NEEDED;
+
+        ret = InitHandshakeHashes(ssl);
+        if (ret != 0)
+            return ret;
+    }
+#endif
+
     /* sanity check msg received */
     if ( (ret = SanityCheckMsgReceived(ssl, type)) != 0) {
@@ -9530,11 +10745,13 @@
     }
 
-#ifdef WOLFSSL_CALLBACKS
+#if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
     /* add name later, add on record and handshake header part back on */
     if (ssl->toInfoOn) {
         int add = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
-        AddPacketInfo(0, &ssl->timeoutInfo, input + *inOutIdx - add,
-                      size + add, ssl->heap);
+        AddPacketInfo(ssl, 0, handshake, input + *inOutIdx - add,
+                      size + add, READ_PROTO, ssl->heap);
+        #ifdef WOLFSSL_CALLBACKS
         AddLateRecordHeader(&ssl->curRL, &ssl->timeoutInfo);
+        #endif
     }
 #endif
@@ -9573,9 +10790,23 @@
      * hashed later if the DTLS cookie is correct. */
     if (type != hello_request &&
-            !(IsDtlsNotSctpMode(ssl) && type == client_hello) &&
-            ssl->error != WC_PENDING_E) {
+            !(IsDtlsNotSctpMode(ssl) && type == client_hello)
+    #ifdef WOLFSSL_ASYNC_CRYPT
+            && ssl->error != WC_PENDING_E
+    #endif
+    #ifdef WOLFSSL_NONBLOCK_OCSP
+            && ssl->error != OCSP_WANT_READ
+    #endif
+    ) {
         ret = HashInput(ssl, input + *inOutIdx, size);
         if (ret != 0) return ret;
     }
+
+#ifdef OPENSSL_EXTRA
+    if (ssl->CBIS != NULL){
+		ssl->cbmode = SSL_CB_MODE_READ;
+		ssl->cbtype = type;
+		ssl->CBIS(ssl, SSL_CB_ACCEPT_LOOP, SSL_SUCCESS);
+    }
+#endif
 
     switch (type) {
@@ -9595,4 +10826,22 @@
         WOLFSSL_MSG("processing server hello");
         ret = DoServerHello(ssl, input, inOutIdx, size);
+    #if !defined(WOLFSSL_NO_CLIENT_AUTH) && defined(HAVE_ED25519) && \
+                                                !defined(NO_ED25519_CLIENT_AUTH)
+        if (ssl->options.resuming || !IsAtLeastTLSv1_2(ssl) ||
+                                               IsAtLeastTLSv1_3(ssl->version)) {
+
+        #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLFSSL_NONBLOCK_OCSP)
+            if (ret != WC_PENDING_E && ret != OCSP_WANT_READ)
+        #endif
+            {
+                ssl->options.cacheMessages = 0;
+                if (ssl->hsHashes->messages != NULL) {
+                    XFREE(ssl->hsHashes->messages, ssl->heap,
+                        DYNAMIC_TYPE_HASHES);
+                    ssl->hsHashes->messages = NULL;
+                }
+            }
+        }
+    #endif
         break;
 
@@ -9633,5 +10882,5 @@
     #ifdef WOLFSSL_CALLBACKS
         if (ssl->hsInfoOn)
-            AddPacketName("ServerHelloDone", &ssl->handShakeInfo);
+            AddPacketName(ssl, "ServerHelloDone");
         if (ssl->toInfoOn)
             AddLateName("ServerHelloDone", &ssl->timeoutInfo);
@@ -9656,4 +10905,27 @@
         WOLFSSL_MSG("processing client hello");
         ret = DoClientHello(ssl, input, inOutIdx, size);
+    #if !defined(WOLFSSL_NO_CLIENT_AUTH) && defined(HAVE_ED25519) && \
+                                                !defined(NO_ED25519_CLIENT_AUTH)
+        if (ssl->options.resuming || !ssl->options.verifyPeer || \
+                     !IsAtLeastTLSv1_2(ssl) || IsAtLeastTLSv1_3(ssl->version)) {
+        #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLFSSL_NONBLOCK_OCSP)
+            if (ret != WC_PENDING_E && ret != OCSP_WANT_READ)
+        #endif
+            {
+                ssl->options.cacheMessages = 0;
+                if (ssl->hsHashes->messages != NULL) {
+                    XFREE(ssl->hsHashes->messages, ssl->heap, DYNAMIC_TYPE_HASHES);
+                    ssl->hsHashes->messages = NULL;
+                }
+            }
+        }
+    #endif
+        if (IsEncryptionOn(ssl, 0)) {
+            /* access beyond input + size should be checked against totalSz */
+            if (*inOutIdx + ssl->keys.padSz > totalSz)
+                return BUFFER_E;
+
+            *inOutIdx += ssl->keys.padSz;
+        }
         break;
 
@@ -9663,10 +10935,11 @@
         break;
 
-#if !defined(NO_RSA) || defined(HAVE_ECC)
+#if (!defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519)) && \
+                                                !defined(WOLFSSL_NO_CLIENT_AUTH)
     case certificate_verify:
         WOLFSSL_MSG("processing certificate verify");
         ret = DoCertificateVerify(ssl, input, inOutIdx, size);
         break;
-#endif /* !NO_RSA || HAVE_ECC */
+#endif /* (!NO_RSA || HAVE_ECC || HAVE_ED25519) && !WOLFSSL_NO_CLIENT_AUTH */
 
 #endif /* !NO_WOLFSSL_SERVER */
@@ -9677,5 +10950,4 @@
         break;
     }
-
     if (ret == 0 && expectedIdx != *inOutIdx) {
         WOLFSSL_MSG("Extra data in handshake message");
@@ -9684,8 +10956,11 @@
         ret = DECODE_E;
     }
-
-#ifdef WOLFSSL_ASYNC_CRYPT
+    if (ret == 0 && ssl->buffers.inputBuffer.dynamicFlag) {
+        ShrinkInputBuffer(ssl, NO_FORCED_FREE);
+    }
+
+#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLFSSL_NONBLOCK_OCSP)
     /* if async, offset index so this msg will be processed again */
-    if (ret == WC_PENDING_E && *inOutIdx > 0) {
+    if ((ret == WC_PENDING_E || ret == OCSP_WANT_READ) && *inOutIdx > 0) {
         *inOutIdx -= HANDSHAKE_HEADER_SZ;
     #ifdef WOLFSSL_DTLS
@@ -9695,5 +10970,10 @@
     #endif
     }
-#endif
+
+    /* make sure async error is cleared */
+    if (ret == 0 && (ssl->error == WC_PENDING_E || ssl->error == OCSP_WANT_READ)) {
+        ssl->error = 0;
+    }
+#endif /* WOLFSSL_ASYNC_CRYPT || WOLFSSL_NONBLOCK_OCSP */
 
     WOLFSSL_LEAVE("DoHandShakeMsgType()", ret);
@@ -9716,4 +10996,6 @@
         if (GetHandShakeHeader(ssl,input,inOutIdx,&type, &size, totalSz) != 0)
             return PARSE_ERROR;
+
+        ssl->options.handShakeState = type;
 
         return DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz);
@@ -9800,7 +11082,9 @@
 }
 
+#endif /* !WOLFSSL_NO_TLS12 */
+
 #ifdef WOLFSSL_DTLS
 
-static INLINE int DtlsCheckWindow(WOLFSSL* ssl)
+static WC_INLINE int DtlsCheckWindow(WOLFSSL* ssl)
 {
     word32* window;
@@ -9903,5 +11187,5 @@
 
 #ifdef WOLFSSL_MULTICAST
-static INLINE word32 UpdateHighwaterMark(word32 cur, word32 first,
+static WC_INLINE word32 UpdateHighwaterMark(word32 cur, word32 first,
                                          word32 second, word32 max)
 {
@@ -9920,5 +11204,5 @@
 
 
-static INLINE int DtlsUpdateWindow(WOLFSSL* ssl)
+static WC_INLINE int DtlsUpdateWindow(WOLFSSL* ssl)
 {
     word32* window;
@@ -10042,5 +11326,5 @@
     /* While there is an item in the store list, and it is the expected
      * message, and it is complete, and there hasn't been an error in the
-     * last messge... */
+     * last message... */
     while (item != NULL &&
             ssl->keys.dtls_expected_peer_handshake_number == item->seq &&
@@ -10051,8 +11335,10 @@
         ret = DoHandShakeMsgType(ssl, item->msg,
                                  &idx, item->type, item->sz, item->sz);
+    #ifdef WOLFSSL_ASYNC_CRYPT
         if (ret == WC_PENDING_E) {
             ssl->keys.dtls_expected_peer_handshake_number--;
             break;
         }
+    #endif
         ssl->dtls_rx_msg_list = item->next;
         DtlsMsgDelete(item, ssl->heap);
@@ -10180,7 +11466,8 @@
 #endif
 
+#ifndef WOLFSSL_NO_TLS12
 
 #ifdef HAVE_AEAD
-static INLINE void AeadIncrementExpIV(WOLFSSL* ssl)
+static WC_INLINE void AeadIncrementExpIV(WOLFSSL* ssl)
 {
     int i;
@@ -10246,9 +11533,9 @@
 
 /* When the flag oldPoly is not set this follows RFC7905. When oldPoly is set
- * the implmentation follows an older draft for creating the nonce and MAC.
- * The flag oldPoly gets set automaticlly depending on what cipher suite was
+ * the implementation follows an older draft for creating the nonce and MAC.
+ * The flag oldPoly gets set automatically depending on what cipher suite was
  * negotiated in the handshake. This is able to be done because the IDs for the
  * cipher suites was updated in RFC7905 giving unique values for the older
- * draft in comparision to the more recent RFC.
+ * draft in comparison to the more recent RFC.
  *
  * ssl   WOLFSSL structure to get cipher and TLS state from
@@ -10397,9 +11684,9 @@
 
 /* When the flag oldPoly is not set this follows RFC7905. When oldPoly is set
- * the implmentation follows an older draft for creating the nonce and MAC.
- * The flag oldPoly gets set automaticlly depending on what cipher suite was
+ * the implementation follows an older draft for creating the nonce and MAC.
+ * The flag oldPoly gets set automatically depending on what cipher suite was
  * negotiated in the handshake. This is able to be done because the IDs for the
  * cipher suites was updated in RFC7905 giving unique values for the older
- * draft in comparision to the more recent RFC.
+ * draft in comparison to the more recent RFC.
  *
  * ssl   WOLFSSL structure to get cipher and TLS state from
@@ -10538,5 +11825,5 @@
 
 
-static INLINE int EncryptDo(WOLFSSL* ssl, byte* out, const byte* input,
+static WC_INLINE int EncryptDo(WOLFSSL* ssl, byte* out, const byte* input,
     word16 sz, int asyncOkay)
 {
@@ -10563,5 +11850,5 @@
         case wolfssl_triple_des:
         #ifdef WOLFSSL_ASYNC_CRYPT
-            /* intialize event */
+            /* initialize event */
             asyncDev = &ssl->encrypt.des3->asyncDev;
             ret = wolfSSL_AsyncInit(ssl, asyncDev, event_flags);
@@ -10579,8 +11866,8 @@
     #endif
 
-    #ifdef BUILD_AES
+    #if defined(BUILD_AES) && defined(HAVE_AES_CBC)
         case wolfssl_aes:
         #ifdef WOLFSSL_ASYNC_CRYPT
-            /* intialize event */
+            /* initialize event */
             asyncDev = &ssl->encrypt.aes->asyncDev;
             ret = wolfSSL_AsyncInit(ssl, asyncDev, event_flags);
@@ -10606,5 +11893,5 @@
 
         #ifdef WOLFSSL_ASYNC_CRYPT
-            /* intialize event */
+            /* initialize event */
             asyncDev = &ssl->encrypt.aes->asyncDev;
             ret = wolfSSL_AsyncInit(ssl, asyncDev, event_flags);
@@ -10715,5 +12002,5 @@
 }
 
-static INLINE int Encrypt(WOLFSSL* ssl, byte* out, const byte* input, word16 sz,
+static WC_INLINE int Encrypt(WOLFSSL* ssl, byte* out, const byte* input, word16 sz,
     int asyncOkay)
 {
@@ -10807,5 +12094,5 @@
 }
 
-static INLINE int DecryptDo(WOLFSSL* ssl, byte* plain, const byte* input,
+static WC_INLINE int DecryptDo(WOLFSSL* ssl, byte* plain, const byte* input,
                            word16 sz)
 {
@@ -10827,5 +12114,5 @@
         case wolfssl_triple_des:
         #ifdef WOLFSSL_ASYNC_CRYPT
-            /* intialize event */
+            /* initialize event */
             ret = wolfSSL_AsyncInit(ssl, &ssl->decrypt.des3->asyncDev,
                 WC_ASYNC_FLAG_CALL_AGAIN);
@@ -10843,8 +12130,8 @@
     #endif
 
-    #ifdef BUILD_AES
+    #if defined(BUILD_AES) && defined(HAVE_AES_CBC)
         case wolfssl_aes:
         #ifdef WOLFSSL_ASYNC_CRYPT
-            /* intialize event */
+            /* initialize event */
             ret = wolfSSL_AsyncInit(ssl, &ssl->decrypt.aes->asyncDev,
                 WC_ASYNC_FLAG_CALL_AGAIN);
@@ -10869,5 +12156,5 @@
 
         #ifdef WOLFSSL_ASYNC_CRYPT
-            /* intialize event */
+            /* initialize event */
             ret = wolfSSL_AsyncInit(ssl, &ssl->decrypt.aes->asyncDev,
                 WC_ASYNC_FLAG_CALL_AGAIN);
@@ -10964,5 +12251,5 @@
 }
 
-static INLINE int Decrypt(WOLFSSL* ssl, byte* plain, const byte* input,
+static WC_INLINE int Decrypt(WOLFSSL* ssl, byte* plain, const byte* input,
                            word16 sz)
 {
@@ -11067,4 +12354,6 @@
 }
 
+#endif /* !WOLFSSL_NO_TLS12 */
+
 /* Check conditions for a cipher to have an explicit IV.
  *
@@ -11072,5 +12361,5 @@
  * returns 1 if the cipher in use has an explicit IV and 0 otherwise.
  */
-static INLINE int CipherHasExpIV(WOLFSSL *ssl)
+static WC_INLINE int CipherHasExpIV(WOLFSSL *ssl)
 {
 #ifdef WOLFSSL_TLS13
@@ -11092,4 +12381,5 @@
 #endif
 
+#ifndef WOLFSSL_AEAD_ONLY
     if (ssl->specs.cipher_type == block) {
         if (encryptSz % ssl->specs.block_size) {
@@ -11106,5 +12396,7 @@
             minLength += ssl->specs.block_size;  /* explicit IV */
     }
-    else if (ssl->specs.cipher_type == aead) {
+    else
+#endif
+    if (ssl->specs.cipher_type == aead) {
         minLength = ssl->specs.aead_mac_size;    /* authTag size */
         if (CipherHasExpIV(ssl))
@@ -11121,172 +12413,5 @@
 
 
-#ifndef NO_OLD_TLS
-
-static INLINE void Md5Rounds(int rounds, const byte* data, int sz)
-{
-    wc_Md5 md5;
-    int i;
-
-    wc_InitMd5(&md5);   /* no error check on purpose, dummy round */
-
-    for (i = 0; i < rounds; i++)
-        wc_Md5Update(&md5, data, sz);
-    wc_Md5Free(&md5); /* in case needed to release resources */
-}
-
-
-
-/* do a dummy sha round */
-static INLINE void ShaRounds(int rounds, const byte* data, int sz)
-{
-    wc_Sha sha;
-    int i;
-
-    wc_InitSha(&sha);  /* no error check on purpose, dummy round */
-
-    for (i = 0; i < rounds; i++)
-        wc_ShaUpdate(&sha, data, sz);
-    wc_ShaFree(&sha); /* in case needed to release resources */
-}
-#endif
-
-
-#ifndef NO_SHA256
-
-static INLINE void Sha256Rounds(int rounds, const byte* data, int sz)
-{
-    wc_Sha256 sha256;
-    int i;
-
-    wc_InitSha256(&sha256);  /* no error check on purpose, dummy round */
-
-    for (i = 0; i < rounds; i++) {
-        wc_Sha256Update(&sha256, data, sz);
-        /* no error check on purpose, dummy round */
-    }
-    wc_Sha256Free(&sha256); /* in case needed to release resources */
-}
-
-#endif
-
-
-#ifdef WOLFSSL_SHA384
-
-static INLINE void Sha384Rounds(int rounds, const byte* data, int sz)
-{
-    wc_Sha384 sha384;
-    int i;
-
-    wc_InitSha384(&sha384);  /* no error check on purpose, dummy round */
-
-    for (i = 0; i < rounds; i++) {
-        wc_Sha384Update(&sha384, data, sz);
-        /* no error check on purpose, dummy round */
-    }
-    wc_Sha384Free(&sha384); /* in case needed to release resources */
-}
-
-#endif
-
-
-#ifdef WOLFSSL_SHA512
-
-static INLINE void Sha512Rounds(int rounds, const byte* data, int sz)
-{
-    wc_Sha512 sha512;
-    int i;
-
-    wc_InitSha512(&sha512);  /* no error check on purpose, dummy round */
-
-    for (i = 0; i < rounds; i++) {
-        wc_Sha512Update(&sha512, data, sz);
-        /* no error check on purpose, dummy round */
-    }
-    wc_Sha512Free(&sha512); /* in case needed to release resources */
-}
-
-#endif
-
-
-#ifdef WOLFSSL_RIPEMD
-
-static INLINE void RmdRounds(int rounds, const byte* data, int sz)
-{
-    RipeMd ripemd;
-    int i;
-
-    wc_InitRipeMd(&ripemd);
-
-    for (i = 0; i < rounds; i++)
-        wc_RipeMdUpdate(&ripemd, data, sz);
-}
-
-#endif
-
-
-/* Do dummy rounds */
-static INLINE void DoRounds(int type, int rounds, const byte* data, int sz)
-{
-    (void)rounds;
-    (void)data;
-    (void)sz;
-
-    switch (type) {
-        case no_mac :
-            break;
-
-#ifndef NO_OLD_TLS
-#ifndef NO_MD5
-        case md5_mac :
-            Md5Rounds(rounds, data, sz);
-            break;
-#endif
-
-#ifndef NO_SHA
-        case sha_mac :
-            ShaRounds(rounds, data, sz);
-            break;
-#endif
-#endif
-
-#ifndef NO_SHA256
-        case sha256_mac :
-            Sha256Rounds(rounds, data, sz);
-            break;
-#endif
-
-#ifdef WOLFSSL_SHA384
-        case sha384_mac :
-            Sha384Rounds(rounds, data, sz);
-            break;
-#endif
-
-#ifdef WOLFSSL_SHA512
-        case sha512_mac :
-            Sha512Rounds(rounds, data, sz);
-            break;
-#endif
-
-#ifdef WOLFSSL_RIPEMD
-        case rmd_mac :
-            RmdRounds(rounds, data, sz);
-            break;
-#endif
-
-        default:
-            WOLFSSL_MSG("Bad round type");
-            break;
-    }
-}
-
-
-/* do number of compression rounds on dummy data */
-static INLINE void CompressRounds(WOLFSSL* ssl, int rounds, const byte* dummy)
-{
-    if (rounds)
-        DoRounds(ssl->specs.mac_algorithm, rounds, dummy, COMPRESS_LOWER);
-}
-
-
+#ifndef WOLFSSL_AEAD_ONLY
 /* check all length bytes for the pad value, return 0 on success */
 static int PadCheck(const byte* a, byte pad, int length)
@@ -11297,5 +12422,5 @@
     for (i = 0; i < length; i++) {
         compareSum |= a[i] ^ pad;
-    }
+}
 
     return compareSum;
@@ -11303,71 +12428,122 @@
 
 
-/* get compression extra rounds */
-static INLINE int GetRounds(int pLen, int padLen, int t)
+/* Mask the padding bytes with the expected values.
+ * Constant time implementation - does maximum pad size possible.
+ *
+ * data   Message data.
+ * sz     Size of the message including MAC and padding and padding length.
+ * macSz  Size of the MAC.
+ * returns 0 on success, otherwise failure.
+ */
+static byte MaskPadding(const byte* data, int sz, int macSz)
 {
-    int  roundL1 = 1;  /* round up flags */
-    int  roundL2 = 1;
-
-    int L1 = COMPRESS_CONSTANT + pLen - t;
-    int L2 = COMPRESS_CONSTANT + pLen - padLen - 1 - t;
-
-    L1 -= COMPRESS_UPPER;
-    L2 -= COMPRESS_UPPER;
-
-    if ( (L1 % COMPRESS_LOWER) == 0)
-        roundL1 = 0;
-    if ( (L2 % COMPRESS_LOWER) == 0)
-        roundL2 = 0;
-
-    L1 /= COMPRESS_LOWER;
-    L2 /= COMPRESS_LOWER;
-
-    L1 += roundL1;
-    L2 += roundL2;
-
-    return L1 - L2;
+    int i;
+    int checkSz = sz - 1;
+    byte paddingSz = data[sz - 1];
+    byte mask;
+    byte good = ctMaskGT(paddingSz, sz - 1 - macSz);
+
+    if (checkSz > TLS_MAX_PAD_SZ)
+        checkSz = TLS_MAX_PAD_SZ;
+
+    for (i = 0; i < checkSz; i++) {
+        mask = ctMaskLTE(i, paddingSz);
+        good |= mask & (data[sz - 1 - i] ^ paddingSz);
 }
 
+    return good;
+}
+
+/* Mask the MAC in the message with the MAC calculated.
+ * Constant time implementation - starts looking for MAC where maximum padding
+ * size has it.
+ *
+ * data    Message data.
+ * sz      Size of the message including MAC and padding and padding length.
+ * macSz   Size of the MAC data.
+ * expMac  Expected MAC value.
+ * returns 0 on success, otherwise failure.
+ */
+static byte MaskMac(const byte* data, int sz, int macSz, byte* expMac)
+{
+    int i, j;
+    unsigned char mac[WC_MAX_DIGEST_SIZE];
+    int scanStart = sz - 1 - TLS_MAX_PAD_SZ - macSz;
+    int macEnd = sz - 1 - data[sz - 1];
+    int macStart = macEnd - macSz;
+    int r = 0;
+    unsigned char started, notEnded;
+    unsigned char good = 0;
+
+    scanStart &= (~scanStart) >> (sizeof(int) * 8 - 1);
+    macStart &= (~macStart) >> (sizeof(int) * 8 - 1);
+
+    /* Div on Intel has different speeds depending on value.
+     * Use a bitwise AND or mod a specific value (converted to mul). */
+    if ((macSz & (macSz - 1)) == 0)
+        r = (macSz - (scanStart - macStart)) & (macSz - 1);
+#ifndef NO_SHA
+    else if (macSz == WC_SHA_DIGEST_SIZE)
+        r = (macSz - (scanStart - macStart)) % WC_SHA_DIGEST_SIZE;
+#endif
+#ifdef WOLFSSL_SHA384
+    else if (macSz == WC_SHA384_DIGEST_SIZE)
+        r = (macSz - (scanStart - macStart)) % WC_SHA384_DIGEST_SIZE;
+#endif
+
+    XMEMSET(mac, 0, macSz);
+    for (i = scanStart; i < sz; i += macSz) {
+        for (j = 0; j < macSz && j + i < sz; j++) {
+            started = ctMaskGTE(i + j, macStart);
+            notEnded = ctMaskLT(i + j, macEnd);
+            mac[j] |= started & notEnded & data[i + j];
+    }
+}
+
+    if ((macSz & (macSz - 1)) == 0) {
+        for (i = 0; i < macSz; i++)
+            good |= expMac[i] ^ mac[(i + r) & (macSz - 1)];
+    }
+#ifndef NO_SHA
+    else if (macSz == WC_SHA_DIGEST_SIZE) {
+        for (i = 0; i < macSz; i++)
+            good |= expMac[i] ^ mac[(i + r) % WC_SHA_DIGEST_SIZE];
+    }
+#endif
+#ifdef WOLFSSL_SHA384
+    else if (macSz == WC_SHA384_DIGEST_SIZE) {
+        for (i = 0; i < macSz; i++)
+            good |= expMac[i] ^ mac[(i + r) % WC_SHA384_DIGEST_SIZE];
+    }
+#endif
+
+    return good;
+}
 
 /* timing resistant pad/verify check, return 0 on success */
-static int TimingPadVerify(WOLFSSL* ssl, const byte* input, int padLen, int t,
-                           int pLen, int content)
+int TimingPadVerify(WOLFSSL* ssl, const byte* input, int padLen, int macSz,
+                    int pLen, int content)
 {
-    byte verify[MAX_DIGEST_SIZE];
-    byte dmy[sizeof(WOLFSSL) >= MAX_PAD_SIZE ? 1 : MAX_PAD_SIZE] = {0};
-    byte* dummy = sizeof(dmy) < MAX_PAD_SIZE ? (byte*) ssl : dmy;
+    byte verify[WC_MAX_DIGEST_SIZE];
+    byte good;
     int  ret = 0;
 
-    (void)dmy;
-
-    if ( (t + padLen + 1) > pLen) {
-        WOLFSSL_MSG("Plain Len not long enough for pad/mac");
-        PadCheck(dummy, (byte)padLen, MAX_PAD_SIZE);
-        ssl->hmac(ssl, verify, input, pLen - t, content, 1); /* still compare */
-        ConstantCompare(verify, input + pLen - t, t);
-
-        return VERIFY_MAC_ERROR;
-    }
-
-    if (PadCheck(input + pLen - (padLen + 1), (byte)padLen, padLen + 1) != 0) {
-        WOLFSSL_MSG("PadCheck failed");
-        PadCheck(dummy, (byte)padLen, MAX_PAD_SIZE - padLen - 1);
-        ssl->hmac(ssl, verify, input, pLen - t, content, 1); /* still compare */
-        ConstantCompare(verify, input + pLen - t, t);
-
-        return VERIFY_MAC_ERROR;
-    }
-
-    PadCheck(dummy, (byte)padLen, MAX_PAD_SIZE - padLen - 1);
-    ret = ssl->hmac(ssl, verify, input, pLen - padLen - 1 - t, content, 1);
-
-    CompressRounds(ssl, GetRounds(pLen, padLen, t), dummy);
-
-    if (ConstantCompare(verify, input + (pLen - padLen - 1 - t), t) != 0) {
-        WOLFSSL_MSG("Verify MAC compare failed");
-        return VERIFY_MAC_ERROR;
-    }
-
-    /* treat any faulure as verify MAC error */
+    good = MaskPadding(input, pLen, macSz);
+    /* 4th argument has potential to underflow, ssl->hmac function should
+     * either increment the size by (macSz + padLen + 1) before use or check on
+     * the size to make sure is valid. */
+    ret = ssl->hmac(ssl, verify, input, pLen - macSz - padLen - 1, padLen,
+                                                                    content, 1);
+    good |= MaskMac(input, pLen, ssl->specs.hash_size, verify);
+
+    /* Non-zero on failure. */
+    good = (byte)~(word32)good;
+    good &= good >> 4;
+    good &= good >> 2;
+    good &= good >> 1;
+    /* Make ret negative on masking failure. */
+    ret -= 1 - good;
+
+    /* Treat any faulure as verify MAC error. */
     if (ret != 0)
         ret = VERIFY_MAC_ERROR;
@@ -11375,4 +12551,5 @@
     return ret;
 }
+#endif
 
 
@@ -11389,5 +12566,5 @@
 
 #ifdef WOLFSSL_EARLY_DATA
-    if (ssl->earlyData) {
+    if (ssl->earlyData != no_early_data) {
     }
     else
@@ -11399,9 +12576,12 @@
     }
 
+#ifndef WOLFSSL_AEAD_ONLY
     if (ssl->specs.cipher_type == block) {
         if (ssl->options.tls1_1)
             ivExtra = ssl->specs.block_size;
     }
-    else if (ssl->specs.cipher_type == aead) {
+    else
+#endif
+    if (ssl->specs.cipher_type == aead) {
         if (CipherHasExpIV(ssl))
             ivExtra = AESGCM_EXP_IV_SZ;
@@ -11414,5 +12594,5 @@
     }
 #ifdef WOLFSSL_EARLY_DATA
-    if (ssl->earlyData) {
+    if (ssl->earlyData != no_early_data) {
         if (ssl->earlyDataSz + dataSz > ssl->options.maxEarlyDataSz) {
             SendAlert(ssl, alert_fatal, unexpected_message);
@@ -11459,12 +12639,12 @@
     byte code;
 
-    #ifdef WOLFSSL_CALLBACKS
+    #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
         if (ssl->hsInfoOn)
-            AddPacketName("Alert", &ssl->handShakeInfo);
+            AddPacketName(ssl, "Alert");
         if (ssl->toInfoOn)
             /* add record header back on to info + alert bytes level/code */
-            AddPacketInfo("Alert", &ssl->timeoutInfo, input + *inOutIdx -
+            AddPacketInfo(ssl, "Alert", alert, input + *inOutIdx -
                           RECORD_HEADER_SZ, RECORD_HEADER_SZ + ALERT_SIZE,
-                          ssl->heap);
+                          READ_PROTO, ssl->heap);
     #endif
 
@@ -11554,5 +12734,5 @@
     /* read data from network */
     do {
-        in = Receive(ssl,
+        in = wolfSSLReceive(ssl,
                      ssl->buffers.inputBuffer.buffer +
                      ssl->buffers.inputBuffer.length,
@@ -11584,7 +12764,8 @@
 
 
-static INLINE int VerifyMac(WOLFSSL* ssl, const byte* input, word32 msgSz,
+static WC_INLINE int VerifyMac(WOLFSSL* ssl, const byte* input, word32 msgSz,
                             int content, word32* padSz)
 {
+#if !defined(WOLFSSL_NO_TLS12) && !defined(WOLFSSL_AEAD_ONLY)
     int    ivExtra = 0;
     int    ret;
@@ -11597,5 +12778,6 @@
     word32 digestSz = ssl->specs.hash_size;
 #endif
-    byte   verify[MAX_DIGEST_SIZE];
+    byte   verify[WC_MAX_DIGEST_SIZE];
+
 
     if (ssl->specs.cipher_type == block) {
@@ -11625,5 +12807,5 @@
             }
             PadCheck(dummy, (byte)pad, MAX_PAD_SIZE);  /* timing only */
-            ret = ssl->hmac(ssl, verify, input, msgSz - digestSz - pad - 1,
+            ret = ssl->hmac(ssl, verify, input, msgSz - digestSz - pad - 1, pad,
                             content, 1);
             if (ConstantCompare(verify, input + msgSz - digestSz - pad - 1,
@@ -11635,5 +12817,5 @@
     }
     else if (ssl->specs.cipher_type == stream) {
-        ret = ssl->hmac(ssl, verify, input, msgSz - digestSz, content, 1);
+        ret = ssl->hmac(ssl, verify, input, msgSz - digestSz, -1, content, 1);
         if (ConstantCompare(verify, input + msgSz - digestSz, digestSz) != 0){
             return VERIFY_MAC_ERROR;
@@ -11642,11 +12824,18 @@
             return VERIFY_MAC_ERROR;
     }
+#endif /* !WOLFSSL_NO_TLS12 && !WOLFSSL_AEAD_ONLY */
 
     if (ssl->specs.cipher_type == aead) {
         *padSz = ssl->specs.aead_mac_size;
     }
+#if !defined(WOLFSSL_NO_TLS12) && !defined(WOLFSSL_AEAD_ONLY)
     else {
         *padSz = digestSz + pad + padByte;
     }
+#endif /* !WOLFSSL_NO_TLS12 && !WOLFSSL_AEAD_ONLY */
+
+    (void)input;
+    (void)msgSz;
+    (void)content;
 
     return 0;
@@ -11670,6 +12859,12 @@
 #endif
 
-    if (ssl->error != 0 && ssl->error != WANT_READ &&
-        ssl->error != WANT_WRITE && ssl->error != WC_PENDING_E) {
+    if (ssl->error != 0 && ssl->error != WANT_READ && ssl->error != WANT_WRITE
+    #ifdef WOLFSSL_ASYNC_CRYPT
+        && ssl->error != WC_PENDING_E
+    #endif
+    #ifdef WOLFSSL_NONBLOCK_OCSP
+        && ssl->error != OCSP_WANT_READ
+    #endif
+    ) {
         WOLFSSL_MSG("ProcessReply retry in error state, not allowed");
         return ssl->error;
@@ -11836,5 +13031,12 @@
         case decryptMessage:
 
-            if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 0) {
+#if !defined(WOLFSSL_TLS13) || defined(WOLFSSL_TLS13_DRAFT_18)
+            if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 0)
+#else
+            if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 0 &&
+                                        (!IsAtLeastTLSv1_3(ssl->version) ||
+                                         ssl->curRL.type != change_cipher_spec))
+#endif
+            {
                 bufferStatic* in = &ssl->buffers.inputBuffer;
 
@@ -11854,15 +13056,30 @@
                 else {
                     if (!ssl->options.tls1_3) {
+                #ifndef WOLFSSL_NO_TLS12
                         ret = Decrypt(ssl,
                                       in->buffer + in->idx,
                                       in->buffer + in->idx,
                                       ssl->curSize);
+                #else
+                        ret = DECRYPT_ERROR;
+                #endif
                     }
-                    else {
+                    else
+                    {
                     #ifdef WOLFSSL_TLS13
+                    #if defined(WOLFSSL_TLS13_DRAFT_18) || \
+                        defined(WOLFSSL_TLS13_DRAFT_22) || \
+                        defined(WOLFSSL_TLS13_DRAFT_23)
                         ret = DecryptTls13(ssl,
                                            in->buffer + in->idx,
                                            in->buffer + in->idx,
-                                           ssl->curSize);
+                                           ssl->curSize, NULL, 0);
+                    #else
+                        ret = DecryptTls13(ssl,
+                                        in->buffer + in->idx,
+                                        in->buffer + in->idx,
+                                        ssl->curSize,
+                                        (byte*)&ssl->curRL, RECORD_HEADER_SZ);
+                    #endif
                     #else
                         ret = DECRYPT_ERROR;
@@ -11877,10 +13094,14 @@
 
                 if (ret >= 0) {
+            #ifndef WOLFSSL_NO_TLS12
                     /* handle success */
+                #ifndef WOLFSSL_AEAD_ONLY
                     if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
                         ssl->buffers.inputBuffer.idx += ssl->specs.block_size;
+                #endif
                         /* go past TLSv1.1 IV */
                     if (CipherHasExpIV(ssl))
                         ssl->buffers.inputBuffer.idx += AESGCM_EXP_IV_SZ;
+            #endif
                 }
                 else {
@@ -11923,5 +13144,12 @@
         case verifyMessage:
 
-            if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 0) {
+#if !defined(WOLFSSL_TLS13) || defined(WOLFSSL_TLS13_DRAFT_18)
+            if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 0)
+#else
+            if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 0 &&
+                                        (!IsAtLeastTLSv1_3(ssl->version) ||
+                                         ssl->curRL.type != change_cipher_spec))
+#endif
+            {
                 if (!atomicUser) {
                     ret = VerifyMac(ssl, ssl->buffers.inputBuffer.buffer +
@@ -11956,8 +13184,14 @@
 #ifdef WOLFSSL_TLS13
                 if (ssl->options.tls1_3) {
+                    word16 i = (word16)(ssl->buffers.inputBuffer.length -
+                                        ssl->keys.padSz);
+                    /* Remove padding from end of plain text. */
+                    for (--i; i > ssl->buffers.inputBuffer.idx; i--) {
+                        if (ssl->buffers.inputBuffer.buffer[i] != 0)
+                            break;
+                    }
                     /* Get the real content type from the end of the data. */
-                    ssl->keys.padSz++;
-                    ssl->curRL.type = ssl->buffers.inputBuffer.buffer[
-                        ssl->buffers.inputBuffer.length - ssl->keys.padSz];
+                    ssl->curRL.type = ssl->buffers.inputBuffer.buffer[i];
+                    ssl->keys.padSz = ssl->buffers.inputBuffer.length - i;
                 }
 #endif
@@ -11990,8 +13224,12 @@
                     }
                     else if (!IsAtLeastTLSv1_3(ssl->version)) {
+#ifndef WOLFSSL_NO_TLS12
                         ret = DoHandShakeMsg(ssl,
                                             ssl->buffers.inputBuffer.buffer,
                                             &ssl->buffers.inputBuffer.idx,
                                             ssl->buffers.inputBuffer.length);
+#else
+                        ret = BUFFER_ERROR;
+#endif
                     }
                     else {
@@ -12007,5 +13245,5 @@
                                 ssl->earlyData &&
                                 ssl->options.handShakeState == HANDSHAKE_DONE) {
-                            ssl->earlyData = 0;
+                            ssl->earlyData = no_early_data;
                             ssl->options.processReply = doProcessInit;
                             return ZERO_RETURN;
@@ -12022,17 +13260,41 @@
                 case change_cipher_spec:
                     WOLFSSL_MSG("got CHANGE CIPHER SPEC");
-                    #ifdef WOLFSSL_CALLBACKS
+                    #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
                         if (ssl->hsInfoOn)
-                            AddPacketName("ChangeCipher", &ssl->handShakeInfo);
+                            AddPacketName(ssl, "ChangeCipher");
                         /* add record header back on info */
                         if (ssl->toInfoOn) {
-                            AddPacketInfo("ChangeCipher", &ssl->timeoutInfo,
+                            AddPacketInfo(ssl, "ChangeCipher",
+                                change_cipher_spec,
                                 ssl->buffers.inputBuffer.buffer +
                                 ssl->buffers.inputBuffer.idx - RECORD_HEADER_SZ,
-                                1 + RECORD_HEADER_SZ, ssl->heap);
+                                1 + RECORD_HEADER_SZ, READ_PROTO, ssl->heap);
+                            #ifdef WOLFSSL_CALLBACKS
                             AddLateRecordHeader(&ssl->curRL, &ssl->timeoutInfo);
+                            #endif
                         }
                     #endif
 
+#ifdef WOLFSSL_TLS13
+    #ifdef WOLFSSL_TLS13_DRAFT_18
+                    if (IsAtLeastTLSv1_3(ssl->version)) {
+                        SendAlert(ssl, alert_fatal, illegal_parameter);
+                        return UNKNOWN_RECORD_TYPE;
+                    }
+    #else
+                    if (IsAtLeastTLSv1_3(ssl->version)) {
+                        word32 i = ssl->buffers.inputBuffer.idx;
+                        if (ssl->curSize != 1 ||
+                                      ssl->buffers.inputBuffer.buffer[i] != 1) {
+                            SendAlert(ssl, alert_fatal, illegal_parameter);
+                            return UNKNOWN_RECORD_TYPE;
+                        }
+                        ssl->buffers.inputBuffer.idx++;
+                        break;
+                        }
+                    #endif
+#endif
+
+#ifndef WOLFSSL_NO_TLS12
                     ret = SanityCheckMsgReceived(ssl, change_cipher_hs);
                     if (ret != 0) {
@@ -12119,4 +13381,5 @@
                     if (ret != 0)
                         return ret;
+#endif /* !WOLFSSL_NO_TLS12 */
                     break;
 
@@ -12214,4 +13477,19 @@
     int                ret;
 
+    #ifdef OPENSSL_EXTRA
+	ssl->cbmode = SSL_CB_MODE_WRITE;
+	if (ssl->options.side == WOLFSSL_SERVER_END){
+		ssl->options.serverState = SERVER_CHANGECIPHERSPEC_COMPLETE;
+		if (ssl->CBIS != NULL)
+			ssl->CBIS(ssl, SSL_CB_ACCEPT_LOOP, SSL_SUCCESS);
+	}
+	else{
+		ssl->options.clientState =
+			CLIENT_CHANGECIPHERSPEC_COMPLETE;
+		if (ssl->CBIS != NULL)
+			ssl->CBIS(ssl, SSL_CB_CONNECT_LOOP, SSL_SUCCESS);
+	}
+    #endif
+
     #ifdef WOLFSSL_DTLS
         if (ssl->options.dtls) {
@@ -12226,5 +13504,5 @@
     }
 
-    /* check for avalaible size */
+    /* check for available size */
     if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
         return ret;
@@ -12256,9 +13534,9 @@
         }
     #endif
-    #ifdef WOLFSSL_CALLBACKS
-        if (ssl->hsInfoOn) AddPacketName("ChangeCipher", &ssl->handShakeInfo);
+    #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
+        if (ssl->hsInfoOn) AddPacketName(ssl, "ChangeCipher");
         if (ssl->toInfoOn)
-            AddPacketInfo("ChangeCipher", &ssl->timeoutInfo, output, sendSz,
-                           ssl->heap);
+            AddPacketInfo(ssl, "ChangeCipher", change_cipher_spec, output,
+                    sendSz, WRITE_PROTO, ssl->heap);
     #endif
     ssl->buffers.outputBuffer.length += sendSz;
@@ -12278,9 +13556,9 @@
 
 
-#ifndef NO_OLD_TLS
+#if !defined(NO_OLD_TLS) && !defined(WOLFSSL_AEAD_ONLY)
 static int SSL_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz,
-                 int content, int verify)
+                    int padLen, int content, int verify)
 {
-    byte   result[MAX_DIGEST_SIZE];
+    byte   result[WC_MAX_DIGEST_SIZE];
     word32 digestSz = ssl->specs.hash_size;            /* actual sizes */
     word32 padSz    = ssl->specs.pad_size;
@@ -12294,4 +13572,6 @@
     byte conLen[ENUM_LEN + LENGTH_SZ];     /* content & length */
     const byte* macSecret = wolfSSL_GetMacSecret(ssl, verify);
+
+    (void)padLen;
 
 #ifdef HAVE_FUZZER
@@ -12391,5 +13671,5 @@
     return 0;
 }
-#endif /* NO_OLD_TLS */
+#endif /* !NO_OLD_TLS && !WOLFSSL_AEAD_ONLY */
 
 
@@ -12538,6 +13818,7 @@
 }
 
-#endif /* WOLFSSL_LEANPSK */
-
+#endif /* !NO_CERTS */
+
+#ifndef WOLFSSL_NO_TLS12
 /* Persistable BuildMessage arguments */
 typedef struct BuildMsgArgs {
@@ -12549,5 +13830,5 @@
     word16 size;
     word32 ivSz;      /* TLSv1.1  IV */
-    byte   iv[AES_BLOCK_SIZE]; /* max size */
+    byte*  iv;
 } BuildMsgArgs;
 
@@ -12559,6 +13840,10 @@
     (void)args;
 
-    /* no allocations in BuildMessage */
+    if (args->iv) {
+        XFREE(args->iv, ssl->heap, DYNAMIC_TYPE_SALT);
+        args->iv = NULL;
 }
+}
+#endif
 
 /* Build SSL Message, encrypted */
@@ -12566,4 +13851,5 @@
              int inSz, int type, int hashOutput, int sizeOnly, int asyncOkay)
 {
+#ifndef WOLFSSL_NO_TLS12
     int ret = 0;
     BuildMsgArgs* args;
@@ -12574,4 +13860,5 @@
     (void)sizeof(args_test);
 #endif
+#endif
 
     WOLFSSL_ENTER("BuildMessage");
@@ -12581,4 +13868,8 @@
     }
 
+#ifdef WOLFSSL_NO_TLS12
+    return BuildTls13Message(ssl, output, outSz, input, inSz, type,
+                                               hashOutput, sizeOnly, asyncOkay);
+#else
 #ifdef WOLFSSL_TLS13
     if (ssl->options.tls1_3) {
@@ -12623,9 +13914,9 @@
             /* catch mistaken sizeOnly parameter */
             if (!sizeOnly && (output == NULL || input == NULL) ) {
-                return BAD_FUNC_ARG;
+                ERROR_OUT(BAD_FUNC_ARG, exit_buildmsg);
             }
             if (sizeOnly && (output || input) ) {
                 WOLFSSL_MSG("BuildMessage w/sizeOnly doesn't need input/output");
-                return BAD_FUNC_ARG;
+                ERROR_OUT(BAD_FUNC_ARG, exit_buildmsg);
             }
 
@@ -12650,4 +13941,5 @@
         #endif
 
+        #ifndef WOLFSSL_AEAD_ONLY
             if (ssl->specs.cipher_type == block) {
                 word32 blockSz = ssl->specs.block_size;
@@ -12656,12 +13948,16 @@
                     args->sz  += args->ivSz;
 
-                    if (args->ivSz > (word32)sizeof(args->iv))
+                    if (args->ivSz > MAX_IV_SZ)
                         ERROR_OUT(BUFFER_E, exit_buildmsg);
                 }
                 args->sz += 1;       /* pad byte */
                 args->pad = (args->sz - args->headerSz) % blockSz;
+                #ifdef OPENSSL_EXTRA
+                if(args->pad != 0)
+                #endif
                 args->pad = blockSz - args->pad;
                 args->sz += args->pad;
             }
+        #endif /* WOLFSSL_AEAD_ONLY */
 
         #ifdef HAVE_AEAD
@@ -12684,4 +13980,8 @@
 
             if (args->ivSz > 0) {
+                args->iv = (byte*)XMALLOC(args->ivSz, ssl->heap, DYNAMIC_TYPE_SALT);
+                if (args->iv == NULL)
+                    ERROR_OUT(MEMORY_E, exit_buildmsg);
+
                 ret = wc_RNG_GenerateBlock(ssl->rng, args->iv, args->ivSz);
                 if (ret != 0)
@@ -12701,7 +14001,7 @@
 
             /* write to output */
-            if (args->ivSz) {
+            if (args->ivSz > 0) {
                 XMEMCPY(output + args->idx, args->iv,
-                                        min(args->ivSz, sizeof(args->iv)));
+                                        min(args->ivSz, MAX_IV_SZ));
                 args->idx += args->ivSz;
             }
@@ -12714,6 +14014,4 @@
         case BUILD_MSG_HASH:
         {
-            word32 i;
-
             if (type == handshake && hashOutput) {
                 ret = HashOutput(ssl, output, args->headerSz + inSz, args->ivSz);
@@ -12721,10 +14019,13 @@
                     goto exit_buildmsg;
             }
+        #ifndef WOLFSSL_AEAD_ONLY
             if (ssl->specs.cipher_type == block) {
                 word32 tmpIdx = args->idx + args->digestSz;
+                word32 i;
 
                 for (i = 0; i <= args->pad; i++)
                     output[tmpIdx++] = (byte)args->pad; /* pad byte gets pad value */
             }
+        #endif
 
             ssl->options.buildMsgState = BUILD_MSG_VERIFY_MAC;
@@ -12744,15 +14045,17 @@
         #endif
 
+        #ifndef WOLFSSL_AEAD_ONLY
             if (ssl->specs.cipher_type != aead) {
         #ifdef HAVE_TRUNCATED_HMAC
-            if (ssl->truncated_hmac && ssl->specs.hash_size > args->digestSz) {
+                if (ssl->truncated_hmac &&
+                                        ssl->specs.hash_size > args->digestSz) {
             #ifdef WOLFSSL_SMALL_STACK
                 byte* hmac = NULL;
             #else
-                byte  hmac[MAX_DIGEST_SIZE];
+                    byte  hmac[WC_MAX_DIGEST_SIZE];
             #endif
 
             #ifdef WOLFSSL_SMALL_STACK
-                hmac = (byte*)XMALLOC(MAX_DIGEST_SIZE, ssl->heap,
+                    hmac = (byte*)XMALLOC(WC_MAX_DIGEST_SIZE, ssl->heap,
                                                        DYNAMIC_TYPE_DIGEST);
                 if (hmac == NULL)
@@ -12760,6 +14063,7 @@
             #endif
 
-                ret = ssl->hmac(ssl, hmac, output + args->headerSz + args->ivSz, inSz,
-                                                                       type, 0);
+                    ret = ssl->hmac(ssl, hmac,
+                                     output + args->headerSz + args->ivSz, inSz,
+                                     -1, type, 0);
                 XMEMCPY(output + args->idx, hmac, args->digestSz);
 
@@ -12770,11 +14074,10 @@
             else
         #endif
-                ret = ssl->hmac(ssl, output + args->idx, output + args->headerSz + args->ivSz,
-                                                                inSz, type, 0);
-            #ifdef WOLFSSL_DTLS
-                if (ssl->options.dtls)
-                    DtlsSEQIncrement(ssl, CUR_ORDER);
-            #endif
-            }
+                {
+                    ret = ssl->hmac(ssl, output + args->idx, output +
+                                args->headerSz + args->ivSz, inSz, -1, type, 0);
+            }
+            }
+        #endif /* WOLFSSL_AEAD_ONLY */
             if (ret != 0)
                 goto exit_buildmsg;
@@ -12804,4 +14107,9 @@
     ssl->options.buildMsgState = BUILD_MSG_BEGIN;
 
+    #ifdef WOLFSSL_DTLS
+        if (ret == 0 && ssl->options.dtls)
+            DtlsSEQIncrement(ssl, CUR_ORDER);
+    #endif
+
     /* return sz on success */
     if (ret == 0)
@@ -12810,8 +14118,13 @@
     /* Final cleanup */
     FreeBuildMsgArgs(ssl, args);
+#ifdef WOLFSSL_ASYNC_CRYPT
+    ssl->async.freeArgs = NULL;
+#endif
 
     return ret;
+#endif /* !WOLFSSL_NO_TLS12 */
 }
 
+#ifndef WOLFSSL_NO_TLS12
 
 int SendFinished(WOLFSSL* ssl)
@@ -12827,4 +14140,7 @@
     int              outputSz;
 
+    WOLFSSL_START(WC_FUNC_FINISHED_SEND);
+    WOLFSSL_ENTER("SendFinished");
+
     /* setup encrypt keys */
     if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0)
@@ -12889,4 +14205,10 @@
 #endif
         if (ssl->options.side == WOLFSSL_SERVER_END) {
+        #ifdef OPENSSL_EXTRA
+            ssl->options.serverState = SERVER_FINISHED_COMPLETE;
+            ssl->cbmode = SSL_CB_MODE_WRITE;
+            if (ssl->CBIS != NULL)
+                ssl->CBIS(ssl, SSL_CB_HANDSHAKE_DONE, SSL_SUCCESS);
+        #endif
             ssl->options.handShakeState = HANDSHAKE_DONE;
             ssl->options.handShakeDone  = 1;
@@ -12895,4 +14217,10 @@
     else {
         if (ssl->options.side == WOLFSSL_CLIENT_END) {
+        #ifdef OPENSSL_EXTRA
+            ssl->options.clientState = CLIENT_FINISHED_COMPLETE;
+            ssl->cbmode = SSL_CB_MODE_WRITE;
+            if (ssl->CBIS != NULL)
+                ssl->CBIS(ssl, SSL_CB_HANDSHAKE_DONE, SSL_SUCCESS);
+        #endif
             ssl->options.handShakeState = HANDSHAKE_DONE;
             ssl->options.handShakeDone  = 1;
@@ -12900,18 +14228,137 @@
     }
 
-    #ifdef WOLFSSL_CALLBACKS
-        if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo);
+    #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
+        if (ssl->hsInfoOn) AddPacketName(ssl, "Finished");
         if (ssl->toInfoOn)
-            AddPacketInfo("Finished", &ssl->timeoutInfo, output, sendSz,
-                          ssl->heap);
+            AddPacketInfo(ssl, "Finished", handshake, output, sendSz,
+                          WRITE_PROTO, ssl->heap);
     #endif
 
     ssl->buffers.outputBuffer.length += sendSz;
 
-    return SendBuffered(ssl);
+    ret = SendBuffered(ssl);
+
+    WOLFSSL_LEAVE("SendFinished", ret);
+    WOLFSSL_END(WC_FUNC_FINISHED_SEND);
+
+    return ret;
 }
-
+#endif /* WOLFSSL_NO_TLS12 */
+
+#ifndef NO_WOLFSSL_SERVER
+#if (!defined(WOLFSSL_NO_TLS12) && \
+        (defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \
+         defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2))) || \
+    (defined(WOLFSSL_TLS13) && defined(HAVE_CERTIFICATE_STATUS_REQUEST))
+static int CreateOcspRequest(WOLFSSL* ssl, OcspRequest* request,
+                             DecodedCert* cert, byte* certData, word32 length)
+{
+    int ret;
+
+    InitDecodedCert(cert, certData, length, ssl->heap);
+    /* TODO: Setup async support here */
+    ret = ParseCertRelative(cert, CERT_TYPE, VERIFY, ssl->ctx->cm);
+    if (ret != 0) {
+        WOLFSSL_MSG("ParseCert failed");
+    }
+    if (ret == 0)
+        ret = InitOcspRequest(request, cert, 0, ssl->heap);
+    if (ret == 0) {
+        /* make sure ctx OCSP request is updated */
+        if (!ssl->buffers.weOwnCert) {
+            wolfSSL_Mutex* ocspLock = &ssl->ctx->cm->ocsp_stapling->ocspLock;
+            if (wc_LockMutex(ocspLock) == 0) {
+                if (ssl->ctx->certOcspRequest == NULL)
+                    ssl->ctx->certOcspRequest = request;
+                wc_UnLockMutex(ocspLock);
+            }
+        }
+    }
+
+    FreeDecodedCert(cert);
+
+    return ret;
+}
+
+
+int CreateOcspResponse(WOLFSSL* ssl, OcspRequest** ocspRequest,
+                       buffer* response)
+{
+    int          ret = 0;
+    OcspRequest* request;
+
+    if (ssl == NULL || ocspRequest == NULL || response == NULL)
+        return BAD_FUNC_ARG;
+
+    request = *ocspRequest;
+
+    XMEMSET(response, 0, sizeof(*response));
+
+    /* unable to fetch status. skip. */
+    if (ssl->ctx->cm == NULL || ssl->ctx->cm->ocspStaplingEnabled == 0)
+        return 0;
+
+    if (request == NULL || ssl->buffers.weOwnCert) {
+        DerBuffer* der = ssl->buffers.certificate;
+        #ifdef WOLFSSL_SMALL_STACK
+            DecodedCert* cert = NULL;
+        #else
+            DecodedCert  cert[1];
+        #endif
+
+        /* unable to fetch status. skip. */
+        if (der->buffer == NULL || der->length == 0)
+            return 0;
+
+    #ifdef WOLFSSL_SMALL_STACK
+        cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), ssl->heap,
+                                        DYNAMIC_TYPE_DCERT);
+        if (cert == NULL)
+            return MEMORY_E;
+    #endif
+        request = (OcspRequest*)XMALLOC(sizeof(OcspRequest), ssl->heap,
+                                                     DYNAMIC_TYPE_OCSP_REQUEST);
+        if (request == NULL)
+            ret = MEMORY_E;
+
+        if (ret == 0) {
+            ret = CreateOcspRequest(ssl, request, cert, der->buffer,
+                                                                   der->length);
+        }
+
+        if (request != NULL && ret != 0) {
+            FreeOcspRequest(request);
+            XFREE(request, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
+            request = NULL;
+        }
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(cert, ssl->heap, DYNAMIC_TYPE_DCERT);
+    #endif
+    }
+
+    if (ret == 0) {
+        request->ssl = ssl;
+        ret = CheckOcspRequest(ssl->ctx->cm->ocsp_stapling, request, response);
+
+        /* Suppressing, not critical */
+        if (ret == OCSP_CERT_REVOKED ||
+            ret == OCSP_CERT_UNKNOWN ||
+            ret == OCSP_LOOKUP_FAIL) {
+            ret = 0;
+        }
+}
+
+    *ocspRequest = request;
+
+    return ret;
+}
+#endif
+#endif /* !NO_WOLFSSL_SERVER */
+
+#ifndef WOLFSSL_NO_TLS12
 
 #ifndef NO_CERTS
+#if !defined(NO_WOLFSSL_SERVER) || !defined(WOLFSSL_NO_CLIENT_AUTH)
+/* handle generation of certificate (11) */
 int SendCertificate(WOLFSSL* ssl)
 {
@@ -12920,8 +14367,18 @@
     word32 length, maxFragment;
 
+    WOLFSSL_START(WC_FUNC_CERTIFICATE_SEND);
+    WOLFSSL_ENTER("SendCertificate");
+
     if (ssl->options.usingPSK_cipher || ssl->options.usingAnon_cipher)
         return 0;  /* not needed */
 
     if (ssl->options.sendVerify == SEND_BLANK_CERT) {
+    #ifdef OPENSSL_EXTRA
+        if (ssl->version.major == SSLv3_MAJOR
+            && ssl->version.minor == SSLv3_MINOR){
+            SendAlert(ssl, alert_warning, no_certificate);
+            return 0;
+        } else {
+    #endif
         certSz = 0;
         certChainSz = 0;
@@ -12929,4 +14386,7 @@
         length = CERT_HEADER_SZ;
         listSz = 0;
+    #ifdef OPENSSL_EXTRA
+        }
+    #endif
     }
     else {
@@ -12957,6 +14417,10 @@
 
     maxFragment = MAX_RECORD_SIZE;
+
     if (ssl->options.dtls) {
     #ifdef WOLFSSL_DTLS
+        /* The 100 bytes is used to account for the UDP and IP headers.
+           It can also include the record padding and MAC if the
+           SendCertificate is called for a secure renegotiation. */
         maxFragment = MAX_MTU - DTLS_RECORD_HEADER_SZ
                       - DTLS_HANDSHAKE_HEADER_SZ - 100;
@@ -12964,8 +14428,5 @@
     }
 
-    #ifdef HAVE_MAX_FRAGMENT
-    if (ssl->max_fragment != 0 && maxFragment >= ssl->max_fragment)
-        maxFragment = ssl->max_fragment;
-    #endif /* HAVE_MAX_FRAGMENT */
+    maxFragment = wolfSSL_GetMaxRecordSize(ssl, maxFragment);
 
     while (length > 0 && ret == 0) {
@@ -13132,10 +14593,10 @@
     #endif
 
-    #ifdef WOLFSSL_CALLBACKS
+    #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
         if (ssl->hsInfoOn)
-            AddPacketName("Certificate", &ssl->handShakeInfo);
+            AddPacketName(ssl, "Certificate");
         if (ssl->toInfoOn)
-            AddPacketInfo("Certificate", &ssl->timeoutInfo, output, sendSz,
-                           ssl->heap);
+            AddPacketInfo(ssl, "Certificate", handshake, output, sendSz,
+                           WRITE_PROTO, ssl->heap);
     #endif
 
@@ -13152,12 +14613,17 @@
                 ssl->keys.dtls_handshake_number++;
         #endif
-        if (ssl->options.side == WOLFSSL_SERVER_END)
+        if (ssl->options.side == WOLFSSL_SERVER_END){
             ssl->options.serverState = SERVER_CERT_COMPLETE;
     }
+    }
+
+    WOLFSSL_LEAVE("SendCertificate", ret);
+    WOLFSSL_END(WC_FUNC_CERTIFICATE_SEND);
 
     return ret;
 }
-
-
+#endif /* !NO_WOLFSSL_SERVER || !WOLFSSL_NO_CLIENT_AUTH */
+
+/* handle generation of certificate_request (13) */
 int SendCertificateRequest(WOLFSSL* ssl)
 {
@@ -13167,5 +14633,5 @@
     word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
     word32 dnLen = 0;
-#ifdef WOLFSSL_NGINX
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX)
     WOLF_STACK_OF(WOLFSSL_X509_NAME)* names;
 #endif
@@ -13174,8 +14640,11 @@
     int  reqSz = ENUM_LEN + typeTotal + REQ_HEADER_SZ;  /* add auth later */
 
+    WOLFSSL_START(WC_FUNC_CERTIFICATE_REQUEST_SEND);
+    WOLFSSL_ENTER("SendCertificateRequest");
+
     if (IsAtLeastTLSv1_2(ssl))
         reqSz += LENGTH_SZ + ssl->suites->hashSigAlgoSz;
 
-#ifdef WOLFSSL_NGINX
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX)
     /* Certificate Authorities */
     names = ssl->ctx->ca_names;
@@ -13196,10 +14665,14 @@
     sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + reqSz;
 
+    if (!ssl->options.dtls) {
+        if (IsEncryptionOn(ssl, 1))
+            sendSz += MAX_MSG_EXTRA;
+    }
+    else {
     #ifdef WOLFSSL_DTLS
-        if (ssl->options.dtls) {
             sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
             i      += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
-        }
     #endif
+    }
     /* check for available size */
     if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
@@ -13228,5 +14701,5 @@
     if (IsAtLeastTLSv1_2(ssl)) {
         c16toa(ssl->suites->hashSigAlgoSz, &output[i]);
-        i += LENGTH_SZ;
+        i += OPAQUE16_LEN;
 
         XMEMCPY(&output[i],
@@ -13238,10 +14711,10 @@
     c16toa((word16)dnLen, &output[i]);  /* auth's */
     i += REQ_HEADER_SZ;
-#ifdef WOLFSSL_NGINX
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX)
     names = ssl->ctx->ca_names;
     while (names != NULL) {
         byte seq[MAX_SEQ_SZ];
 
-        c16toa(names->data.name->rawLen +
+        c16toa((word16)names->data.name->rawLen +
                SetSequence(names->data.name->rawLen, seq), &output[i]);
         i += OPAQUE16_LEN;
@@ -13254,29 +14727,50 @@
     (void)i;
 
+        if (IsEncryptionOn(ssl, 1)) {
+            byte* input;
+            int   inputSz = i - RECORD_HEADER_SZ; /* build msg adds rec hdr */
+
+            input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+            if (input == NULL)
+                return MEMORY_E;
+
+            XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
+            sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
+                                  handshake, 1, 0, 0);
+            XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+
+            if (sendSz < 0)
+                return sendSz;
+        } else {
     #ifdef WOLFSSL_DTLS
+                if (ssl->options.dtls)
+                    DtlsSEQIncrement(ssl, CUR_ORDER);
         if (IsDtlsNotSctpMode(ssl)) {
             if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0)
                 return ret;
         }
-        if (ssl->options.dtls)
-            DtlsSEQIncrement(ssl, CUR_ORDER);
     #endif
-
     ret = HashOutput(ssl, output, sendSz, 0);
     if (ret != 0)
         return ret;
-
-    #ifdef WOLFSSL_CALLBACKS
+        }
+
+    #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
         if (ssl->hsInfoOn)
-            AddPacketName("CertificateRequest", &ssl->handShakeInfo);
+            AddPacketName(ssl, "CertificateRequest");
         if (ssl->toInfoOn)
-            AddPacketInfo("CertificateRequest", &ssl->timeoutInfo, output,
-                          sendSz, ssl->heap);
+            AddPacketInfo(ssl, "CertificateRequest", handshake, output, sendSz,
+                    WRITE_PROTO, ssl->heap);
     #endif
     ssl->buffers.outputBuffer.length += sendSz;
     if (ssl->options.groupMessages)
-        return 0;
+        ret = 0;
     else
-        return SendBuffered(ssl);
+        ret = SendBuffered(ssl);
+
+    WOLFSSL_LEAVE("SendCertificateRequest", ret);
+    WOLFSSL_END(WC_FUNC_CERTIFICATE_REQUEST_SEND);
+
+    return ret;
 }
 
@@ -13365,10 +14859,10 @@
     #endif
 
-    #ifdef WOLFSSL_CALLBACKS
+    #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
         if (ret == 0 && ssl->hsInfoOn)
-            AddPacketName("CertificateStatus", &ssl->handShakeInfo);
+            AddPacketName(ssl, "CertificateStatus");
         if (ret == 0 && ssl->toInfoOn)
-            AddPacketInfo("CertificateStatus", &ssl->timeoutInfo, output,
-                                                             sendSz, ssl->heap);
+            AddPacketInfo(ssl, "CertificateStatus", handshake, output, sendSz,
+                    WRITE_PROTO, ssl->heap);
     #endif
 
@@ -13386,5 +14880,5 @@
 #endif /* NO_WOLFSSL_SERVER */
 
-
+/* handle generation of certificate_status (22) */
 int SendCertificateStatus(WOLFSSL* ssl)
 {
@@ -13392,4 +14886,5 @@
     byte status_type = 0;
 
+    WOLFSSL_START(WC_FUNC_CERTIFICATE_STATUS_SEND);
     WOLFSSL_ENTER("SendCertificateStatus");
 
@@ -13415,12 +14910,32 @@
             buffer response;
 
-            XMEMSET(&response, 0, sizeof(response));
-
-            /* unable to fetch status. skip. */
-            if (ssl->ctx->cm == NULL || ssl->ctx->cm->ocspStaplingEnabled == 0)
-                return 0;
-
-            if (request == NULL || ssl->buffers.weOwnCert) {
-                DerBuffer* der = ssl->buffers.certificate;
+            ret = CreateOcspResponse(ssl, &request, &response);
+            if (ret == 0 && response.buffer) {
+                ret = BuildCertificateStatus(ssl, status_type, &response, 1);
+
+                XFREE(response.buffer, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
+                response.buffer = NULL;
+            }
+
+            break;
+        }
+
+    #endif /* HAVE_CERTIFICATE_STATUS_REQUEST    */
+           /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */
+
+    #if defined HAVE_CERTIFICATE_STATUS_REQUEST_V2
+        case WOLFSSL_CSR2_OCSP_MULTI:
+        {
+            OcspRequest* request = ssl->ctx->certOcspRequest;
+            buffer responses[1 + MAX_CHAIN_DEPTH];
+            int i = 0;
+
+            XMEMSET(responses, 0, sizeof(responses));
+
+            ret = CreateOcspResponse(ssl, &request, &responses[0]);
+            if (ret == 0 && (!ssl->ctx->chainOcspRequest[0]
+                                              || ssl->buffers.weOwnCertChain)) {
+                buffer der;
+                word32 idx = 0;
                 #ifdef WOLFSSL_SMALL_STACK
                     DecodedCert* cert = NULL;
@@ -13428,8 +14943,4 @@
                     DecodedCert  cert[1];
                 #endif
-
-                /* unable to fetch status. skip. */
-                if (der->buffer == NULL || der->length == 0)
-                    return 0;
 
             #ifdef WOLFSSL_SMALL_STACK
@@ -13439,49 +14950,29 @@
                     return MEMORY_E;
             #endif
-
-                InitDecodedCert(cert, der->buffer, der->length, ssl->heap);
-                /* TODO: Setup async support here */
-                if ((ret = ParseCertRelative(cert, CERT_TYPE, VERIFY,
-                                                          ssl->ctx->cm)) != 0) {
-                    WOLFSSL_MSG("ParseCert failed");
-                }
-                else {
-                    request = (OcspRequest*)XMALLOC(sizeof(OcspRequest),
-                                          ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
-                    if (request) {
-                        ret = InitOcspRequest(request, cert, 0, ssl->heap);
-                        if (ret == 0) {
-                            /* make sure ctx OCSP request is updated */
-                            if (!ssl->buffers.weOwnCert) {
-                                wolfSSL_Mutex* ocspLock =
-                                    &ssl->ctx->cm->ocsp_stapling->ocspLock;
-                                if (wc_LockMutex(ocspLock) == 0) {
-                                    if (ssl->ctx->certOcspRequest == NULL)
-                                        ssl->ctx->certOcspRequest = request;
-                                    wc_UnLockMutex(ocspLock);
-                                }
-                            }
-                        }
-                        else {
-                            XFREE(request, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
-                            request = NULL;
-                        }
-                    }
-                    else {
-                        ret = MEMORY_E;
-                    }
-                }
-
-                FreeDecodedCert(cert);
-
+                request = (OcspRequest*)XMALLOC(sizeof(OcspRequest), ssl->heap,
+                                                     DYNAMIC_TYPE_OCSP_REQUEST);
+                if (request == NULL) {
             #ifdef WOLFSSL_SMALL_STACK
                 XFREE(cert, ssl->heap, DYNAMIC_TYPE_DCERT);
             #endif
-            }
-
+                    return MEMORY_E;
+            }
+
+                while (idx + OPAQUE24_LEN < ssl->buffers.certChain->length) {
+                    c24to32(ssl->buffers.certChain->buffer + idx, &der.length);
+                    idx += OPAQUE24_LEN;
+
+                    der.buffer = ssl->buffers.certChain->buffer + idx;
+                    idx += der.length;
+
+                    if (idx > ssl->buffers.certChain->length)
+                        break;
+
+                    ret = CreateOcspRequest(ssl, request, cert, der.buffer,
+                                                                    der.length);
             if (ret == 0) {
                 request->ssl = ssl;
-                ret = CheckOcspRequest(ssl->ctx->cm->ocsp_stapling, request,
-                                                                     &response);
+                        ret = CheckOcspRequest(ssl->ctx->cm->ocsp_stapling,
+                                                    request, &responses[i + 1]);
 
                 /* Suppressing, not critical */
@@ -13492,100 +14983,21 @@
                 }
 
-                if (response.buffer) {
-                    if (ret == 0)
-                        ret = BuildCertificateStatus(ssl, status_type,
-                                                                  &response, 1);
-
-                    XFREE(response.buffer, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
-                    response.buffer = NULL;
+
+                        i++;
+                        FreeOcspRequest(request);
                 }
-
-            }
-
-            if (request != ssl->ctx->certOcspRequest)
+            }
+
                 XFREE(request, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
-
-            break;
-        }
-
-    #endif /* HAVE_CERTIFICATE_STATUS_REQUEST    */
-           /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */
-
-    #if defined HAVE_CERTIFICATE_STATUS_REQUEST_V2
-        case WOLFSSL_CSR2_OCSP_MULTI:
-        {
-            OcspRequest* request = ssl->ctx->certOcspRequest;
-            buffer responses[1 + MAX_CHAIN_DEPTH];
-            int i = 0;
-
-            XMEMSET(responses, 0, sizeof(responses));
-
-            /* unable to fetch status. skip. */
-            if (ssl->ctx->cm == NULL || ssl->ctx->cm->ocspStaplingEnabled == 0)
-                return 0;
-
-            if (!request || ssl->buffers.weOwnCert) {
-                DerBuffer* der = ssl->buffers.certificate;
-            #ifdef WOLFSSL_SMALL_STACK
-                DecodedCert* cert = NULL;
-            #else
-                DecodedCert  cert[1];
-            #endif
-
-                /* unable to fetch status. skip. */
-                if (der->buffer == NULL || der->length == 0)
-                    return 0;
-
-            #ifdef WOLFSSL_SMALL_STACK
-                cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), ssl->heap,
-                                             DYNAMIC_TYPE_DCERT);
-                if (cert == NULL)
-                    return MEMORY_E;
-            #endif
-
-                InitDecodedCert(cert, der->buffer, der->length, ssl->heap);
-                /* TODO: Setup async support here */
-                if ((ret = ParseCertRelative(cert, CERT_TYPE, VERIFY,
-                                                          ssl->ctx->cm)) != 0) {
-                    WOLFSSL_MSG("ParseCert failed");
-                }
-                else {
-                    request = (OcspRequest*)XMALLOC(sizeof(OcspRequest),
-                                          ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
-                    if (request) {
-                        ret = InitOcspRequest(request, cert, 0, ssl->heap);
-                        if (ret == 0) {
-                            /* make sure ctx OCSP request is updated */
-                            if (!ssl->buffers.weOwnCert) {
-                                wolfSSL_Mutex* ocspLock =
-                                    &ssl->ctx->cm->ocsp_stapling->ocspLock;
-                                if (wc_LockMutex(ocspLock) == 0) {
-                                    if (ssl->ctx->certOcspRequest == NULL)
-                                        ssl->ctx->certOcspRequest = request;
-                                    wc_UnLockMutex(ocspLock);
-                                }
-                            }
-                        }
-                        else {
-                            XFREE(request, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
-                            request = NULL;
-                        }
-                    }
-                    else {
-                        ret = MEMORY_E;
-                    }
-                }
-
-                FreeDecodedCert(cert);
-
             #ifdef WOLFSSL_SMALL_STACK
                 XFREE(cert, ssl->heap, DYNAMIC_TYPE_DCERT);
             #endif
-            }
-
-            if (ret == 0) {
-                request->ssl = ssl;
-                ret = CheckOcspRequest(ssl->ctx->cm->ocsp_stapling, request,
-                                                                 &responses[0]);
+        }
+            else {
+                while (ret == 0 &&
+                            NULL != (request = ssl->ctx->chainOcspRequest[i])) {
+                    request->ssl = ssl;
+                    ret = CheckOcspRequest(ssl->ctx->cm->ocsp_stapling,
+                                                request, &responses[++i]);
 
                 /* Suppressing, not critical */
@@ -13596,124 +15008,19 @@
                 }
             }
-
-            if (request != ssl->ctx->certOcspRequest)
-                XFREE(request, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
-
-            if (ret == 0 && (!ssl->ctx->chainOcspRequest[0]
-                                              || ssl->buffers.weOwnCertChain)) {
-                buffer der;
-                word32 idx = 0;
-            #ifdef WOLFSSL_SMALL_STACK
-                DecodedCert* cert = NULL;
-            #else
-                DecodedCert  cert[1];
-            #endif
-
-                XMEMSET(&der, 0, sizeof(buffer));
-
-            #ifdef WOLFSSL_SMALL_STACK
-                cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), ssl->heap,
-                                             DYNAMIC_TYPE_DCERT);
-                if (cert == NULL)
-                    return MEMORY_E;
-            #endif
-
-                while (idx + OPAQUE24_LEN < ssl->buffers.certChain->length) {
-                    c24to32(ssl->buffers.certChain->buffer + idx, &der.length);
-                    idx += OPAQUE24_LEN;
-
-                    der.buffer = ssl->buffers.certChain->buffer + idx;
-                    idx += der.length;
-
-                    if (idx > ssl->buffers.certChain->length)
-                        break;
-
-                    InitDecodedCert(cert, der.buffer, der.length, ssl->heap);
-                    /* TODO: Setup async support here */
-                    if ((ret = ParseCertRelative(cert, CERT_TYPE, VERIFY,
-                                                      ssl->ctx->cm)) != 0) {
-                        WOLFSSL_MSG("ParseCert failed");
-                        break;
-                    }
-                    else {
-                        request = (OcspRequest*)XMALLOC(sizeof(OcspRequest),
-                                          ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
-                        if (request == NULL) {
-                            FreeDecodedCert(cert);
-
-                            ret = MEMORY_E;
-                            break;
                         }
 
-                        ret = InitOcspRequest(request, cert, 0, ssl->heap);
+            if (responses[0].buffer) {
                         if (ret == 0) {
-                            /* make sure ctx OCSP request is updated */
-                            if (!ssl->buffers.weOwnCertChain) {
-                                wolfSSL_Mutex* ocspLock =
-                                    &ssl->ctx->cm->ocsp_stapling->ocspLock;
-                                if (wc_LockMutex(ocspLock) == 0) {
-                                    if (ssl->ctx->chainOcspRequest[i] == NULL)
-                                        ssl->ctx->chainOcspRequest[i] = request;
-                                    wc_UnLockMutex(ocspLock);
-                                }
-                            }
-                        }
-                        else {
-                            FreeDecodedCert(cert);
-                            XFREE(request, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
-                            request = NULL;
-                            break;
-                        }
-
-                        request->ssl = ssl;
-                        ret = CheckOcspRequest(ssl->ctx->cm->ocsp_stapling,
-                                                    request, &responses[i + 1]);
-
-                        /* Suppressing, not critical */
-                        if (ret == OCSP_CERT_REVOKED ||
-                            ret == OCSP_CERT_UNKNOWN ||
-                            ret == OCSP_LOOKUP_FAIL) {
-                            ret = 0;
-                        }
-
-                        if (request != ssl->ctx->chainOcspRequest[i])
-                            XFREE(request, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
-
-                        i++;
-                    }
-
-                    FreeDecodedCert(cert);
-                }
-
-            #ifdef WOLFSSL_SMALL_STACK
-                XFREE(cert, ssl->heap, DYNAMIC_TYPE_DCERT);
-            #endif
-            }
-            else {
-                while (ret == 0 &&
-                            NULL != (request = ssl->ctx->chainOcspRequest[i])) {
-                    request->ssl = ssl;
-                    ret = CheckOcspRequest(ssl->ctx->cm->ocsp_stapling,
-                                                request, &responses[++i]);
-
-                    /* Suppressing, not critical */
-                    if (ret == OCSP_CERT_REVOKED ||
-                        ret == OCSP_CERT_UNKNOWN ||
-                        ret == OCSP_LOOKUP_FAIL) {
-                        ret = 0;
-                    }
-                }
-            }
-
-            if (responses[0].buffer) {
-                if (ret == 0)
-                    ret = BuildCertificateStatus(ssl, status_type,
-                                                        responses, (byte)i + 1);
-
-                for (i = 0; i < 1 + MAX_CHAIN_DEPTH; i++)
-                    if (responses[i].buffer)
+                    ret = BuildCertificateStatus(ssl, status_type, responses,
+                                                                   (byte)i + 1);
+            }
+
+                for (i = 0; i < 1 + MAX_CHAIN_DEPTH; i++) {
+                    if (responses[i].buffer) {
                         XFREE(responses[i].buffer, ssl->heap,
                                                        DYNAMIC_TYPE_OCSP_REQUEST);
             }
+                }
+            }
 
             break;
@@ -13726,4 +15033,7 @@
     }
 
+    WOLFSSL_LEAVE("SendCertificateStatus", ret);
+    WOLFSSL_END(WC_FUNC_CERTIFICATE_STATUS_SEND);
+
     return ret;
 }
@@ -13731,4 +15041,5 @@
 #endif /* !NO_CERTS */
 
+#endif /* WOLFSSL_NO_TLS12 */
 
 int SendData(WOLFSSL* ssl, const void* data, int sz)
@@ -13738,7 +15049,13 @@
         ret,
         dtlsExtra = 0;
-
-    if (ssl->error == WANT_WRITE || ssl->error == WC_PENDING_E)
+    int groupMsgs = 0;
+
+    if (ssl->error == WANT_WRITE
+    #ifdef WOLFSSL_ASYNC_CRYPT
+        || ssl->error == WC_PENDING_E
+    #endif
+    ) {
         ssl->error = 0;
+    }
 
 #ifdef WOLFSSL_DTLS
@@ -13752,9 +15069,12 @@
 
 #ifdef WOLFSSL_EARLY_DATA
-    if (ssl->earlyData) {
+    if (ssl->earlyData != no_early_data) {
         if (ssl->options.handShakeState == HANDSHAKE_DONE) {
             WOLFSSL_MSG("handshake complete, trying to send early data");
             return BUILD_MSG_ERROR;
         }
+    #ifdef WOLFSSL_EARLY_DATA_GROUP
+        groupMsgs = 1;
+    #endif
     }
     else
@@ -13764,8 +15084,10 @@
         WOLFSSL_MSG("handshake not complete, trying to finish");
         if ( (err = wolfSSL_negotiate(ssl)) != WOLFSSL_SUCCESS) {
+        #ifdef WOLFSSL_ASYNC_CRYPT
             /* if async would block return WANT_WRITE */
             if (ssl->error == WC_PENDING_E) {
                 return WOLFSSL_CBIO_ERR_WANT_WRITE;
             }
+        #endif
             return  err;
         }
@@ -13773,10 +15095,14 @@
 
     /* last time system socket output buffer was full, try again to send */
-    if (ssl->buffers.outputBuffer.length > 0) {
+    if (!groupMsgs && ssl->buffers.outputBuffer.length > 0) {
         WOLFSSL_MSG("output buffer was full, trying to send again");
         if ( (ssl->error = SendBuffered(ssl)) < 0) {
             WOLFSSL_ERROR(ssl->error);
-            if (ssl->error == SOCKET_ERROR_E && ssl->options.connReset)
-                return 0;     /* peer reset */
+            if (ssl->error == SOCKET_ERROR_E && (ssl->options.connReset ||
+                                                 ssl->options.isClosed)) {
+                ssl->error = SOCKET_PEER_CLOSED_E;
+                WOLFSSL_ERROR(ssl->error);
+                return 0;  /* peer reset or closed */
+            }
             return ssl->error;
         }
@@ -13811,8 +15137,5 @@
         if (sent == sz) break;
 
-        len = min(sz - sent, OUTPUT_RECORD_SIZE);
-#ifdef HAVE_MAX_FRAGMENT
-        len = min(len, ssl->max_fragment);
-#endif
+        len = wolfSSL_GetMaxRecordSize(ssl, sz - sent);
 
 #ifdef WOLFSSL_DTLS
@@ -13863,13 +15186,17 @@
         ssl->buffers.outputBuffer.length += sendSz;
 
-        if ( (ret = SendBuffered(ssl)) < 0) {
-            WOLFSSL_ERROR(ret);
+        if ( (ssl->error = SendBuffered(ssl)) < 0) {
+            WOLFSSL_ERROR(ssl->error);
             /* store for next call if WANT_WRITE or user embedSend() that
                doesn't present like WANT_WRITE */
             ssl->buffers.plainSz  = len;
             ssl->buffers.prevSent = sent;
-            if (ret == SOCKET_ERROR_E && ssl->options.connReset)
-                return 0;  /* peer reset */
-            return ssl->error = ret;
+            if (ssl->error == SOCKET_ERROR_E && (ssl->options.connReset ||
+                                                 ssl->options.isClosed)) {
+                ssl->error = SOCKET_PEER_CLOSED_E;
+                WOLFSSL_ERROR(ssl->error);
+                return 0;  /* peer reset or closed */
+            }
+            return ssl->error;
         }
 
@@ -13878,5 +15205,5 @@
         /* only one message per attempt */
         if (ssl->options.partialWrite == 1) {
-            WOLFSSL_MSG("Paritial Write on, only sending one record");
+            WOLFSSL_MSG("Partial Write on, only sending one record");
             break;
         }
@@ -13894,5 +15221,9 @@
 
     /* reset error state */
-    if (ssl->error == WANT_READ || ssl->error == WC_PENDING_E) {
+    if (ssl->error == WANT_READ
+    #ifdef WOLFSSL_ASYNC_CRYPT
+        || ssl->error == WC_PENDING_E
+    #endif
+    ) {
         ssl->error = 0;
     }
@@ -13913,5 +15244,5 @@
 
 #ifdef WOLFSSL_EARLY_DATA
-    if (ssl->earlyData) {
+    if (ssl->earlyData != no_early_data) {
     }
     else
@@ -13935,8 +15266,8 @@
     if (ssl->secure_renegotiation && ssl->secure_renegotiation->startScr) {
         int err;
-        ssl->secure_renegotiation->startScr = 0;  /* only start once */
         WOLFSSL_MSG("Need to start scr, server requested");
         if ( (err = wolfSSL_Rehandshake(ssl)) != WOLFSSL_SUCCESS)
             return  err;
+        ssl->secure_renegotiation->startScr = 0;  /* only start once */
     }
 #endif
@@ -14026,4 +15357,9 @@
     }
 
+   #ifdef OPENSSL_EXTRA
+        if (ssl->CBIS != NULL) {
+            ssl->CBIS(ssl, SSL_CB_ALERT, type);
+        }
+   #endif
    #ifdef WOLFSSL_DTLS
         if (ssl->options.dtls)
@@ -14035,4 +15371,8 @@
     if ((ret = CheckAvailableSize(ssl, outputSz)) != 0)
         return ret;
+
+    /* Check output buffer */
+    if (ssl->buffers.outputBuffer.buffer == NULL)
+        return BUFFER_E;
 
     /* get output buffer */
@@ -14072,9 +15412,10 @@
         return BUILD_MSG_ERROR;
 
-    #ifdef WOLFSSL_CALLBACKS
+    #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
         if (ssl->hsInfoOn)
-            AddPacketName("Alert", &ssl->handShakeInfo);
+            AddPacketName(ssl, "Alert");
         if (ssl->toInfoOn)
-            AddPacketInfo("Alert", &ssl->timeoutInfo, output, sendSz,ssl->heap);
+            AddPacketInfo(ssl, "Alert", alert, output, sendSz, WRITE_PROTO,
+                    ssl->heap);
     #endif
 
@@ -14103,4 +15444,9 @@
     switch (error) {
 
+#ifdef WOLFSSL_WPAS
+    case 0 :
+        return "ok";
+#endif
+
     case UNSUPPORTED_SUITE :
         return "unsupported cipher suite";
@@ -14191,7 +15537,4 @@
         return "handshake layer not ready yet, complete first";
 
-    case PMS_VERSION_ERROR :
-        return "premaster secret version mismatch error";
-
     case VERSION_ERROR :
         return "record layer version error";
@@ -14231,13 +15574,4 @@
         return "NTRU decrypt error";
 
-    case ZLIB_INIT_ERROR:
-        return "zlib init error";
-
-    case ZLIB_COMPRESS_ERROR:
-        return "zlib compress error";
-
-    case ZLIB_DECOMPRESS_ERROR:
-        return "zlib decompress error";
-
     case GETTIME_ERROR:
         return "gettimeofday() error";
@@ -14325,7 +15659,4 @@
         return "Suites Pointer Error";
 
-    case SSL_NO_PEM_HEADER:
-        return "No PEM Header Error";
-
     case OUT_OF_ORDER_E:
         return "Out of order message, fatal";
@@ -14430,4 +15761,7 @@
         return "Invalid OCSP Status Error";
 
+    case OCSP_WANT_READ:
+        return "OCSP nonblock wants read";
+
     case RSA_KEY_SIZE_E:
         return "RSA key too small";
@@ -14464,5 +15798,5 @@
 
     case BAD_KEY_SHARE_DATA:
-        return "The Key Share data contains group that was in Client Hello";
+        return "The Key Share data contains group that wasn't in Client Hello";
 
     case MISSING_HANDSHAKE_DATA:
@@ -14477,4 +15811,7 @@
     case INVALID_PARAMETER:
         return "The security parameter is invalid";
+
+    case UNSUPPORTED_EXTENSION:
+        return "TLS Extension not requested by the client";
 
     case KEY_SHARE_ERROR:
@@ -14508,946 +15845,488 @@
 }
 
-
-/* be sure to add to cipher_name_idx too !!!! */
-static const char* const cipher_names[] =
+#ifndef NO_ERROR_STRINGS
+    #define SUITE_INFO(x,y,z,w) {(x),(y),(z),(w)}
+#else
+    #define SUITE_INFO(x,y,z,w) {(x),(z),(w)}
+#endif
+
+static const CipherSuiteInfo cipher_names[] =
 {
+#ifndef WOLFSSL_NO_TLS12
+
 #ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA
-    "RC4-SHA",
+    SUITE_INFO("RC4-SHA","SSL_RSA_WITH_RC4_128_SHA",CIPHER_BYTE,SSL_RSA_WITH_RC4_128_SHA),
 #endif
 
 #ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5
-    "RC4-MD5",
+    SUITE_INFO("RC4-MD5","SSL_RSA_WITH_RC4_128_MD5",CIPHER_BYTE,SSL_RSA_WITH_RC4_128_MD5),
 #endif
 
 #ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA
-    "DES-CBC3-SHA",
+    SUITE_INFO("DES-CBC3-SHA","SSL_RSA_WITH_3DES_EDE_CBC_SHA",CIPHER_BYTE,SSL_RSA_WITH_3DES_EDE_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA
-    "AES128-SHA",
+    SUITE_INFO("AES128-SHA","TLS_RSA_WITH_AES_128_CBC_SHA",CIPHER_BYTE,TLS_RSA_WITH_AES_128_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA
-    "AES256-SHA",
+    SUITE_INFO("AES256-SHA","TLS_RSA_WITH_AES_256_CBC_SHA",CIPHER_BYTE,TLS_RSA_WITH_AES_256_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_RSA_WITH_NULL_SHA
-    "NULL-SHA",
+    SUITE_INFO("NULL-SHA","TLS_RSA_WITH_NULL_SHA",CIPHER_BYTE,TLS_RSA_WITH_NULL_SHA),
 #endif
 
 #ifdef BUILD_TLS_RSA_WITH_NULL_SHA256
-    "NULL-SHA256",
+    SUITE_INFO("NULL-SHA256","TLS_RSA_WITH_NULL_SHA256",CIPHER_BYTE,TLS_RSA_WITH_NULL_SHA256),
 #endif
 
 #ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
-    "DHE-RSA-AES128-SHA",
+    SUITE_INFO("DHE-RSA-AES128-SHA","TLS_DHE_RSA_WITH_AES_128_CBC_SHA",CIPHER_BYTE,TLS_DHE_RSA_WITH_AES_128_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
-    "DHE-RSA-AES256-SHA",
+    SUITE_INFO("DHE-RSA-AES256-SHA","TLS_DHE_RSA_WITH_AES_256_CBC_SHA",CIPHER_BYTE,TLS_DHE_RSA_WITH_AES_256_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384
-    "DHE-PSK-AES256-GCM-SHA384",
+    SUITE_INFO("DHE-PSK-AES256-GCM-SHA384","TLS_DHE_PSK_WITH_AES_256_GCM_SHA384",CIPHER_BYTE,TLS_DHE_PSK_WITH_AES_256_GCM_SHA384),
 #endif
 
 #ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256
-    "DHE-PSK-AES128-GCM-SHA256",
+    SUITE_INFO("DHE-PSK-AES128-GCM-SHA256","TLS_DHE_PSK_WITH_AES_128_GCM_SHA256",CIPHER_BYTE,TLS_DHE_PSK_WITH_AES_128_GCM_SHA256),
 #endif
 
 #ifdef BUILD_TLS_PSK_WITH_AES_256_GCM_SHA384
-    "PSK-AES256-GCM-SHA384",
+    SUITE_INFO("PSK-AES256-GCM-SHA384","TLS_PSK_WITH_AES_256_GCM_SHA384",CIPHER_BYTE,TLS_PSK_WITH_AES_256_GCM_SHA384),
 #endif
 
 #ifdef BUILD_TLS_PSK_WITH_AES_128_GCM_SHA256
-    "PSK-AES128-GCM-SHA256",
+    SUITE_INFO("PSK-AES128-GCM-SHA256","TLS_PSK_WITH_AES_128_GCM_SHA256",CIPHER_BYTE,TLS_PSK_WITH_AES_128_GCM_SHA256),
 #endif
 
 #ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384
-    "DHE-PSK-AES256-CBC-SHA384",
+    SUITE_INFO("DHE-PSK-AES256-CBC-SHA384","TLS_DHE_PSK_WITH_AES_256_CBC_SHA384",CIPHER_BYTE,TLS_DHE_PSK_WITH_AES_256_CBC_SHA384),
 #endif
 
 #ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256
-    "DHE-PSK-AES128-CBC-SHA256",
+    SUITE_INFO("DHE-PSK-AES128-CBC-SHA256","TLS_DHE_PSK_WITH_AES_128_CBC_SHA256",CIPHER_BYTE,TLS_DHE_PSK_WITH_AES_128_CBC_SHA256),
 #endif
 
 #ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA384
-    "PSK-AES256-CBC-SHA384",
+    SUITE_INFO("PSK-AES256-CBC-SHA384","TLS_PSK_WITH_AES_256_CBC_SHA384",CIPHER_BYTE,TLS_PSK_WITH_AES_256_CBC_SHA384),
 #endif
 
 #ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA256
-    "PSK-AES128-CBC-SHA256",
+    SUITE_INFO("PSK-AES128-CBC-SHA256","TLS_PSK_WITH_AES_128_CBC_SHA256",CIPHER_BYTE,TLS_PSK_WITH_AES_128_CBC_SHA256),
 #endif
 
 #ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA
-    "PSK-AES128-CBC-SHA",
+    SUITE_INFO("PSK-AES128-CBC-SHA","TLS_PSK_WITH_AES_128_CBC_SHA",CIPHER_BYTE,TLS_PSK_WITH_AES_128_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA
-    "PSK-AES256-CBC-SHA",
+    SUITE_INFO("PSK-AES256-CBC-SHA","TLS_PSK_WITH_AES_256_CBC_SHA",CIPHER_BYTE,TLS_PSK_WITH_AES_256_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_CCM
-    "DHE-PSK-AES128-CCM",
+    SUITE_INFO("DHE-PSK-AES128-CCM","TLS_DHE_PSK_WITH_AES_128_CCM",ECC_BYTE,TLS_DHE_PSK_WITH_AES_128_CCM),
 #endif
 
 #ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_CCM
-    "DHE-PSK-AES256-CCM",
+    SUITE_INFO("DHE-PSK-AES256-CCM","TLS_DHE_PSK_WITH_AES_256_CCM",ECC_BYTE,TLS_DHE_PSK_WITH_AES_256_CCM),
 #endif
 
 #ifdef BUILD_TLS_PSK_WITH_AES_128_CCM
-    "PSK-AES128-CCM",
+    SUITE_INFO("PSK-AES128-CCM","TLS_PSK_WITH_AES_128_CCM",ECC_BYTE,TLS_PSK_WITH_AES_128_CCM),
 #endif
 
 #ifdef BUILD_TLS_PSK_WITH_AES_256_CCM
-    "PSK-AES256-CCM",
+    SUITE_INFO("PSK-AES256-CCM","TLS_PSK_WITH_AES_256_CCM",ECC_BYTE,TLS_PSK_WITH_AES_256_CCM),
 #endif
 
 #ifdef BUILD_TLS_PSK_WITH_AES_128_CCM_8
-    "PSK-AES128-CCM-8",
+    SUITE_INFO("PSK-AES128-CCM-8","TLS_PSK_WITH_AES_128_CCM_8",ECC_BYTE,TLS_PSK_WITH_AES_128_CCM_8),
 #endif
 
 #ifdef BUILD_TLS_PSK_WITH_AES_256_CCM_8
-    "PSK-AES256-CCM-8",
+    SUITE_INFO("PSK-AES256-CCM-8","TLS_PSK_WITH_AES_256_CCM_8",ECC_BYTE,TLS_PSK_WITH_AES_256_CCM_8),
 #endif
 
 #ifdef BUILD_TLS_DHE_PSK_WITH_NULL_SHA384
-    "DHE-PSK-NULL-SHA384",
+    SUITE_INFO("DHE-PSK-NULL-SHA384","TLS_DHE_PSK_WITH_NULL_SHA384",CIPHER_BYTE,TLS_DHE_PSK_WITH_NULL_SHA384),
 #endif
 
 #ifdef BUILD_TLS_DHE_PSK_WITH_NULL_SHA256
-    "DHE-PSK-NULL-SHA256",
+    SUITE_INFO("DHE-PSK-NULL-SHA256","TLS_DHE_PSK_WITH_NULL_SHA256",CIPHER_BYTE,TLS_DHE_PSK_WITH_NULL_SHA256),
 #endif
 
 #ifdef BUILD_TLS_PSK_WITH_NULL_SHA384
-    "PSK-NULL-SHA384",
+    SUITE_INFO("PSK-NULL-SHA384","TLS_PSK_WITH_NULL_SHA384",CIPHER_BYTE,TLS_PSK_WITH_NULL_SHA384),
 #endif
 
 #ifdef BUILD_TLS_PSK_WITH_NULL_SHA256
-    "PSK-NULL-SHA256",
+    SUITE_INFO("PSK-NULL-SHA256","TLS_PSK_WITH_NULL_SHA256",CIPHER_BYTE,TLS_PSK_WITH_NULL_SHA256),
 #endif
 
 #ifdef BUILD_TLS_PSK_WITH_NULL_SHA
-    "PSK-NULL-SHA",
+    SUITE_INFO("PSK-NULL-SHA","TLS_PSK_WITH_NULL_SHA",CIPHER_BYTE,TLS_PSK_WITH_NULL_SHA),
 #endif
 
 #ifdef BUILD_TLS_RSA_WITH_HC_128_MD5
-    "HC128-MD5",
+    SUITE_INFO("HC128-MD5","TLS_RSA_WITH_HC_128_MD5",CIPHER_BYTE,TLS_RSA_WITH_HC_128_MD5),
 #endif
 
 #ifdef BUILD_TLS_RSA_WITH_HC_128_SHA
-    "HC128-SHA",
+    SUITE_INFO("HC128-SHA","TLS_RSA_WITH_HC_128_SHA",CIPHER_BYTE,TLS_RSA_WITH_HC_128_SHA),
 #endif
 
 #ifdef BUILD_TLS_RSA_WITH_HC_128_B2B256
-    "HC128-B2B256",
+    SUITE_INFO("HC128-B2B256","TLS_RSA_WITH_HC_128_B2B256",CIPHER_BYTE,TLS_RSA_WITH_HC_128_B2B256),
 #endif
 
 #ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256
-    "AES128-B2B256",
+    SUITE_INFO("AES128-B2B256","TLS_RSA_WITH_AES_128_CBC_B2B256",CIPHER_BYTE,TLS_RSA_WITH_AES_128_CBC_B2B256),
 #endif
 
 #ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256
-    "AES256-B2B256",
+    SUITE_INFO("AES256-B2B256","TLS_RSA_WITH_AES_256_CBC_B2B256",CIPHER_BYTE,TLS_RSA_WITH_AES_256_CBC_B2B256),
 #endif
 
 #ifdef BUILD_TLS_RSA_WITH_RABBIT_SHA
-    "RABBIT-SHA",
+    SUITE_INFO("RABBIT-SHA","TLS_RSA_WITH_RABBIT_SHA",CIPHER_BYTE,TLS_RSA_WITH_RABBIT_SHA),
 #endif
 
 #ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA
-    "NTRU-RC4-SHA",
+    SUITE_INFO("NTRU-RC4-SHA","TLS_NTRU_RSA_WITH_RC4_128_SHA",CIPHER_BYTE,TLS_NTRU_RSA_WITH_RC4_128_SHA),
 #endif
 
 #ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA
-    "NTRU-DES-CBC3-SHA",
+    SUITE_INFO("NTRU-DES-CBC3-SHA","TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA",CIPHER_BYTE,TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
-    "NTRU-AES128-SHA",
+    SUITE_INFO("NTRU-AES128-SHA","TLS_NTRU_RSA_WITH_AES_128_CBC_SHA",CIPHER_BYTE,TLS_NTRU_RSA_WITH_AES_128_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
-    "NTRU-AES256-SHA",
+    SUITE_INFO("NTRU-AES256-SHA","TLS_NTRU_RSA_WITH_AES_256_CBC_SHA",CIPHER_BYTE,TLS_NTRU_RSA_WITH_AES_256_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8
-    "AES128-CCM-8",
+    SUITE_INFO("AES128-CCM-8","TLS_RSA_WITH_AES_128_CCM_8",ECC_BYTE,TLS_RSA_WITH_AES_128_CCM_8),
 #endif
 
 #ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8
-    "AES256-CCM-8",
+    SUITE_INFO("AES256-CCM-8","TLS_RSA_WITH_AES_256_CCM_8",ECC_BYTE,TLS_RSA_WITH_AES_256_CCM_8),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM
-    "ECDHE-ECDSA-AES128-CCM",
+	SUITE_INFO("ECDHE-ECDSA-AES128-CCM","TLS_ECDHE_ECDSA_WITH_AES_128_CCM",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_AES_128_CCM),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
-    "ECDHE-ECDSA-AES128-CCM-8",
+    SUITE_INFO("ECDHE-ECDSA-AES128-CCM-8","TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
-    "ECDHE-ECDSA-AES256-CCM-8",
+    SUITE_INFO("ECDHE-ECDSA-AES256-CCM-8","TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
-    "ECDHE-RSA-AES128-SHA",
+    SUITE_INFO("ECDHE-RSA-AES128-SHA","TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",ECC_BYTE,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
-    "ECDHE-RSA-AES256-SHA",
+    SUITE_INFO("ECDHE-RSA-AES256-SHA","TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",ECC_BYTE,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
-    "ECDHE-ECDSA-AES128-SHA",
+    SUITE_INFO("ECDHE-ECDSA-AES128-SHA","TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
-    "ECDHE-ECDSA-AES256-SHA",
+    SUITE_INFO("ECDHE-ECDSA-AES256-SHA","TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA
-    "ECDHE-RSA-RC4-SHA",
+    SUITE_INFO("ECDHE-RSA-RC4-SHA","TLS_ECDHE_RSA_WITH_RC4_128_SHA",ECC_BYTE,TLS_ECDHE_RSA_WITH_RC4_128_SHA),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
-    "ECDHE-RSA-DES-CBC3-SHA",
+    SUITE_INFO("ECDHE-RSA-DES-CBC3-SHA","TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",ECC_BYTE,TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
-    "ECDHE-ECDSA-RC4-SHA",
+    SUITE_INFO("ECDHE-ECDSA-RC4-SHA","TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_RC4_128_SHA),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
-    "ECDHE-ECDSA-DES-CBC3-SHA",
+    SUITE_INFO("ECDHE-ECDSA-DES-CBC3-SHA","TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256
-    "AES128-SHA256",
+    SUITE_INFO("AES128-SHA256","TLS_RSA_WITH_AES_128_CBC_SHA256",CIPHER_BYTE,TLS_RSA_WITH_AES_128_CBC_SHA256),
 #endif
 
 #ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256
-    "AES256-SHA256",
+    SUITE_INFO("AES256-SHA256","TLS_RSA_WITH_AES_256_CBC_SHA256",CIPHER_BYTE,TLS_RSA_WITH_AES_256_CBC_SHA256),
 #endif
 
 #ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
-    "DHE-RSA-AES128-SHA256",
+    SUITE_INFO("DHE-RSA-AES128-SHA256","TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",CIPHER_BYTE,TLS_DHE_RSA_WITH_AES_128_CBC_SHA256),
 #endif
 
 #ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
-    "DHE-RSA-AES256-SHA256",
+    SUITE_INFO("DHE-RSA-AES256-SHA256","TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",CIPHER_BYTE,TLS_DHE_RSA_WITH_AES_256_CBC_SHA256),
 #endif
 
 #ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
-    "ECDH-RSA-AES128-SHA",
+    SUITE_INFO("ECDH-RSA-AES128-SHA","TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",ECC_BYTE,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
-    "ECDH-RSA-AES256-SHA",
+    SUITE_INFO("ECDH-RSA-AES256-SHA","TLS_ECDH_RSA_WITH_AES_256_CBC_SHA",ECC_BYTE,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
-    "ECDH-ECDSA-AES128-SHA",
+    SUITE_INFO("ECDH-ECDSA-AES128-SHA","TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",ECC_BYTE,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
-    "ECDH-ECDSA-AES256-SHA",
+    SUITE_INFO("ECDH-ECDSA-AES256-SHA","TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA",ECC_BYTE,TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA
-    "ECDH-RSA-RC4-SHA",
+    SUITE_INFO("ECDH-RSA-RC4-SHA","TLS_ECDH_RSA_WITH_RC4_128_SHA",ECC_BYTE,TLS_ECDH_RSA_WITH_RC4_128_SHA),
 #endif
 
 #ifdef BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
-    "ECDH-RSA-DES-CBC3-SHA",
+    SUITE_INFO("ECDH-RSA-DES-CBC3-SHA","TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",ECC_BYTE,TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA
-    "ECDH-ECDSA-RC4-SHA",
+    SUITE_INFO("ECDH-ECDSA-RC4-SHA","TLS_ECDH_ECDSA_WITH_RC4_128_SHA",ECC_BYTE,TLS_ECDH_ECDSA_WITH_RC4_128_SHA),
 #endif
 
 #ifdef BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
-    "ECDH-ECDSA-DES-CBC3-SHA",
+    SUITE_INFO("ECDH-ECDSA-DES-CBC3-SHA","TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",ECC_BYTE,TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256
-    "AES128-GCM-SHA256",
+    SUITE_INFO("AES128-GCM-SHA256","TLS_RSA_WITH_AES_128_GCM_SHA256",CIPHER_BYTE,TLS_RSA_WITH_AES_128_GCM_SHA256),
 #endif
 
 #ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384
-    "AES256-GCM-SHA384",
+    SUITE_INFO("AES256-GCM-SHA384","TLS_RSA_WITH_AES_256_GCM_SHA384",CIPHER_BYTE,TLS_RSA_WITH_AES_256_GCM_SHA384),
 #endif
 
 #ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
-    "DHE-RSA-AES128-GCM-SHA256",
+    SUITE_INFO("DHE-RSA-AES128-GCM-SHA256","TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",CIPHER_BYTE,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256),
 #endif
 
 #ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
-    "DHE-RSA-AES256-GCM-SHA384",
+    SUITE_INFO("DHE-RSA-AES256-GCM-SHA384","TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",CIPHER_BYTE,TLS_DHE_RSA_WITH_AES_256_GCM_SHA384),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
-    "ECDHE-RSA-AES128-GCM-SHA256",
+    SUITE_INFO("ECDHE-RSA-AES128-GCM-SHA256","TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",ECC_BYTE,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
-    "ECDHE-RSA-AES256-GCM-SHA384",
+    SUITE_INFO("ECDHE-RSA-AES256-GCM-SHA384","TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",ECC_BYTE,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
-    "ECDHE-ECDSA-AES128-GCM-SHA256",
+    SUITE_INFO("ECDHE-ECDSA-AES128-GCM-SHA256","TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
-    "ECDHE-ECDSA-AES256-GCM-SHA384",
+    SUITE_INFO("ECDHE-ECDSA-AES256-GCM-SHA384","TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384),
 #endif
 
 #ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
-    "ECDH-RSA-AES128-GCM-SHA256",
+    SUITE_INFO("ECDH-RSA-AES128-GCM-SHA256","TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",ECC_BYTE,TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256),
 #endif
 
 #ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
-    "ECDH-RSA-AES256-GCM-SHA384",
+    SUITE_INFO("ECDH-RSA-AES256-GCM-SHA384","TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384",ECC_BYTE,TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384),
 #endif
 
 #ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
-    "ECDH-ECDSA-AES128-GCM-SHA256",
+    SUITE_INFO("ECDH-ECDSA-AES128-GCM-SHA256","TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",ECC_BYTE,TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256),
 #endif
 
 #ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
-    "ECDH-ECDSA-AES256-GCM-SHA384",
+    SUITE_INFO("ECDH-ECDSA-AES256-GCM-SHA384","TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384",ECC_BYTE,TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384),
 #endif
 
 #ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
-    "CAMELLIA128-SHA",
+    SUITE_INFO("CAMELLIA128-SHA","TLS_RSA_WITH_CAMELLIA_128_CBC_SHA",CIPHER_BYTE,TLS_RSA_WITH_CAMELLIA_128_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
-    "DHE-RSA-CAMELLIA128-SHA",
+    SUITE_INFO("DHE-RSA-CAMELLIA128-SHA","TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA",CIPHER_BYTE,TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
-    "CAMELLIA256-SHA",
+    SUITE_INFO("CAMELLIA256-SHA","TLS_RSA_WITH_CAMELLIA_256_CBC_SHA",CIPHER_BYTE,TLS_RSA_WITH_CAMELLIA_256_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
-    "DHE-RSA-CAMELLIA256-SHA",
+    SUITE_INFO("DHE-RSA-CAMELLIA256-SHA","TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA",CIPHER_BYTE,TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
-    "CAMELLIA128-SHA256",
+    SUITE_INFO("CAMELLIA128-SHA256","TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256",CIPHER_BYTE,TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256),
 #endif
 
 #ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
-    "DHE-RSA-CAMELLIA128-SHA256",
+    SUITE_INFO("DHE-RSA-CAMELLIA128-SHA256","TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",CIPHER_BYTE,TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256),
 #endif
 
 #ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256
-    "CAMELLIA256-SHA256",
+    SUITE_INFO("CAMELLIA256-SHA256","TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256",CIPHER_BYTE,TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256),
 #endif
 
 #ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
-    "DHE-RSA-CAMELLIA256-SHA256",
+    SUITE_INFO("DHE-RSA-CAMELLIA256-SHA256","TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256",CIPHER_BYTE,TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
-    "ECDHE-RSA-AES128-SHA256",
+    SUITE_INFO("ECDHE-RSA-AES128-SHA256","TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",ECC_BYTE,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
-    "ECDHE-ECDSA-AES128-SHA256",
+    SUITE_INFO("ECDHE-ECDSA-AES128-SHA256","TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256),
 #endif
 
 #ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
-    "ECDH-RSA-AES128-SHA256",
+    SUITE_INFO("ECDH-RSA-AES128-SHA256","TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256",ECC_BYTE,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256),
 #endif
 
 #ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
-    "ECDH-ECDSA-AES128-SHA256",
+    SUITE_INFO("ECDH-ECDSA-AES128-SHA256","TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256",ECC_BYTE,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
-    "ECDHE-RSA-AES256-SHA384",
+    SUITE_INFO("ECDHE-RSA-AES256-SHA384","TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",ECC_BYTE,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
-    "ECDHE-ECDSA-AES256-SHA384",
+    SUITE_INFO("ECDHE-ECDSA-AES256-SHA384","TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384),
 #endif
 
 #ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
-    "ECDH-RSA-AES256-SHA384",
+    SUITE_INFO("ECDH-RSA-AES256-SHA384","TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384",ECC_BYTE,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384),
 #endif
 
 #ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
-    "ECDH-ECDSA-AES256-SHA384",
+    SUITE_INFO("ECDH-ECDSA-AES256-SHA384","TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384",ECC_BYTE,TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
-    "ECDHE-RSA-CHACHA20-POLY1305",
+    SUITE_INFO("ECDHE-RSA-CHACHA20-POLY1305","TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",CHACHA_BYTE,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
-    "ECDHE-ECDSA-CHACHA20-POLY1305",
+    SUITE_INFO("ECDHE-ECDSA-CHACHA20-POLY1305","TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",CHACHA_BYTE,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256),
 #endif
 
 #ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
-    "DHE-RSA-CHACHA20-POLY1305",
+    SUITE_INFO("DHE-RSA-CHACHA20-POLY1305","TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256",CHACHA_BYTE,TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256
-    "ECDHE-RSA-CHACHA20-POLY1305-OLD",
+    SUITE_INFO("ECDHE-RSA-CHACHA20-POLY1305-OLD","TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256",CHACHA_BYTE,TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256
-    "ECDHE-ECDSA-CHACHA20-POLY1305-OLD",
+    SUITE_INFO("ECDHE-ECDSA-CHACHA20-POLY1305-OLD","TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256",CHACHA_BYTE,TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256),
 #endif
 
 #ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256
-    "DHE-RSA-CHACHA20-POLY1305-OLD",
+    SUITE_INFO("DHE-RSA-CHACHA20-POLY1305-OLD","TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256",CHACHA_BYTE,TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256),
 #endif
 
 #ifdef BUILD_TLS_DH_anon_WITH_AES_128_CBC_SHA
-    "ADH-AES128-SHA",
+    SUITE_INFO("ADH-AES128-SHA","TLS_DH_anon_WITH_AES_128_CBC_SHA",CIPHER_BYTE,TLS_DH_anon_WITH_AES_128_CBC_SHA),
+#endif
+
+#ifdef BUILD_TLS_DH_anon_WITH_AES_256_GCM_SHA384
+    SUITE_INFO("ADH-AES256-GCM-SHA384","TLS_DH_anon_WITH_AES_256_GCM_SHA384",CIPHER_BYTE,TLS_DH_anon_WITH_AES_256_GCM_SHA384),
 #endif
 
 #ifdef BUILD_TLS_QSH
-    "QSH",
+    SUITE_INFO("QSH","TLS_QSH",QSH_BYTE,TLS_QSH),
 #endif
 
 #ifdef HAVE_RENEGOTIATION_INDICATION
-    "RENEGOTIATION-INFO",
+    SUITE_INFO("RENEGOTIATION-INFO","TLS_EMPTY_RENEGOTIATION_INFO_SCSV",CIPHER_BYTE,TLS_EMPTY_RENEGOTIATION_INFO_SCSV),
 #endif
 
 #ifdef BUILD_SSL_RSA_WITH_IDEA_CBC_SHA
-    "IDEA-CBC-SHA",
+    SUITE_INFO("IDEA-CBC-SHA","SSL_RSA_WITH_IDEA_CBC_SHA",CIPHER_BYTE,SSL_RSA_WITH_IDEA_CBC_SHA),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_NULL_SHA
-    "ECDHE-ECDSA-NULL-SHA",
+    SUITE_INFO("ECDHE-ECDSA-NULL-SHA","TLS_ECDHE_ECDSA_WITH_NULL_SHA",ECC_BYTE,TLS_ECDHE_ECDSA_WITH_NULL_SHA),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_PSK_WITH_NULL_SHA256
-    "ECDHE-PSK-NULL-SHA256",
+    SUITE_INFO("ECDHE-PSK-NULL-SHA256","TLS_ECDHE_PSK_WITH_NULL_SHA256",ECC_BYTE,TLS_ECDHE_PSK_WITH_NULL_SHA256),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256
-    "ECDHE-PSK-AES128-CBC-SHA256",
+    SUITE_INFO("ECDHE-PSK-AES128-CBC-SHA256","TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256",ECC_BYTE,TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256),
 #endif
 
 #ifdef BUILD_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256
-    "PSK-CHACHA20-POLY1305",
+    SUITE_INFO("PSK-CHACHA20-POLY1305","TLS_PSK_WITH_CHACHA20_POLY1305_SHA256",CHACHA_BYTE,TLS_PSK_WITH_CHACHA20_POLY1305_SHA256),
 #endif
 
 #ifdef BUILD_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256
-    "ECDHE-PSK-CHACHA20-POLY1305",
+    SUITE_INFO("ECDHE-PSK-CHACHA20-POLY1305","TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256",CHACHA_BYTE,TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256),
 #endif
 
 #ifdef BUILD_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256
-    "DHE-PSK-CHACHA20-POLY1305",
+    SUITE_INFO("DHE-PSK-CHACHA20-POLY1305","TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256",CHACHA_BYTE,TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256),
 #endif
 
 #ifdef BUILD_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
-    "EDH-RSA-DES-CBC3-SHA",
-#endif
+    SUITE_INFO("EDH-RSA-DES-CBC3-SHA","TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",CIPHER_BYTE,TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA),
+#endif
+
+#ifdef BUILD_WDM_WITH_NULL_SHA256
+    SUITE_INFO("WDM-NULL-SHA256","WDM_WITH_NULL_SHA256",CIPHER_BYTE,WDM_WITH_NULL_SHA256),
+#endif
+
+#endif /* WOLFSSL_NO_TLS12 */
 
 #ifdef BUILD_TLS_AES_128_GCM_SHA256
-    "TLS13-AES128-GCM-SHA256",
+    SUITE_INFO("TLS13-AES128-GCM-SHA256","TLS_AES_128_GCM_SHA256",TLS13_BYTE,TLS_AES_128_GCM_SHA256),
 #endif
 
 #ifdef BUILD_TLS_AES_256_GCM_SHA384
-    "TLS13-AES256-GCM-SHA384",
+    SUITE_INFO("TLS13-AES256-GCM-SHA384","TLS_AES_256_GCM_SHA384",TLS13_BYTE,TLS_AES_256_GCM_SHA384),
 #endif
 
 #ifdef BUILD_TLS_CHACHA20_POLY1305_SHA256
-    "TLS13-CHACHA20-POLY1305-SHA256",
+    SUITE_INFO("TLS13-CHACHA20-POLY1305-SHA256","TLS_CHACHA20_POLY1305_SHA256",TLS13_BYTE,TLS_CHACHA20_POLY1305_SHA256),
 #endif
 
 #ifdef BUILD_TLS_AES_128_CCM_SHA256
-    "TLS13-AES128-CCM-SHA256",
+    SUITE_INFO("TLS13-AES128-CCM-SHA256","TLS_AES_128_CCM_SHA256",TLS13_BYTE,TLS_AES_128_CCM_SHA256),
 #endif
 
 #ifdef BUILD_TLS_AES_128_CCM_8_SHA256
-    "TLS13-AES128-CCM-8-SHA256",
-#endif
-
-#ifdef BUILD_WDM_WITH_NULL_SHA256
-    "WDM-NULL-SHA256",
+    SUITE_INFO("TLS13-AES128-CCM-8-SHA256","TLS_AES_128_CCM_8_SHA256",TLS13_BYTE,TLS_AES_128_CCM_8_SHA256),
 #endif
 };
 
 
-/* cipher suite number that matches above name table */
-static int cipher_name_idx[] =
-{
-
-#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA
-    SSL_RSA_WITH_RC4_128_SHA,
-#endif
-
-#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5
-    SSL_RSA_WITH_RC4_128_MD5,
-#endif
-
-#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA
-    SSL_RSA_WITH_3DES_EDE_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA
-    TLS_RSA_WITH_AES_128_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA
-    TLS_RSA_WITH_AES_256_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_RSA_WITH_NULL_SHA
-    TLS_RSA_WITH_NULL_SHA,
-#endif
-
-#ifdef BUILD_TLS_RSA_WITH_NULL_SHA256
-    TLS_RSA_WITH_NULL_SHA256,
-#endif
-
-#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
-    TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
-    TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384
-    TLS_DHE_PSK_WITH_AES_256_GCM_SHA384,
-#endif
-
-#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256
-    TLS_DHE_PSK_WITH_AES_128_GCM_SHA256,
-#endif
-
-#ifdef BUILD_TLS_PSK_WITH_AES_256_GCM_SHA384
-    TLS_PSK_WITH_AES_256_GCM_SHA384,
-#endif
-
-#ifdef BUILD_TLS_PSK_WITH_AES_128_GCM_SHA256
-    TLS_PSK_WITH_AES_128_GCM_SHA256,
-#endif
-
-#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384
-    TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,
-#endif
-
-#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256
-    TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
-#endif
-
-#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA384
-    TLS_PSK_WITH_AES_256_CBC_SHA384,
-#endif
-
-#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA256
-    TLS_PSK_WITH_AES_128_CBC_SHA256,
-#endif
-
-#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA
-    TLS_PSK_WITH_AES_128_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA
-    TLS_PSK_WITH_AES_256_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_CCM
-    TLS_DHE_PSK_WITH_AES_128_CCM,
-#endif
-
-#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_CCM
-    TLS_DHE_PSK_WITH_AES_256_CCM,
-#endif
-
-#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM
-    TLS_PSK_WITH_AES_128_CCM,
-#endif
-
-#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM
-    TLS_PSK_WITH_AES_256_CCM,
-#endif
-
-#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM_8
-    TLS_PSK_WITH_AES_128_CCM_8,
-#endif
-
-#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM_8
-    TLS_PSK_WITH_AES_256_CCM_8,
-#endif
-
-#ifdef BUILD_TLS_DHE_PSK_WITH_NULL_SHA384
-    TLS_DHE_PSK_WITH_NULL_SHA384,
-#endif
-
-#ifdef BUILD_TLS_DHE_PSK_WITH_NULL_SHA256
-    TLS_DHE_PSK_WITH_NULL_SHA256,
-#endif
-
-#ifdef BUILD_TLS_PSK_WITH_NULL_SHA384
-    TLS_PSK_WITH_NULL_SHA384,
-#endif
-
-#ifdef BUILD_TLS_PSK_WITH_NULL_SHA256
-    TLS_PSK_WITH_NULL_SHA256,
-#endif
-
-#ifdef BUILD_TLS_PSK_WITH_NULL_SHA
-    TLS_PSK_WITH_NULL_SHA,
-#endif
-
-#ifdef BUILD_TLS_RSA_WITH_HC_128_MD5
-    TLS_RSA_WITH_HC_128_MD5,
-#endif
-
-#ifdef BUILD_TLS_RSA_WITH_HC_128_SHA
-    TLS_RSA_WITH_HC_128_SHA,
-#endif
-
-#ifdef BUILD_TLS_RSA_WITH_HC_128_B2B256
-    TLS_RSA_WITH_HC_128_B2B256,
-#endif
-
-#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256
-    TLS_RSA_WITH_AES_128_CBC_B2B256,
-#endif
-
-#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256
-    TLS_RSA_WITH_AES_256_CBC_B2B256,
-#endif
-
-#ifdef BUILD_TLS_RSA_WITH_RABBIT_SHA
-    TLS_RSA_WITH_RABBIT_SHA,
-#endif
-
-#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA
-    TLS_NTRU_RSA_WITH_RC4_128_SHA,
-#endif
-
-#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA
-    TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
-    TLS_NTRU_RSA_WITH_AES_128_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
-    TLS_NTRU_RSA_WITH_AES_256_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8
-    TLS_RSA_WITH_AES_128_CCM_8,
-#endif
-
-#ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8
-    TLS_RSA_WITH_AES_256_CCM_8,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM
-    TLS_ECDHE_ECDSA_WITH_AES_128_CCM,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
-    TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
-    TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
-    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
-    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
-    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
-    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA
-    TLS_ECDHE_RSA_WITH_RC4_128_SHA,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
-    TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
-    TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
-    TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256
-    TLS_RSA_WITH_AES_128_CBC_SHA256,
-#endif
-
-#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256
-    TLS_RSA_WITH_AES_256_CBC_SHA256,
-#endif
-
-#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
-    TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
-#endif
-
-#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
-    TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
-#endif
-
-#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
-    TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
-    TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
-    TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
-    TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA
-    TLS_ECDH_RSA_WITH_RC4_128_SHA,
-#endif
-
-#ifdef BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
-    TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA
-    TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
-#endif
-
-#ifdef BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
-    TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256
-    TLS_RSA_WITH_AES_128_GCM_SHA256,
-#endif
-
-#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384
-    TLS_RSA_WITH_AES_256_GCM_SHA384,
-#endif
-
-#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
-    TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
-#endif
-
-#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
-    TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
-    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
-    TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
-    TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
-    TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
-#endif
-
-#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
-    TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
-#endif
-
-#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
-    TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
-#endif
-
-#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
-    TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
-#endif
-
-#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
-    TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
-#endif
-
-#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
-    TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
-    TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
-    TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
-    TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
-    TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256,
-#endif
-
-#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
-    TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
-#endif
-
-#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256
-    TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256,
-#endif
-
-#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
-    TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
-    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
-    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
-#endif
-
-#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
-    TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
-#endif
-
-#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
-    TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
-    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
-    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
-#endif
-
-#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
-    TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
-#endif
-
-#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
-    TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
-    TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
-    TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
-#endif
-
-#ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
-    TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256
-    TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256
-    TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256,
-#endif
-
-#ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256
-    TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256,
-#endif
-
-#ifdef BUILD_TLS_DH_anon_WITH_AES_128_CBC_SHA
-    TLS_DH_anon_WITH_AES_128_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_QSH
-    TLS_QSH,
-#endif
-
-#ifdef HAVE_RENEGOTIATION_INDICATION
-    TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
-#endif
-
-#ifdef BUILD_SSL_RSA_WITH_IDEA_CBC_SHA
-    SSL_RSA_WITH_IDEA_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_NULL_SHA
-    TLS_ECDHE_ECDSA_WITH_NULL_SHA,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_PSK_WITH_NULL_SHA256
-    TLS_ECDHE_PSK_WITH_NULL_SHA256,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256
-    TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
-#endif
-
-#ifdef BUILD_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256
-    TLS_PSK_WITH_CHACHA20_POLY1305_SHA256,
-#endif
-
-#ifdef BUILD_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256
-    TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
-#endif
-
-#ifdef BUILD_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256
-    TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
-#endif
-
-#ifdef BUILD_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
-    TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
-#endif
-
-#ifdef BUILD_TLS_AES_128_GCM_SHA256
-    TLS_AES_128_GCM_SHA256,
-#endif
-
-#ifdef BUILD_TLS_AES_256_GCM_SHA384
-    TLS_AES_256_GCM_SHA384,
-#endif
-
-#ifdef BUILD_TLS_CHACHA20_POLY1305_SHA256
-    TLS_CHACHA20_POLY1305_SHA256,
-#endif
-
-#ifdef BUILD_TLS_AES_128_CCM_SHA256
-    TLS_AES_128_CCM_SHA256,
-#endif
-
-#ifdef BUILD_TLS_AES_128_CCM_8_SHA256
-    TLS_AES_128_CCM_8_SHA256,
-#endif
-
-#ifdef BUILD_WDM_WITH_NULL_SHA256
-    WDM_WITH_NULL_SHA256,
-#endif
-};
-
-
 /* returns the cipher_names array */
-const char* const* GetCipherNames(void)
+const CipherSuiteInfo* GetCipherNames(void)
 {
     return cipher_names;
@@ -15455,53 +16334,45 @@
 
 
-/* returns the size of the cipher_names array */
+/* returns the number of elements in the cipher_names array */
 int GetCipherNamesSize(void)
 {
-    return (int)(sizeof(cipher_names) / sizeof(char*));
+    return (int)(sizeof(cipher_names) / sizeof(CipherSuiteInfo));
 }
 
-/* gets cipher name in the format DHE-RSA-... rather then TLS_DHE... */
-const char* GetCipherNameInternal(const char* cipherName, int cipherSuite)
+
+const char* GetCipherNameInternal(const byte cipherSuite0, const byte cipherSuite)
 {
-    const char* result = NULL;
-    const char* first;
     int i;
-
-    if (cipherName == NULL) {
-        WOLFSSL_MSG("Bad argument");
-        return NULL;
-    }
-
-    first = (XSTRSTR(cipherName, "CHACHA")) ? "CHACHA"
-          : (XSTRSTR(cipherName, "EC"))     ? "EC"
-          : (XSTRSTR(cipherName, "CCM"))    ? "CCM"
-          : NULL; /* normal */
-
-    for (i = 0; i < (int)(sizeof(cipher_name_idx)/sizeof(int)); i++) {
-        if (cipher_name_idx[i] == cipherSuite) {
-            const char* nameFound = cipher_names[i];
-
-            /* extra sanity check on returned cipher name */
-            if (nameFound == NULL) {
-                continue;
-            }
-
-            /* if first is null then not any */
-            if (first == NULL) {
-                if (    !XSTRSTR(nameFound, "CHACHA") &&
-                        !XSTRSTR(nameFound, "EC") &&
-                        !XSTRSTR(nameFound, "CCM")) {
-                    result = nameFound;
-                    break;
-                }
-            }
-            else if (XSTRSTR(nameFound, first)) {
-                result = nameFound;
-                break;
-            }
-        }
-    }
-
-    return result;
+    const char* nameInternal = NULL;
+
+    for (i = 0; i < GetCipherNamesSize(); i++) {
+        if ((cipher_names[i].cipherSuite0 == cipherSuite0) &&
+            (cipher_names[i].cipherSuite  == cipherSuite)) {
+            nameInternal = cipher_names[i].name;
+            break;
+        }
+    }
+    return nameInternal;
+}
+
+const char* GetCipherNameIana(const byte cipherSuite0, const byte cipherSuite)
+{
+#ifndef NO_ERROR_STRINGS
+    int i;
+    const char* nameIana = "NONE";
+
+    for (i = 0; i < GetCipherNamesSize(); i++) {
+        if ((cipher_names[i].cipherSuite0 == cipherSuite0) &&
+            (cipher_names[i].cipherSuite  == cipherSuite)) {
+            nameIana = cipher_names[i].name_iana;
+            break;
+        }
+    }
+    return nameIana;
+#else
+    (void)cipherSuite0;
+    (void)cipherSuite;
+    return NULL;
+#endif
 }
 
@@ -15509,442 +16380,37 @@
 {
     if (ssl == NULL) {
-        WOLFSSL_MSG("Bad argument");
         return NULL;
     }
 
-    return GetCipherNameInternal(
-        wolfSSL_CIPHER_get_name(&ssl->cipher),
-        ssl->options.cipherSuite);
+    return GetCipherNameInternal(ssl->options.cipherSuite0, ssl->options.cipherSuite);
 }
 
-
-const char* wolfSSL_get_cipher_name_from_suite(const unsigned char cipherSuite,
-    const unsigned char cipherSuite0)
+const char* wolfSSL_get_cipher_name_iana(WOLFSSL* ssl)
 {
-
-    WOLFSSL_ENTER("wolfSSL_get_cipher_name_from_suite");
-
-    (void)cipherSuite;
-    (void)cipherSuite0;
-
-#ifndef NO_ERROR_STRINGS
-
-#if defined(HAVE_CHACHA)
-    if (cipherSuite0 == CHACHA_BYTE) {
-        /* ChaCha suites */
-        switch (cipherSuite) {
-#ifdef HAVE_POLY1305
-#ifndef NO_RSA
-            case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 :
-                return "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256";
-
-            case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 :
-                return "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256";
-
-            case TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 :
-                return "TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256";
-
-            case TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 :
-                return "TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256";
-#endif
-            case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 :
-                return "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256";
-
-            case TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256 :
-                return "TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256";
-#ifndef NO_PSK
-            case TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 :
-                return "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256";
-            case TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 :
-                return "TLS_PSK_WITH_CHACHA20_POLY1305_SHA256";
-            case TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 :
-                return "TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256";
-#endif /* NO_PSK */
-#endif /* HAVE_POLY1305 */
-        } /* switch */
-    } /* chacha */
-#endif /* HAVE_CHACHA */
-
-#if defined(HAVE_ECC) || defined(HAVE_AESCCM)
-        /* Awkwardly, the ECC cipher suites use the ECC_BYTE as expected,
-         * but the AES-CCM cipher suites also use it, even the ones that
-         * aren't ECC. */
-    if (cipherSuite0 == ECC_BYTE) {
-        /* ECC suites */
-        switch (cipherSuite) {
-#ifdef HAVE_ECC
-    #ifndef NO_RSA
-            case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 :
-                return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256";
-    #endif /* !NO_RSA */
-            case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 :
-                return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256";
-    #ifndef NO_RSA
-            case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 :
-                return "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256";
-    #endif /* !NO_RSA */
-            case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 :
-                return "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256";
-    #ifndef NO_RSA
-            case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 :
-                return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384";
-    #endif /* !NO_RSA */
-            case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 :
-                return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384";
-    #ifndef NO_RSA
-            case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 :
-                return "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384";
-    #endif /* !NO_RSA */
-            case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 :
-                return "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384";
-#ifndef NO_SHA
-    #ifndef NO_RSA
-            case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA :
-                return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA";
-            case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA :
-                return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA";
-    #endif /* !NO_RSA */
-            case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA :
-                return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA";
-            case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA :
-                return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA";
-    #ifndef NO_RC4
-        #ifndef NO_RSA
-            case TLS_ECDHE_RSA_WITH_RC4_128_SHA :
-                return "TLS_ECDHE_RSA_WITH_RC4_128_SHA";
-        #endif /* !NO_RSA */
-            case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA :
-                return "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA";
-    #endif /* !NO_RC4 */
-    #ifndef NO_DES3
-        #ifndef NO_RSA
-            case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA :
-                return "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA";
-        #endif /* !NO_RSA */
-            case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA :
-                return "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA";
-    #endif /* !NO_DES3 */
-
-    #ifndef NO_RSA
-            case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA :
-                return "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA";
-            case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA :
-                return "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA";
-    #endif /* !NO_RSA */
-            case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA :
-                return "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA";
-            case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA :
-                return "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA";
-    #ifndef NO_RC4
-        #ifndef NO_RSA
-            case TLS_ECDH_RSA_WITH_RC4_128_SHA :
-                return "TLS_ECDH_RSA_WITH_RC4_128_SHA";
-        #endif /* !NO_RSA */
-            case TLS_ECDH_ECDSA_WITH_RC4_128_SHA :
-                return "TLS_ECDH_ECDSA_WITH_RC4_128_SHA";
-    #endif /* !NO_RC4 */
-    #ifndef NO_DES3
-        #ifndef NO_RSA
-            case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA :
-                return "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA";
-        #endif /* !NO_RSA */
-            case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA :
-                return "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA";
-    #endif /* !NO_DES3 */
-#endif /* HAVE_ECC */
-
-#ifdef HAVE_AESGCM
-    #ifndef NO_RSA
-            case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 :
-                return "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256";
-            case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 :
-                return "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384";
-    #endif /* !NO_RSA */
-            case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 :
-                return "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256";
-            case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 :
-                return "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384";
-    #ifndef NO_RSA
-            case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 :
-                return "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256";
-            case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 :
-                return "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384";
-    #endif /* !NO_RSA */
-            case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 :
-                return "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256";
-            case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 :
-                return "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384";
-#endif /* HAVE_AESGCM */
-
-            case TLS_ECDHE_ECDSA_WITH_NULL_SHA :
-                return "TLS_ECDHE_ECDSA_WITH_NULL_SHA";
-    #ifndef NO_PSK
-            case TLS_ECDHE_PSK_WITH_NULL_SHA256 :
-                return "TLS_ECDHE_PSK_WITH_NULL_SHA256";
-            case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 :
-                return "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256";
-    #endif /* !NO_PSK */
-    #ifndef NO_RSA
-            case TLS_RSA_WITH_AES_128_CCM_8 :
-                return "TLS_RSA_WITH_AES_128_CCM_8";
-            case TLS_RSA_WITH_AES_256_CCM_8 :
-                return "TLS_RSA_WITH_AES_256_CCM_8";
-    #endif /* !NO_RSA */
-    #ifndef NO_PSK
-            case TLS_PSK_WITH_AES_128_CCM_8 :
-                return "TLS_PSK_WITH_AES_128_CCM_8";
-            case TLS_PSK_WITH_AES_256_CCM_8 :
-                return "TLS_PSK_WITH_AES_256_CCM_8";
-            case TLS_PSK_WITH_AES_128_CCM :
-                return "TLS_PSK_WITH_AES_128_CCM";
-            case TLS_PSK_WITH_AES_256_CCM :
-                return "TLS_PSK_WITH_AES_256_CCM";
-            case TLS_DHE_PSK_WITH_AES_128_CCM :
-                return "TLS_DHE_PSK_WITH_AES_128_CCM";
-            case TLS_DHE_PSK_WITH_AES_256_CCM :
-                return "TLS_DHE_PSK_WITH_AES_256_CCM";
-    #endif /* !NO_PSK */
-    #ifdef HAVE_ECC
-            case TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
-                return "TLS_ECDHE_ECDSA_WITH_AES_128_CCM";
-            case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
-                return "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8";
-            case TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 :
-                return "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8";
-    #endif /* HAVE_ECC */
-#endif /* HAVE_AESGCM */
-
-            default:
-                return "NONE";
-        } /* switch */
-    } /* ECC and AES CCM/GCM */
-#endif  /* HAVE_ECC || HAVE_AESCCM*/
-
-    if (cipherSuite0 == TLS13_BYTE) {
-        /* TLS v1.3 suites */
-        switch (cipherSuite) {
-#ifdef WOLFSSL_TLS13
-    #ifdef HAVE_AESGCM
-            case TLS_AES_128_GCM_SHA256 :
-                return "TLS_AES_128_GCM_SHA256";
-            case TLS_AES_256_GCM_SHA384 :
-                return "TLS_AES_256_GCM_SHA384";
-    #endif
-
-    #ifdef HAVE_CHACHA
-            case TLS_CHACHA20_POLY1305_SHA256 :
-                return "TLS_CHACHA20_POLY1305_SHA256";
-    #endif
-
-    #ifdef HAVE_AESCCM
-            case TLS_AES_128_CCM_SHA256 :
-                return "TLS_AES_128_CCM_SHA256";
-            case TLS_AES_128_CCM_8_SHA256 :
-                return "TLS_AES_256_CCM_8_SHA256";
-    #endif
-#endif
-
-            default:
-                return "NONE";
-        }
-    }
-
-    if (cipherSuite0 != ECC_BYTE &&
-        cipherSuite0 != CHACHA_BYTE &&
-        cipherSuite0 != TLS13_BYTE) {
-
-        /* normal suites */
-        switch (cipherSuite) {
-#ifndef NO_RSA
-    #ifndef NO_RC4
-        #ifndef NO_SHA
-            case SSL_RSA_WITH_RC4_128_SHA :
-                return "SSL_RSA_WITH_RC4_128_SHA";
-        #endif /* !NO_SHA */
-        #ifndef NO_MD5
-            case SSL_RSA_WITH_RC4_128_MD5 :
-                return "SSL_RSA_WITH_RC4_128_MD5";
-        #endif /* !NO_MD5 */
-    #endif /* !NO_RC4 */
-    #ifndef NO_SHA
-        #ifndef NO_DES3
-            case SSL_RSA_WITH_3DES_EDE_CBC_SHA :
-                return "SSL_RSA_WITH_3DES_EDE_CBC_SHA";
-        #endif /* !NO_DES3 */
-        #ifdef HAVE_IDEA
-            case SSL_RSA_WITH_IDEA_CBC_SHA :
-                return "SSL_RSA_WITH_IDEA_CBC_SHA";
-        #endif /* HAVE_IDEA */
-
-            case TLS_RSA_WITH_AES_128_CBC_SHA :
-                return "TLS_RSA_WITH_AES_128_CBC_SHA";
-            case TLS_RSA_WITH_AES_256_CBC_SHA :
-                return "TLS_RSA_WITH_AES_256_CBC_SHA";
-    #endif /* !NO_SHA */
-            case TLS_RSA_WITH_AES_128_CBC_SHA256 :
-                return "TLS_RSA_WITH_AES_128_CBC_SHA256";
-            case TLS_RSA_WITH_AES_256_CBC_SHA256 :
-                return "TLS_RSA_WITH_AES_256_CBC_SHA256";
-    #ifdef HAVE_BLAKE2
-            case TLS_RSA_WITH_AES_128_CBC_B2B256:
-                return "TLS_RSA_WITH_AES_128_CBC_B2B256";
-            case TLS_RSA_WITH_AES_256_CBC_B2B256:
-                return "TLS_RSA_WITH_AES_256_CBC_B2B256";
-    #endif /* HAVE_BLAKE2 */
-    #ifndef NO_SHA
-            case TLS_RSA_WITH_NULL_SHA :
-                return "TLS_RSA_WITH_NULL_SHA";
-    #endif /* !NO_SHA */
-            case TLS_RSA_WITH_NULL_SHA256 :
-                return "TLS_RSA_WITH_NULL_SHA256";
-#endif /* NO_RSA */
-
-#ifndef NO_PSK
-    #ifndef NO_SHA
-            case TLS_PSK_WITH_AES_128_CBC_SHA :
-                return "TLS_PSK_WITH_AES_128_CBC_SHA";
-            case TLS_PSK_WITH_AES_256_CBC_SHA :
-                return "TLS_PSK_WITH_AES_256_CBC_SHA";
-    #endif /* !NO_SHA */
-    #ifndef NO_SHA256
-            case TLS_PSK_WITH_AES_128_CBC_SHA256 :
-                return "TLS_PSK_WITH_AES_128_CBC_SHA256";
-            case TLS_PSK_WITH_NULL_SHA256 :
-                return "TLS_PSK_WITH_NULL_SHA256";
-            case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 :
-                return "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256";
-            case TLS_DHE_PSK_WITH_NULL_SHA256 :
-                return "TLS_DHE_PSK_WITH_NULL_SHA256";
-        #ifdef HAVE_AESGCM
-            case TLS_PSK_WITH_AES_128_GCM_SHA256 :
-                return "TLS_PSK_WITH_AES_128_GCM_SHA256";
-            case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 :
-                return "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256";
-        #endif /* HAVE_AESGCM */
-    #endif /* !NO_SHA256 */
-    #ifdef WOLFSSL_SHA384
-            case TLS_PSK_WITH_AES_256_CBC_SHA384 :
-                return "TLS_PSK_WITH_AES_256_CBC_SHA384";
-            case TLS_PSK_WITH_NULL_SHA384 :
-                return "TLS_PSK_WITH_NULL_SHA384";
-            case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 :
-                return "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384";
-            case TLS_DHE_PSK_WITH_NULL_SHA384 :
-                return "TLS_DHE_PSK_WITH_NULL_SHA384";
-        #ifdef HAVE_AESGCM
-            case TLS_PSK_WITH_AES_256_GCM_SHA384 :
-                return "TLS_PSK_WITH_AES_256_GCM_SHA384";
-            case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 :
-                return "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384";
-        #endif /* HAVE_AESGCM */
-    #endif /* WOLFSSL_SHA384 */
-    #ifndef NO_SHA
-            case TLS_PSK_WITH_NULL_SHA :
-                return "TLS_PSK_WITH_NULL_SHA";
-    #endif /* !NO_SHA */
-    #endif /* NO_PSK */
-
-    #ifndef NO_RSA
-            case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 :
-                return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256";
-            case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 :
-                return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256";
-    #ifndef NO_SHA
-            case TLS_DHE_RSA_WITH_AES_128_CBC_SHA :
-                return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA";
-            case TLS_DHE_RSA_WITH_AES_256_CBC_SHA :
-                return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA";
-        #ifndef NO_DES3
-            case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
-                return "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA";
-         #endif
-    #endif /* !NO_RSA */
-    #ifndef NO_HC128
-        #ifndef NO_MD5
-            case TLS_RSA_WITH_HC_128_MD5 :
-                return "TLS_RSA_WITH_HC_128_MD5";
-        #endif /* !NO_MD5 */
-        #ifndef NO_SHA
-            case TLS_RSA_WITH_HC_128_SHA :
-                return "TLS_RSA_WITH_HC_128_SHA";
-        #endif /* !NO_SHA */
-        #ifdef HAVE_BLAKE2
-            case TLS_RSA_WITH_HC_128_B2B256:
-                return "TLS_RSA_WITH_HC_128_B2B256";
-        #endif /* HAVE_BLAKE2 */
-    #endif /* !NO_HC128 */
-    #ifndef NO_SHA
-        #ifndef NO_RABBIT
-            case TLS_RSA_WITH_RABBIT_SHA :
-                return "TLS_RSA_WITH_RABBIT_SHA";
-        #endif /* !NO_RABBIT */
-        #ifdef HAVE_NTRU
-            #ifndef NO_RC4
-            case TLS_NTRU_RSA_WITH_RC4_128_SHA :
-                return "TLS_NTRU_RSA_WITH_RC4_128_SHA";
-            #endif /* !NO_RC4 */
-            #ifndef NO_DES3
-            case TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA :
-                return "TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA";
-            #endif /* !NO_DES3 */
-            case TLS_NTRU_RSA_WITH_AES_128_CBC_SHA :
-                return "TLS_NTRU_RSA_WITH_AES_128_CBC_SHA";
-            case TLS_NTRU_RSA_WITH_AES_256_CBC_SHA :
-                return "TLS_NTRU_RSA_WITH_AES_256_CBC_SHA";
-        #endif /* HAVE_NTRU */
-
-        #ifdef HAVE_QSH
-            case TLS_QSH :
-                return "TLS_QSH";
-        #endif /* HAVE_QSH */
-    #endif /* !NO_SHA */
-
-            case TLS_RSA_WITH_AES_128_GCM_SHA256 :
-                return "TLS_RSA_WITH_AES_128_GCM_SHA256";
-            case TLS_RSA_WITH_AES_256_GCM_SHA384 :
-                return "TLS_RSA_WITH_AES_256_GCM_SHA384";
-            case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 :
-                return "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256";
-            case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 :
-                return "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384";
-    #ifndef NO_SHA
-            case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA :
-                return "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA";
-            case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA :
-                return "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA";
-    #endif /* !NO_SHA */
-            case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 :
-                return "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256";
-            case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 :
-                return "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256";
-    #ifndef NO_SHA
-            case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA :
-                return "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA";
-            case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA :
-                return "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA";
-    #endif /* !NO_SHA */
-            case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 :
-                return "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256";
-            case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 :
-                return "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256";
-#endif /* !NO_PSK */
-
-#ifdef BUILD_TLS_DH_anon_WITH_AES_128_CBC_SHA
-            case TLS_DH_anon_WITH_AES_128_CBC_SHA :
-                return "TLS_DH_anon_WITH_AES_128_CBC_SHA";
-#endif
-#ifdef BUILD_WDM_WITH_NULL_SHA256
-            case WDM_WITH_NULL_SHA256 :
-                return "WDM_WITH_NULL_SHA256";
-#endif
-            default:
-                return "NONE";
-        } /* switch */
-    } /* normal / PSK */
-#endif /* NO_ERROR_STRINGS */
-
-    return "NONE";
+    if (ssl == NULL) {
+        return NULL;
+    }
+
+    return GetCipherNameIana(ssl->options.cipherSuite0, ssl->options.cipherSuite);
 }
 
+int GetCipherSuiteFromName(const char* name, byte* cipherSuite0,
+                           byte* cipherSuite)
+{
+    int           ret = BAD_FUNC_ARG;
+    int           i;
+    unsigned long len = (unsigned long)XSTRLEN(name);
+
+    for (i = 0; i < GetCipherNamesSize(); i++) {
+        if (XSTRNCMP(name, cipher_names[i].name, len) == 0) {
+            *cipherSuite0 = cipher_names[i].cipherSuite0;
+            *cipherSuite  = cipher_names[i].cipherSuite;
+            ret = 0;
+            break;
+        }
+}
+
+    return ret;
+}
 
 /**
@@ -15974,5 +16440,5 @@
     if (next[0] == 0 || XSTRNCMP(next, "ALL", 3) == 0 ||
                         XSTRNCMP(next, "DEFAULT", 7) == 0)
-        return 1; /* wolfSSL defualt */
+        return 1; /* wolfSSL default */
 
     do {
@@ -15990,5 +16456,5 @@
 
         for (i = 0; i < suiteSz; i++) {
-            if (XSTRNCMP(name, cipher_names[i], sizeof(name)) == 0) {
+            if (XSTRNCMP(name, cipher_names[i].name, sizeof(name)) == 0) {
             #ifdef WOLFSSL_DTLS
                 /* don't allow stream ciphers with DTLS */
@@ -16010,24 +16476,53 @@
                 }
 
-                suites->suites[idx++] = (XSTRSTR(name, "TLS13"))  ? TLS13_BYTE
-                                      : (XSTRSTR(name, "CHACHA")) ? CHACHA_BYTE
-                                      : (XSTRSTR(name, "QSH"))    ? QSH_BYTE
-                                      : (XSTRSTR(name, "EC"))     ? ECC_BYTE
-                                      : (XSTRSTR(name, "CCM"))    ? ECC_BYTE
-                                      : 0x00; /* normal */
-                suites->suites[idx++] = (byte)cipher_name_idx[i];
-
+                suites->suites[idx++] =
+            #ifdef WOLFSSL_TLS13
+                    (XSTRSTR(name, "TLS13"))  ? TLS13_BYTE :
+            #endif
+            #ifdef HAVE_CHACHA
+                    (XSTRSTR(name, "CHACHA")) ? CHACHA_BYTE :
+            #endif
+            #ifdef HAVE_QSH
+                    (XSTRSTR(name, "QSH"))    ? QSH_BYTE :
+            #endif
+            #if defined(HAVE_ECC) || defined(HAVE_CURVE25519)
+                    (XSTRSTR(name, "EC"))     ? ECC_BYTE :
+            #endif
+            #ifdef HAVE_AESCCM
+                    (XSTRSTR(name, "CCM"))    ? ECC_BYTE :
+            #endif
+                    CIPHER_BYTE; /* normal */
+
+                suites->suites[idx++] = cipher_names[i].cipherSuite;
                 /* The suites are either ECDSA, RSA, PSK, or Anon. The RSA
                  * suites don't necessarily have RSA in the name. */
+            #ifdef WOLFSSL_TLS13
                 if (XSTRSTR(name, "TLS13")) {
+                #ifndef NO_RSA
                     haveRSAsig = 1;
+                #endif
+                #if defined(HAVE_ECC) || defined(HAVE_ED25519)
                     haveECDSAsig = 1;
+                #endif
                 }
-                else if ((haveECDSAsig == 0) && XSTRSTR(name, "ECDSA"))
+                else
+            #endif
+            #if defined(HAVE_ECC) || defined(HAVE_ED25519)
+                if ((haveECDSAsig == 0) && XSTRSTR(name, "ECDSA"))
                     haveECDSAsig = 1;
-                else if (XSTRSTR(name, "ADH"))
+                else
+            #endif
+            #ifdef HAVE_ANON
+                if (XSTRSTR(name, "ADH"))
                     haveAnon = 1;
-                else if ((haveRSAsig == 0) && (XSTRSTR(name, "PSK") == NULL))
+                else
+            #endif
+                if (haveRSAsig == 0
+                    #ifndef NO_PSK
+                        && (XSTRSTR(name, "PSK") == NULL)
+                    #endif
+                   ) {
                     haveRSAsig = 1;
+                }
 
                 ret = 1; /* found at least one */
@@ -16054,4 +16549,5 @@
 }
 
+
 #if !defined(NO_WOLFSSL_SERVER) || !defined(NO_CERTS)
 void PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo,
@@ -16069,4 +16565,5 @@
     #endif
     }
+#ifndef WOLFSSL_NO_TLS12
     else if (IsAtLeastTLSv1_2(ssl)) {
     #ifdef WOLFSSL_ALLOW_TLS_SHA1
@@ -16079,4 +16576,5 @@
         ssl->suites->hashAlgo = sha_mac;
     }
+#endif
 
     /* i+1 since peek a byte ahead for type */
@@ -16085,5 +16583,5 @@
 
         DecodeSigAlg(&hashSigAlgo[i], &hashAlgo, &sigAlgo);
-    #ifdef HAVE_ECC
+    #ifdef HAVE_ED25519
         if (ssl->pkCurveOID == ECC_ED25519_OID && sigAlgo != ed25519_sa_algo)
             continue;
@@ -16096,31 +16594,79 @@
         }
     #endif
+    /* For ECDSA the `USE_ECDSA_KEYSZ_HASH_ALGO` build option will choose a hash
+     * algorithm that matches the ephemeral ECDHE key size or the next higest
+     * available. This workaround resolves issue with some peer's that do not
+     * properly support scenarios such as a P-256 key hashed with SHA512.
+     */
+    #if defined(HAVE_ECC) && defined(USE_ECDSA_KEYSZ_HASH_ALGO)
+        if (sigAlgo == ssl->suites->sigAlgo && sigAlgo == ecc_dsa_sa_algo) {
+            word32 digestSz = 0;
+            switch (hashAlgo) {
+            #ifndef NO_SHA
+                case sha_mac:
+                    digestSz = WC_SHA_DIGEST_SIZE;
+                break;
+            #endif
+            #ifndef NO_SHA256
+                case sha256_mac:
+                    digestSz = WC_SHA256_DIGEST_SIZE;
+                break;
+            #endif
+            #ifdef WOLFSSL_SHA384
+                case sha384_mac:
+                    digestSz = WC_SHA384_DIGEST_SIZE;
+                    break;
+            #endif
+            #ifdef WOLFSSL_SHA512
+                case sha512_mac:
+                    digestSz = WC_SHA512_DIGEST_SIZE;
+                break;
+            #endif
+                default:
+                    continue;
+            }
+
+            /* For ecc_dsa_sa_algo, pick hash algo that is curve size unless
+                algorithm in not compiled in, then choose next highest */
+            if (digestSz == ssl->eccTempKeySz) {
+                ssl->suites->hashAlgo = hashAlgo;
+                ssl->suites->sigAlgo = sigAlgo;
+                return; /* done selected sig/hash algorithms */
+            }
+            /* not strong enough, so keep checking hashSigAlso list */
+            if (digestSz < ssl->eccTempKeySz)
+                continue;
+
+            /* mark as highest and check remainder of hashSigAlgo list */
+            ssl->suites->hashAlgo = hashAlgo;
+            ssl->suites->sigAlgo = sigAlgo;
+            }
+        else
+    #endif
         if (sigAlgo == ssl->suites->sigAlgo || (sigAlgo == rsa_pss_sa_algo &&
                                          ssl->suites->sigAlgo == rsa_sa_algo)) {
-            if (hashAlgo == sha_mac) {
+            /* pick highest available between both server and client */
+            switch (hashAlgo) {
+                case sha_mac:
+            #ifndef NO_SHA256
+                case sha256_mac:
+            #endif
+            #ifdef WOLFSSL_SHA384
+                case sha384_mac:
+            #endif
+            #ifdef WOLFSSL_SHA512
+                case sha512_mac:
+            #endif
+                    /* not strong enough, so keep checking hashSigAlso list */
+                    if (hashAlgo < ssl->suites->hashAlgo)
+                        continue;
+                    /* mark as highest and check remainder of hashSigAlgo list */
+                    ssl->suites->hashAlgo = hashAlgo;
                 ssl->suites->sigAlgo = sigAlgo;
                 break;
-            }
-            #ifndef NO_SHA256
-            else if (hashAlgo == sha256_mac) {
-                ssl->suites->hashAlgo = sha256_mac;
-                ssl->suites->sigAlgo = sigAlgo;
-                break;
-            }
-            #endif
-            #ifdef WOLFSSL_SHA384
-            else if (hashAlgo == sha384_mac) {
-                ssl->suites->hashAlgo = sha384_mac;
-                ssl->suites->sigAlgo = sigAlgo;
-                break;
-            }
-            #endif
-            #ifdef WOLFSSL_SHA512
-            else if (hashAlgo == sha512_mac) {
-                ssl->suites->hashAlgo = sha512_mac;
-                ssl->suites->sigAlgo = sigAlgo;
-                break;
-            }
-            #endif
+                default:
+                    continue;
+            }
+            break;
         }
         else if (ssl->specs.sig_algo == 0) {
@@ -16128,11 +16674,10 @@
         }
     }
-
 }
 #endif /* !defined(NO_WOLFSSL_SERVER) || !defined(NO_CERTS) */
 
-#ifdef WOLFSSL_CALLBACKS
-
-    /* Initialisze HandShakeInfo */
+#if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
+
+    /* Initialize HandShakeInfo */
     void InitHandShakeInfo(HandShakeInfo* info, WOLFSSL* ssl)
     {
@@ -16151,11 +16696,13 @@
     {
         int i;
-        int sz = sizeof(cipher_name_idx)/sizeof(int);
+        int sz = GetCipherNamesSize();
 
         for (i = 0; i < sz; i++)
-            if (info->ssl->options.cipherSuite == (byte)cipher_name_idx[i]) {
+            if (info->ssl->options.cipherSuite ==
+                                            (byte)cipher_names[i].cipherSuite) {
                 if (info->ssl->options.cipherSuite0 == ECC_BYTE)
                     continue;   /* ECC suites at end */
-                XSTRNCPY(info->cipherName, cipher_names[i], MAX_CIPHERNAME_SZ);
+                XSTRNCPY(info->cipherName, cipher_names[i].name, MAX_CIPHERNAME_SZ);
+                info->cipherName[MAX_CIPHERNAME_SZ] = '\0';
                 break;
             }
@@ -16168,14 +16715,22 @@
 
     /* Add name to info packet names, increase packet name count */
-    void AddPacketName(const char* name, HandShakeInfo* info)
+    void AddPacketName(WOLFSSL* ssl, const char* name)
     {
+    #ifdef WOLFSSL_CALLBACKS
+        HandShakeInfo* info = &ssl->handShakeInfo;
         if (info->numberPackets < MAX_PACKETS_HANDSHAKE) {
-            XSTRNCPY(info->packetNames[info->numberPackets++], name,
-                    MAX_PACKETNAME_SZ);
-        }
-    }
-
-
-    /* Initialisze TimeoutInfo */
+            char* packetName = info->packetNames[info->numberPackets];
+            XSTRNCPY(packetName, name, MAX_PACKETNAME_SZ);
+            packetName[MAX_PACKETNAME_SZ] = '\0';
+            info->numberPackets++;
+        }
+    #endif
+        (void)ssl;
+        (void)name;
+    }
+
+
+    #ifdef WOLFSSL_CALLBACKS
+    /* Initialize TimeoutInfo */
     void InitTimeoutInfo(TimeoutInfo* info)
     {
@@ -16211,16 +16766,59 @@
     }
 
-
-    /* Add PacketInfo to TimeoutInfo */
-    void AddPacketInfo(const char* name, TimeoutInfo* info, const byte* data,
-                       int sz, void* heap)
+    /* Add packet name to previsouly added packet info */
+    void AddLateName(const char* name, TimeoutInfo* info)
     {
+        /* make sure we have a valid previous one */
+        if (info->numberPackets > 0 && info->numberPackets <
+                                                        MAX_PACKETS_HANDSHAKE) {
+            char* packetName = info->packets[info->numberPackets-1].packetName;
+            XSTRNCPY(packetName, name, MAX_PACKETNAME_SZ);
+            packetName[MAX_PACKETNAME_SZ] = '\0';
+        }
+    }
+
+    /* Add record header to previsouly added packet info */
+    void AddLateRecordHeader(const RecordLayerHeader* rl, TimeoutInfo* info)
+    {
+        /* make sure we have a valid previous one */
+        if (info->numberPackets > 0 && info->numberPackets <
+                                                        MAX_PACKETS_HANDSHAKE) {
+            if (info->packets[info->numberPackets - 1].bufferValue)
+                XMEMCPY(info->packets[info->numberPackets - 1].bufferValue, rl,
+                       RECORD_HEADER_SZ);
+            else
+                XMEMCPY(info->packets[info->numberPackets - 1].value, rl,
+                       RECORD_HEADER_SZ);
+        }
+    }
+
+    #endif /* WOLFSSL_CALLBACKS */
+
+
+    /* Add PacketInfo to TimeoutInfo
+     *
+     * ssl   WOLFSSL structure sending or receiving packet
+     * name  name of packet being sent
+     * type  type of packet being sent
+     * data  data bing sent with packet
+     * sz    size of data buffer
+     * written 1 if this packet is being written to wire, 0 if being read
+     * heap  custom heap to use for mallocs/frees
+     */
+    void AddPacketInfo(WOLFSSL* ssl, const char* name, int type,
+            const byte* data, int sz, int written, void* heap)
+    {
+    #ifdef WOLFSSL_CALLBACKS
+        TimeoutInfo* info = &ssl->timeoutInfo;
+
         if (info->numberPackets < (MAX_PACKETS_HANDSHAKE - 1)) {
             Timeval currTime;
 
             /* may add name after */
-            if (name)
-                XSTRNCPY(info->packets[info->numberPackets].packetName, name,
-                        MAX_PACKETNAME_SZ);
+            if (name) {
+                char* packetName = info->packets[info->numberPackets].packetName;
+                XSTRNCPY(packetName, name, MAX_PACKETNAME_SZ);
+                packetName[MAX_PACKETNAME_SZ] = '\0';
+            }
 
             /* add data, put in buffer if bigger than static buffer */
@@ -16245,40 +16843,188 @@
             info->numberPackets++;
         }
-    }
-
-
-    /* Add packet name to previsouly added packet info */
-    void AddLateName(const char* name, TimeoutInfo* info)
-    {
-        /* make sure we have a valid previous one */
-        if (info->numberPackets > 0 && info->numberPackets <
-                                                        MAX_PACKETS_HANDSHAKE) {
-            XSTRNCPY(info->packets[info->numberPackets - 1].packetName, name,
-                    MAX_PACKETNAME_SZ);
-        }
-    }
-
-    /* Add record header to previsouly added packet info */
-    void AddLateRecordHeader(const RecordLayerHeader* rl, TimeoutInfo* info)
-    {
-        /* make sure we have a valid previous one */
-        if (info->numberPackets > 0 && info->numberPackets <
-                                                        MAX_PACKETS_HANDSHAKE) {
-            if (info->packets[info->numberPackets - 1].bufferValue)
-                XMEMCPY(info->packets[info->numberPackets - 1].bufferValue, rl,
-                       RECORD_HEADER_SZ);
-            else
-                XMEMCPY(info->packets[info->numberPackets - 1].value, rl,
-                       RECORD_HEADER_SZ);
-        }
+    #endif /* WOLFSSL_CALLBACKS */
+    #ifdef OPENSSL_EXTRA
+        if (ssl->protoMsgCb != NULL && sz > RECORD_HEADER_SZ) {
+            /* version from hex to dec  16 is 16^1, 256 from 16^2 and
+               4096 from 16^3 */
+            int version = (ssl->version.minor & 0X0F) +
+                          (ssl->version.minor & 0xF0) * 16  +
+                          (ssl->version.major & 0X0F) * 256 +
+                          (ssl->version.major & 0xF0) * 4096;
+
+            ssl->protoMsgCb(written, version, type,
+                         (const void *)(data + RECORD_HEADER_SZ),
+                         (size_t)(sz - RECORD_HEADER_SZ),
+                         ssl, ssl->protoMsgCtx);
+        }
+    #endif /* OPENSSL_EXTRA */
+        (void)written;
+        (void)name;
+        (void)heap;
+        (void)type;
+        (void)ssl;
     }
 
 #endif /* WOLFSSL_CALLBACKS */
 
-
+#if !defined(NO_CERTS) && (defined(WOLFSSL_TLS13) || \
+                                                    !defined(NO_WOLFSSL_CLIENT))
+
+/* Decode the private key - RSA, ECC, or Ed25519 - and creates a key object.
+ * The signature type is set as well.
+ * The maximum length of a signature is returned.
+ *
+ * ssl     The SSL/TLS object.
+ * length  The length of a signature.
+ * returns 0 on success, otherwise failure.
+ */
+int DecodePrivateKey(WOLFSSL *ssl, word16* length)
+{
+    int      ret = BAD_FUNC_ARG;
+    int      keySz;
+    word32   idx;
+
+    /* make sure private key exists */
+    if (ssl->buffers.key == NULL || ssl->buffers.key->buffer == NULL) {
+        WOLFSSL_MSG("Private key missing!");
+        ERROR_OUT(NO_PRIVATE_KEY, exit_dpk);
+    }
+
+#ifndef NO_RSA
+    if (ssl->buffers.keyType == rsa_sa_algo || ssl->buffers.keyType == 0) {
+        ssl->hsType = DYNAMIC_TYPE_RSA;
+        ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey);
+        if (ret != 0) {
+            goto exit_dpk;
+        }
+
+        WOLFSSL_MSG("Trying RSA private key");
+
+        /* Set start of data to beginning of buffer. */
+        idx = 0;
+        /* Decode the key assuming it is an RSA private key. */
+        ret = wc_RsaPrivateKeyDecode(ssl->buffers.key->buffer, &idx,
+                    (RsaKey*)ssl->hsKey, ssl->buffers.key->length);
+        if (ret == 0) {
+            WOLFSSL_MSG("Using RSA private key");
+
+            /* It worked so check it meets minimum key size requirements. */
+            keySz = wc_RsaEncryptSize((RsaKey*)ssl->hsKey);
+            if (keySz < 0) { /* check if keySz has error case */
+                ERROR_OUT(keySz, exit_dpk);
+            }
+
+            if (keySz < ssl->options.minRsaKeySz) {
+                WOLFSSL_MSG("RSA key size too small");
+                ERROR_OUT(RSA_KEY_SIZE_E, exit_dpk);
+            }
+
+            /* Return the maximum signature length. */
+            *length = (word16)keySz;
+
+            goto exit_dpk;
+        }
+    }
+#endif /* !NO_RSA */
+
+#ifdef HAVE_ECC
+#ifndef NO_RSA
+    FreeKey(ssl, ssl->hsType, (void**)&ssl->hsKey);
+#endif /* !NO_RSA */
+
+    if (ssl->buffers.keyType == ecc_dsa_sa_algo || ssl->buffers.keyType == 0) {
+        ssl->hsType = DYNAMIC_TYPE_ECC;
+        ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey);
+        if (ret != 0) {
+            goto exit_dpk;
+            }
+
+    #ifndef NO_RSA
+        WOLFSSL_MSG("Trying ECC private key, RSA didn't work");
+    #else
+        WOLFSSL_MSG("Trying ECC private key");
+    #endif
+
+        /* Set start of data to beginning of buffer. */
+        idx = 0;
+        /* Decode the key assuming it is an ECC private key. */
+        ret = wc_EccPrivateKeyDecode(ssl->buffers.key->buffer, &idx,
+                                     (ecc_key*)ssl->hsKey,
+                                     ssl->buffers.key->length);
+        if (ret == 0) {
+            WOLFSSL_MSG("Using ECC private key");
+
+            /* Check it meets the minimum ECC key size requirements. */
+            keySz = wc_ecc_size((ecc_key*)ssl->hsKey);
+            if (keySz < ssl->options.minEccKeySz) {
+                WOLFSSL_MSG("ECC key size too small");
+                ERROR_OUT(ECC_KEY_SIZE_E, exit_dpk);
+            }
+
+            /* Return the maximum signature length. */
+            *length = (word16)wc_ecc_sig_size((ecc_key*)ssl->hsKey);
+
+            goto exit_dpk;
+            }
+        }
+#endif
+#ifdef HAVE_ED25519
+    #if !defined(NO_RSA) || defined(HAVE_ECC)
+        FreeKey(ssl, ssl->hsType, (void**)&ssl->hsKey);
+    #endif
+
+    if (ssl->buffers.keyType == ed25519_sa_algo || ssl->buffers.keyType == 0) {
+        ssl->hsType = DYNAMIC_TYPE_ED25519;
+        ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey);
+        if (ret != 0) {
+            goto exit_dpk;
+    }
+
+        #ifdef HAVE_ECC
+            WOLFSSL_MSG("Trying ED25519 private key, ECC didn't work");
+        #elif !defined(NO_RSA)
+            WOLFSSL_MSG("Trying ED25519 private key, RSA didn't work");
+        #else
+            WOLFSSL_MSG("Trying ED25519 private key");
+        #endif
+
+        /* Set start of data to beginning of buffer. */
+        idx = 0;
+        /* Decode the key assuming it is an ED25519 private key. */
+        ret = wc_Ed25519PrivateKeyDecode(ssl->buffers.key->buffer, &idx,
+                                         (ed25519_key*)ssl->hsKey,
+                                         ssl->buffers.key->length);
+        if (ret == 0) {
+            WOLFSSL_MSG("Using ED25519 private key");
+
+            /* Check it meets the minimum ECC key size requirements. */
+            if (ED25519_KEY_SIZE < ssl->options.minEccKeySz) {
+                WOLFSSL_MSG("ED25519 key size too small");
+                ERROR_OUT(ECC_KEY_SIZE_E, exit_dpk);
+    }
+
+            /* Return the maximum signature length. */
+            *length = ED25519_SIG_SIZE;
+
+            goto exit_dpk;
+        }
+    }
+#endif /* HAVE_ED25519 */
+
+    (void)idx;
+    (void)keySz;
+    (void)length;
+exit_dpk:
+    return ret;
+}
+
+#endif /* WOLFSSL_TLS13 || !NO_WOLFSSL_CLIENT */
 
 /* client only parts */
 #ifndef NO_WOLFSSL_CLIENT
 
+#ifndef WOLFSSL_NO_TLS12
+
+    /* handle generation of client_hello (1) */
     int SendClientHello(WOLFSSL* ssl)
     {
@@ -16292,5 +17038,4 @@
         word16             extSz = 0;
 
-
 #ifdef WOLFSSL_TLS13
         if (IsAtLeastTLSv1_3(ssl->version))
@@ -16298,4 +17043,7 @@
 #endif
 
+        WOLFSSL_START(WC_FUNC_CLIENT_HELLO_SEND);
+        WOLFSSL_ENTER("SendClientHello");
+
         if (ssl->suites == NULL) {
             WOLFSSL_MSG("Bad suites pointer in SendClientHello");
@@ -16312,5 +17060,8 @@
 
             ret = TLSX_UseSessionTicket(&ssl->extensions, ticket, ssl->heap);
-            if (ret != WOLFSSL_SUCCESS) return ret;
+            if (ret != WOLFSSL_SUCCESS) {
+                TLSX_SessionTicket_Free(ticket, ssl->heap);
+                return ret;
+            }
 
             idSz = 0;
@@ -16330,6 +17081,8 @@
             return MEMORY_E;
     #endif
-        extSz = TLSX_GetRequestSize(ssl, client_hello);
-        if (extSz != 0)
+        extSz = 0;
+        ret = TLSX_GetRequestSize(ssl, client_hello, &extSz);
+        if (ret != 0)
+            return ret;
             length += extSz;
 #else
@@ -16427,5 +17180,9 @@
 
 #ifdef HAVE_TLS_EXTENSIONS
-        idx += TLSX_WriteRequest(ssl, output + idx, client_hello);
+        extSz = 0;
+        ret = TLSX_WriteRequest(ssl, output + idx, client_hello, &extSz);
+        if (ret != 0)
+            return ret;
+        idx += extSz;
 
         (void)idx; /* suppress analyzer warning, keep idx current */
@@ -16481,4 +17238,8 @@
         } else {
             #ifdef WOLFSSL_DTLS
+                if (IsDtlsNotSctpMode(ssl)) {
+                    if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0)
+                        return ret;
+                }
                 if (ssl->options.dtls)
                     DtlsSEQIncrement(ssl, CUR_ORDER);
@@ -16489,26 +17250,30 @@
         }
 
-        #ifdef WOLFSSL_DTLS
-            if (IsDtlsNotSctpMode(ssl)) {
-                if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0)
-                    return ret;
-            }
-        #endif
-
         ssl->options.clientState = CLIENT_HELLO_COMPLETE;
-
-#ifdef WOLFSSL_CALLBACKS
-        if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo);
+#ifdef OPENSSL_EXTRA
+        ssl->cbmode = SSL_CB_MODE_WRITE;
+		if (ssl->CBIS != NULL)
+			ssl->CBIS(ssl, SSL_CB_CONNECT_LOOP, SSL_SUCCESS);
+#endif
+
+#if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
+        if (ssl->hsInfoOn) AddPacketName(ssl, "ClientHello");
         if (ssl->toInfoOn)
-            AddPacketInfo("ClientHello", &ssl->timeoutInfo, output, sendSz,
-                          ssl->heap);
+            AddPacketInfo(ssl, "ClientHello", handshake, output, sendSz,
+                          WRITE_PROTO, ssl->heap);
 #endif
 
         ssl->buffers.outputBuffer.length += sendSz;
 
-        return SendBuffered(ssl);
-    }
-
-
+        ret = SendBuffered(ssl);
+
+        WOLFSSL_LEAVE("SendClientHello", ret);
+        WOLFSSL_END(WC_FUNC_CLIENT_HELLO_SEND);
+
+        return ret;
+    }
+
+
+    /* handle processing of DTLS hello_verify_request (3) */
     static int DoHelloVerifyRequest(WOLFSSL* ssl, const byte* input,
                                     word32* inOutIdx, word32 size)
@@ -16519,6 +17284,5 @@
 
 #ifdef WOLFSSL_CALLBACKS
-        if (ssl->hsInfoOn) AddPacketName("HelloVerifyRequest",
-                                         &ssl->handShakeInfo);
+        if (ssl->hsInfoOn) AddPacketName(ssl, "HelloVerifyRequest");
         if (ssl->toInfoOn) AddLateName("HelloVerifyRequest", &ssl->timeoutInfo);
 #endif
@@ -16560,5 +17324,5 @@
 
 
-    static INLINE int DSH_CheckSessionId(WOLFSSL* ssl)
+    static WC_INLINE int DSH_CheckSessionId(WOLFSSL* ssl)
     {
         int ret = 0;
@@ -16592,8 +17356,5 @@
     int CheckVersion(WOLFSSL *ssl, ProtocolVersion pv)
     {
-#ifdef WOLFSSL_TLS13
-        /* TODO: [TLS13] Remove this.
-         * Translate the draft TLS v1.3 version to final version.
-         */
+    #ifdef WOLFSSL_TLS13_DRAFT
         if (pv.major == TLS_DRAFT_MAJOR) {
             pv.major = SSLv3_MAJOR;
@@ -16602,5 +17363,10 @@
 #endif
 
-        /* Check for upgrade attack. */
+        #ifdef OPENSSL_EXTRA
+        if (ssl->CBIS != NULL) {
+            ssl->CBIS(ssl, SSL_CB_HANDSHAKE_START, SSL_SUCCESS);
+        }
+        #endif
+
         if (pv.minor > ssl->version.minor) {
             WOLFSSL_MSG("Server using higher version, fatal error");
@@ -16692,4 +17458,5 @@
     }
 
+    /* handle processing of server_hello (2) */
     int DoServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
                       word32 helloSz)
@@ -16703,6 +17470,9 @@
         int             ret;
 
+        WOLFSSL_START(WC_FUNC_SERVER_HELLO_DO);
+        WOLFSSL_ENTER("DoServerHello");
+
 #ifdef WOLFSSL_CALLBACKS
-        if (ssl->hsInfoOn) AddPacketName("ServerHello", &ssl->handShakeInfo);
+        if (ssl->hsInfoOn) AddPacketName(ssl, "ServerHello");
         if (ssl->toInfoOn) AddLateName("ServerHello", &ssl->timeoutInfo);
 #endif
@@ -16721,6 +17491,8 @@
 
 #ifdef WOLFSSL_TLS13
-        if (IsAtLeastTLSv1_3(pv))
-            return DoTls13ServerHello(ssl, input, inOutIdx, helloSz);
+        if (IsAtLeastTLSv1_3(pv)) {
+            byte type = server_hello;
+            return DoTls13ServerHello(ssl, input, inOutIdx, helloSz, &type);
+        }
 #endif
 
@@ -16728,31 +17500,4 @@
         XMEMCPY(ssl->arrays->serverRandom, input + i, RAN_LEN);
         i += RAN_LEN;
-
-#ifdef WOLFSSL_TLS13
-        if (IsAtLeastTLSv1_3(ssl->ctx->method->version)) {
-            /* TLS v1.3 capable client not allowed to downgrade when connecting
-             * to TLS v1.3 capable server.
-             */
-            if (XMEMCMP(input + i - (TLS13_DOWNGRADE_SZ + 1),
-                             tls13Downgrade, TLS13_DOWNGRADE_SZ) == 0 &&
-                             (*(input + i - 1) == 0 || *(input + i - 1) == 1)) {
-                SendAlert(ssl, alert_fatal, illegal_parameter);
-                return VERSION_ERROR;
-            }
-        }
-        else
-#endif
-        if (ssl->ctx->method->version.major == SSLv3_MAJOR &&
-                             ssl->ctx->method->version.minor == TLSv1_2_MINOR) {
-            /* TLS v1.2 capable client not allowed to downgrade when connecting
-             * to TLS v1.2 capable server.
-             */
-            if (XMEMCMP(input + i - (TLS13_DOWNGRADE_SZ + 1),
-                        tls13Downgrade, TLS13_DOWNGRADE_SZ) == 0 &&
-                                                        *(input + i - 1) == 0) {
-                SendAlert(ssl, alert_fatal, illegal_parameter);
-                return VERSION_ERROR;
-            }
-        }
 
         /* session id */
@@ -16823,6 +17568,6 @@
                     return BUFFER_ERROR;
 
-                if ((ret = TLSX_Parse(ssl, (byte *) input + i,
-                                                          totalExtSz, 0, NULL)))
+                if ((ret = TLSX_Parse(ssl, (byte *) input + i, totalExtSz,
+                                                           server_hello, NULL)))
                     return ret;
 
@@ -16912,5 +17657,47 @@
 #endif /* HAVE_SECRET_CALLBACK */
 
-        if (ssl->options.resuming) {
+        ret = CompleteServerHello(ssl);
+
+        WOLFSSL_LEAVE("DoServerHello", ret);
+        WOLFSSL_END(WC_FUNC_SERVER_HELLO_DO);
+
+        return ret;
+    }
+
+    int CompleteServerHello(WOLFSSL* ssl)
+    {
+        int ret;
+
+        if (!ssl->options.resuming) {
+            byte* down = ssl->arrays->serverRandom + RAN_LEN -
+                                                         TLS13_DOWNGRADE_SZ - 1;
+            byte  vers = ssl->arrays->serverRandom[RAN_LEN - 1];
+    #ifdef WOLFSSL_TLS13
+            if (IsAtLeastTLSv1_3(ssl->ctx->method->version)) {
+                /* TLS v1.3 capable client not allowed to downgrade when
+                 * connecting to TLS v1.3 capable server unless cipher suite
+                 * demands it.
+                 */
+                if (XMEMCMP(down, tls13Downgrade, TLS13_DOWNGRADE_SZ) == 0 &&
+                                                     (vers == 0 || vers == 1)) {
+                    SendAlert(ssl, alert_fatal, illegal_parameter);
+                    return VERSION_ERROR;
+                }
+            }
+            else
+    #endif
+            if (ssl->ctx->method->version.major == SSLv3_MAJOR &&
+                             ssl->ctx->method->version.minor == TLSv1_2_MINOR) {
+                /* TLS v1.2 capable client not allowed to downgrade when
+                 * connecting to TLS v1.2 capable server.
+                 */
+                if (XMEMCMP(down, tls13Downgrade, TLS13_DOWNGRADE_SZ) == 0 &&
+                                                                    vers == 0) {
+                    SendAlert(ssl, alert_fatal, illegal_parameter);
+                    return VERSION_ERROR;
+                }
+            }
+        }
+        else {
             if (DSH_CheckSessionId(ssl)) {
                 if (SetCipherSpecs(ssl) == 0) {
@@ -16952,4 +17739,6 @@
     }
 
+#endif /* WOLFSSL_NO_TLS12 */
+
 
     /* Make sure client setup is valid for this suite, true on success */
@@ -16977,7 +17766,8 @@
     }
 
+#ifndef WOLFSSL_NO_TLS12
 
 #ifndef NO_CERTS
-    /* just read in and ignore for now TODO: */
+    /* handle processing of certificate_request (13) */
     static int DoCertificateRequest(WOLFSSL* ssl, const byte* input, word32*
                                     inOutIdx, word32 size)
@@ -16986,7 +17776,10 @@
         word32 begin = *inOutIdx;
 
+        WOLFSSL_START(WC_FUNC_CERTIFICATE_REQUEST_DO);
+        WOLFSSL_ENTER("DoCertificateRequest");
+
         #ifdef WOLFSSL_CALLBACKS
             if (ssl->hsInfoOn)
-                AddPacketName("CertificateRequest", &ssl->handShakeInfo);
+                AddPacketName(ssl, "CertificateRequest");
             if (ssl->toInfoOn)
                 AddLateName("CertificateRequest", &ssl->timeoutInfo);
@@ -17052,13 +17845,30 @@
         /* don't send client cert or cert verify if user hasn't provided
            cert and private key */
-        if (ssl->buffers.certificate && ssl->buffers.certificate->buffer &&
-            ssl->buffers.key && ssl->buffers.key->buffer)
+        if (ssl->buffers.certificate && ssl->buffers.certificate->buffer) {
+        #ifdef HAVE_PK_CALLBACKS
+            if (wolfSSL_CTX_IsPrivatePkSet(ssl->ctx)) {
+                WOLFSSL_MSG("Using PK for client private key");
+                ssl->options.sendVerify = SEND_CERT;
+            }
+        #endif
+            if (ssl->buffers.key && ssl->buffers.key->buffer) {
             ssl->options.sendVerify = SEND_CERT;
+            }
+        }
+	#ifdef OPENSSL_EXTRA
+		else
+	#else
         else if (IsTLS(ssl))
+	#endif
+        {
             ssl->options.sendVerify = SEND_BLANK_CERT;
+        }
 
         if (IsEncryptionOn(ssl, 0))
             *inOutIdx += ssl->keys.padSz;
 
+        WOLFSSL_LEAVE("DoCertificateRequest", 0);
+        WOLFSSL_END(WC_FUNC_CERTIFICATE_REQUEST_DO);
+
         return 0;
     }
@@ -17066,5 +17876,5 @@
 
 
-#ifdef HAVE_ECC
+#if defined(HAVE_ECC) || defined(HAVE_CURVE25519)
 
     static int CheckCurveId(int tlsCurveId)
@@ -17143,10 +17953,10 @@
 typedef struct DskeArgs {
     byte*  output; /* not allocated */
-#if !defined(NO_DH) || defined(HAVE_ECC)
+#if !defined(NO_DH) || defined(HAVE_ECC) || defined(HAVE_ED25519)
     byte*  verifySig;
 #endif
     word32 idx;
     word32 begin;
-#if !defined(NO_DH) || defined(HAVE_ECC)
+#if !defined(NO_DH) || defined(HAVE_ECC) || defined(HAVE_ED25519)
     word16 verifySigSz;
 #endif
@@ -17163,5 +17973,5 @@
     (void)args;
 
-#if !defined(NO_DH) || defined(HAVE_ECC)
+#if !defined(NO_DH) || defined(HAVE_ECC) || defined(HAVE_ED25519)
     if (args->verifySig) {
         XFREE(args->verifySig, ssl->heap, DYNAMIC_TYPE_SIGNATURE);
@@ -17171,4 +17981,5 @@
 }
 
+/* handle processing of server_key_exchange (12) */
 static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input,
                                word32* inOutIdx, word32 size)
@@ -17183,4 +17994,8 @@
 #endif
 
+    (void)input;
+    (void)size;
+
+    WOLFSSL_START(WC_FUNC_SERVER_KEY_EXCHANGE_DO);
     WOLFSSL_ENTER("DoServerKeyExchange");
 
@@ -17214,5 +18029,5 @@
         #ifdef WOLFSSL_CALLBACKS
             if (ssl->hsInfoOn)
-                AddPacketName("ServerKeyExchange", &ssl->handShakeInfo);
+                AddPacketName(ssl, "ServerKeyExchange");
             if (ssl->toInfoOn)
                 AddLateName("ServerKeyExchange", &ssl->timeoutInfo);
@@ -17269,4 +18084,9 @@
                         ERROR_OUT(DH_KEY_SIZE_E, exit_dske);
                     }
+                    if (length > ssl->options.maxDhKeySz) {
+                        WOLFSSL_MSG("Server using a DH key that is too big");
+                        SendAlert(ssl, alert_fatal, handshake_failure);
+                        ERROR_OUT(DH_KEY_SIZE_E, exit_dske);
+                    }
 
                     ssl->buffers.serverDH_P.buffer =
@@ -17310,4 +18130,6 @@
                     args->idx += length;
 
+                    ssl->buffers.weOwnDH = 1;
+
                     /* pub */
                     if ((args->idx - args->begin) + OPAQUE16_LEN > size) {
@@ -17337,9 +18159,12 @@
                 }
             #endif /* !NO_DH */
-            #ifdef HAVE_ECC
+            #if defined(HAVE_ECC) || defined(HAVE_CURVE25519)
                 case ecc_diffie_hellman_kea:
                 {
                     byte b;
-                    int curveId, curveOid;
+                #ifdef HAVE_ECC
+                    int curveId;
+                #endif
+                    int curveOid;
                     word16 length;
 
@@ -17374,5 +18199,5 @@
                                 goto exit_dske;
                             }
-                        } else if (ssl->peerEccKeyPresent) {
+                        } else if (ssl->peerX25519KeyPresent) {
                             ret = ReuseKey(ssl, DYNAMIC_TYPE_CURVE25519,
                                            ssl->peerX25519Key);
@@ -17394,4 +18219,5 @@
                     }
              #endif
+                #ifdef HAVE_ECC
                     if (ssl->peerEccKey == NULL) {
                         ret = AllocKey(ssl, DYNAMIC_TYPE_ECC,
@@ -17417,6 +18243,7 @@
                     ssl->peerEccKeyPresent = 1;
                     break;
+                #endif
                 }
-            #endif /* HAVE_ECC */
+            #endif /* HAVE_ECC || HAVE_CURVE25519 */
             #if !defined(NO_DH) && !defined(NO_PSK)
                 case dhe_psk_kea:
@@ -17457,4 +18284,9 @@
                     if (length < ssl->options.minDhKeySz) {
                         WOLFSSL_MSG("Server using a DH key that is too small");
+                        SendAlert(ssl, alert_fatal, handshake_failure);
+                        ERROR_OUT(DH_KEY_SIZE_E, exit_dske);
+                    }
+                    if (length > ssl->options.maxDhKeySz) {
+                        WOLFSSL_MSG("Server using a DH key that is too big");
                         SendAlert(ssl, alert_fatal, handshake_failure);
                         ERROR_OUT(DH_KEY_SIZE_E, exit_dske);
@@ -17501,4 +18333,6 @@
                     args->idx += length;
 
+                    ssl->buffers.weOwnDH = 1;
+
                     /* pub */
                     if ((args->idx - args->begin) + OPAQUE16_LEN > size) {
@@ -17528,5 +18362,6 @@
                 }
             #endif /* !NO_DH || !NO_PSK */
-            #if defined(HAVE_ECC) && !defined(NO_PSK)
+            #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \
+                                                                !defined(NO_PSK)
                 case ecdhe_psk_kea:
                 {
@@ -17607,5 +18442,5 @@
 
                     if (ssl->peerEccKey == NULL) {
-                        AllocKey(ssl, DYNAMIC_TYPE_ECC,
+                        ret = AllocKey(ssl, DYNAMIC_TYPE_ECC,
                                  (void**)&ssl->peerEccKey);
                         if (ret != 0) {
@@ -17630,5 +18465,5 @@
                     break;
                 }
-            #endif /* HAVE_ECC || !NO_PSK */
+            #endif /* (HAVE_ECC || HAVE_CURVE25519) && !NO_PSK */
                 default:
                     ret = BAD_KEA_TYPE_E;
@@ -17660,5 +18495,5 @@
                 case ecc_diffie_hellman_kea:
                 {
-            #if defined(NO_DH) && !defined(HAVE_ECC)
+            #if defined(NO_DH) && !defined(HAVE_ECC) && !defined(HAVE_ED25519)
                     ERROR_OUT(NOT_COMPILED_IN, exit_dske);
             #else
@@ -17729,7 +18564,11 @@
 
                     if (args->sigAlgo != ed25519_sa_algo) {
+                        int digest_sz = wc_HashGetDigestSize(hashType);
+                        if (digest_sz <= 0) {
+                            ERROR_OUT(BUFFER_ERROR, exit_dske);
+                        }
+                        ssl->buffers.digest.length = (unsigned int)digest_sz;
+
                         /* buffer for hash */
-                        ssl->buffers.digest.length =
-                                                 wc_HashGetDigestSize(hashType);
                         ssl->buffers.digest.buffer = (byte*)XMALLOC(
                             ssl->buffers.digest.length, ssl->heap,
@@ -17773,5 +18612,5 @@
                         }
                     #endif /* HAVE_ECC */
-                    #ifdef HAVE_ED25519
+                    #if defined(HAVE_ED25519)
                         case ed25519_sa_algo:
                         {
@@ -17781,5 +18620,5 @@
                             break;
                         }
-                    #endif /* HAVE_ECC */
+                    #endif /* HAVE_ED25519 */
 
                     default:
@@ -17787,5 +18626,5 @@
                     } /* switch (args->sigAlgo) */
 
-            #endif /* NO_DH && !HAVE_ECC */
+            #endif /* NO_DH && !HAVE_ECC && !HAVE_ED25519 */
                     break;
                 }
@@ -17819,5 +18658,5 @@
                 case ecc_diffie_hellman_kea:
                 {
-            #if defined(NO_DH) && !defined(HAVE_ECC)
+            #if defined(NO_DH) && !defined(HAVE_ECC) && !defined(HAVE_ED25519)
                     ERROR_OUT(NOT_COMPILED_IN, exit_dske);
             #else
@@ -17850,9 +18689,7 @@
                                 ssl->peerRsaKey,
                             #ifdef HAVE_PK_CALLBACKS
-                                ssl->buffers.peerRsaKey.buffer,
-                                ssl->buffers.peerRsaKey.length,
-                                ssl->RsaVerifyCtx
+                                &ssl->buffers.peerRsaKey
                             #else
-                                NULL, 0, NULL
+                                NULL
                             #endif
                             );
@@ -17861,4 +18698,13 @@
                                 args->sigSz = (word16)ret;
                                 ret = 0;
+                            }
+                        #ifdef WOLFSSL_ASYNC_CRYPT
+                            if (ret != WC_PENDING_E)
+                        #endif
+                            {
+                                /* peerRsaKey */
+                                FreeKey(ssl, DYNAMIC_TYPE_RSA,
+                                                      (void**)&ssl->peerRsaKey);
+                                ssl->peerRsaKeyPresent = 0;
                             }
                             break;
@@ -17874,16 +18720,23 @@
                                 ssl->peerEccDsaKey,
                             #ifdef HAVE_PK_CALLBACKS
-                                ssl->buffers.peerEccDsaKey.buffer,
-                                ssl->buffers.peerEccDsaKey.length,
-                                ssl->EccVerifyCtx
+                                &ssl->buffers.peerEccDsaKey
                             #else
-                                NULL, 0, NULL
+                                NULL
                             #endif
                             );
 
+                        #ifdef WOLFSSL_ASYNC_CRYPT
+                            if (ret != WC_PENDING_E)
+                        #endif
+                            {
+                                /* peerEccDsaKey */
+                                FreeKey(ssl, DYNAMIC_TYPE_ECC,
+                                                   (void**)&ssl->peerEccDsaKey);
+                                ssl->peerEccDsaKeyPresent = 0;
+                            }
                             break;
                         }
                     #endif /* HAVE_ECC */
-                    #ifdef HAVE_ED25519
+                    #if defined(HAVE_ED25519)
                         case ed25519_sa_algo:
                         {
@@ -17894,20 +18747,27 @@
                                 ssl->peerEd25519Key,
                             #ifdef HAVE_PK_CALLBACKS
-                                ssl->buffers.peerEccDsaKey.buffer,
-                                ssl->buffers.peerEccDsaKey.length,
-                                ssl->Ed25519VerifyCtx
+                                &ssl->buffers.peerEd25519Key
                             #else
-                                NULL, 0, NULL
+                                NULL
                             #endif
                             );
 
+                        #ifdef WOLFSSL_ASYNC_CRYPT
+                            if (ret != WC_PENDING_E)
+                        #endif
+                            {
+                                /* peerEccDsaKey */
+                                FreeKey(ssl, DYNAMIC_TYPE_ED25519,
+                                                  (void**)&ssl->peerEd25519Key);
+                                ssl->peerEd25519KeyPresent = 0;
+                            }
                             break;
                         }
-                    #endif /* HAVE_ECC */
+                    #endif /* HAVE_ED25519 */
 
                     default:
                         ret = ALGO_ID_E;
                     } /* switch (sigAlgo) */
-            #endif /* NO_DH && !HAVE_ECC */
+            #endif /* NO_DH && !HAVE_ECC && !HAVE_ED25519 */
                     break;
                 }
@@ -17941,5 +18801,5 @@
                 case ecc_diffie_hellman_kea:
                 {
-            #if defined(NO_DH) && !defined(HAVE_ECC)
+            #if defined(NO_DH) && !defined(HAVE_ECC) && !defined(HAVE_ED25519)
                     ERROR_OUT(NOT_COMPILED_IN, exit_dske);
             #else
@@ -18014,13 +18874,13 @@
                             break;
                     #endif /* HAVE_ECC */
-                    #ifdef HAVE_ED25519
+                    #if defined(HAVE_ED25519)
                         case ed25519_sa_algo:
                             /* Nothing to do in this algo */
                             break;
-                    #endif /* HAVE_ECC */
+                    #endif /* HAVE_ED25519 */
                         default:
                             ret = ALGO_ID_E;
                     } /* switch (sigAlgo) */
-            #endif /* NO_DH && !HAVE_ECC */
+            #endif /* NO_DH && !HAVE_ECC && !HAVE_ED25519 */
                     break;
                 }
@@ -18091,9 +18951,10 @@
 
     WOLFSSL_LEAVE("DoServerKeyExchange", ret);
+    WOLFSSL_END(WC_FUNC_SERVER_KEY_EXCHANGE_DO);
 
 #ifdef WOLFSSL_ASYNC_CRYPT
     /* Handle async operation */
     if (ret == WC_PENDING_E) {
-        /* Mark message as not recevied so it can process again */
+        /* Mark message as not received so it can process again */
         ssl->msgsReceived.got_server_key_exchange = 0;
 
@@ -18518,4 +19379,5 @@
 }
 
+/* handle generation client_key_exchange (16) */
 int SendClientKeyExchange(WOLFSSL* ssl)
 {
@@ -18529,5 +19391,13 @@
 #endif
 
+    WOLFSSL_START(WC_FUNC_CLIENT_KEY_EXCHANGE_SEND);
     WOLFSSL_ENTER("SendClientKeyExchange");
+
+#ifdef OPENSSL_EXTRA
+	ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE;
+	ssl->cbmode = SSL_CB_MODE_WRITE;
+	if (ssl->CBIS != NULL)
+		ssl->CBIS(ssl, SSL_CB_CONNECT_LOOP, SSL_SUCCESS);
+#endif
 
 #ifdef WOLFSSL_ASYNC_CRYPT
@@ -18596,5 +19466,6 @@
                     break;
             #endif /* !NO_DH && !NO_PSK */
-            #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && !defined(NO_PSK)
+            #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \
+                                                                !defined(NO_PSK)
                 case ecdhe_psk_kea:
                     /* sanity check that PSK client callback has been set */
@@ -18643,5 +19514,5 @@
                 #endif
 
-                    /* create private key */
+                    /* create ephemeral private key */
                     ssl->hsType = DYNAMIC_TYPE_ECC;
                     ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey);
@@ -18702,7 +19573,6 @@
                 #ifdef HAVE_ECC
                     if (ssl->specs.static_ecdh) {
-                        /* TODO: EccDsa is really fixed Ecc change naming */
-                        if (!ssl->peerEccDsaKey ||
-                                !ssl->peerEccDsaKeyPresent ||
+                        /* Note: EccDsa is really fixed Ecc key here */
+                        if (!ssl->peerEccDsaKey || !ssl->peerEccDsaKeyPresent ||
                                     !ssl->peerEccDsaKey->dp) {
                             ERROR_OUT(NO_PEER_KEY, exit_scke);
@@ -18721,5 +19591,5 @@
                     }
 
-                    /* create private key */
+                    /* create ephemeral private key */
                     ssl->hsType = DYNAMIC_TYPE_ECC;
                     ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey);
@@ -18757,4 +19627,12 @@
                 ERROR_OUT(MEMORY_E, exit_scke);
             }
+            if (ssl->arrays->preMasterSecret == NULL) {
+                ssl->arrays->preMasterSecret = (byte*)XMALLOC(ENCRYPT_LEN,
+                                                ssl->heap, DYNAMIC_TYPE_SECRET);
+                if (ssl->arrays->preMasterSecret == NULL) {
+                    ERROR_OUT(MEMORY_E, exit_scke);
+                }
+                XMEMSET(ssl->arrays->preMasterSecret, 0, ENCRYPT_LEN);
+            }
 
             switch(ssl->specs.kea)
@@ -18763,6 +19641,8 @@
                 case rsa_kea:
                 {
+                    /* build PreMasterSecret with RNG data */
                     ret = wc_RNG_GenerateBlock(ssl->rng,
-                        ssl->arrays->preMasterSecret, SECRET_LEN);
+                        &ssl->arrays->preMasterSecret[VERSION_SZ],
+                        SECRET_LEN - VERSION_SZ);
                     if (ret != 0) {
                         goto exit_scke;
@@ -18791,4 +19671,23 @@
                     }
 
+                    #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \
+                        !defined(WOLFSSL_OLD_PRIME_CHECK)
+                    if (ssl->options.dhDoKeyTest &&
+                        !ssl->options.dhKeyTested)
+                    {
+                        ret = wc_DhSetCheckKey(ssl->buffers.serverDH_Key,
+                            ssl->buffers.serverDH_P.buffer,
+                            ssl->buffers.serverDH_P.length,
+                            ssl->buffers.serverDH_G.buffer,
+                            ssl->buffers.serverDH_G.length,
+                            NULL, 0, 0, ssl->rng);
+                        if (ret != 0) {
+                            goto exit_scke;
+                        }
+                        ssl->options.dhKeyTested = 1;
+                    }
+                    else
+                    #endif
+                    {
                     ret = wc_DhSetKey(ssl->buffers.serverDH_Key,
                         ssl->buffers.serverDH_P.buffer,
@@ -18798,4 +19697,5 @@
                     if (ret != 0) {
                         goto exit_scke;
+                    }
                     }
 
@@ -18886,4 +19786,23 @@
                     }
 
+                    #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \
+                        !defined(WOLFSSL_OLD_PRIME_CHECK)
+                    if (ssl->options.dhDoKeyTest &&
+                        !ssl->options.dhKeyTested)
+                    {
+                        ret = wc_DhSetCheckKey(ssl->buffers.serverDH_Key,
+                            ssl->buffers.serverDH_P.buffer,
+                            ssl->buffers.serverDH_P.length,
+                            ssl->buffers.serverDH_G.buffer,
+                            ssl->buffers.serverDH_G.length,
+                            NULL, 0, 0, ssl->rng);
+                        if (ret != 0) {
+                            goto exit_scke;
+                        }
+                        ssl->options.dhKeyTested = 1;
+                    }
+                    else
+                    #endif
+                    {
                     ret = wc_DhSetKey(ssl->buffers.serverDH_Key,
                         ssl->buffers.serverDH_P.buffer,
@@ -18894,4 +19813,5 @@
                         goto exit_scke;
                     }
+                    }
 
                     /* for DH, encSecret is Yc, agree is pre-master */
@@ -18902,5 +19822,6 @@
                 }
             #endif /* !NO_DH && !NO_PSK */
-            #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && !defined(NO_PSK)
+            #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \
+                                                                !defined(NO_PSK)
                 case ecdhe_psk_kea:
                 {
@@ -18972,5 +19893,5 @@
                     break;
                 }
-            #endif /* HAVE_ECC && !NO_PSK */
+            #endif /* (HAVE_ECC || HAVE_CURVE25519) && !NO_PSK */
             #ifdef HAVE_NTRU
                 case ntru_kea:
@@ -19012,5 +19933,5 @@
                     }
                 #endif
-                #ifdef HAVE_ECC
+                #if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT)
                 #ifdef HAVE_PK_CALLBACKS
                     /* if callback then use it for shared secret */
@@ -19057,9 +19978,7 @@
                         ssl->peerRsaKey,
                     #if defined(HAVE_PK_CALLBACKS)
-                        ssl->buffers.peerRsaKey.buffer,
-                        ssl->buffers.peerRsaKey.length,
-                        ssl->RsaEncCtx
+                        &ssl->buffers.peerRsaKey
                     #else
-                        NULL, 0, NULL
+                        NULL
                     #endif
                     );
@@ -19098,5 +20017,6 @@
                 }
             #endif /* !NO_DH && !NO_PSK */
-            #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && !defined(NO_PSK)
+            #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \
+                                                                !defined(NO_PSK)
                 case ecdhe_psk_kea:
                 {
@@ -19108,11 +20028,15 @@
                             ssl->arrays->preMasterSecret + OPAQUE16_LEN,
                             &ssl->arrays->preMasterSz,
-                            WOLFSSL_CLIENT_END,
-                        #ifdef HAVE_PK_CALLBACKS
-                            ssl->EccSharedSecretCtx
-                        #else
-                            NULL
+                            WOLFSSL_CLIENT_END
+                        );
+                        if (!ssl->specs.static_ecdh
+                        #ifdef WOLFSSL_ASYNC_CRYPT
+                            && ret != WC_PENDING_E
                         #endif
-                        );
+                        ) {
+                            FreeKey(ssl, DYNAMIC_TYPE_CURVE25519,
+                                                   (void**)&ssl->peerX25519Key);
+                            ssl->peerX25519KeyPresent = 0;
+                        }
                         break;
                     }
@@ -19123,11 +20047,14 @@
                         ssl->arrays->preMasterSecret + OPAQUE16_LEN,
                         &ssl->arrays->preMasterSz,
-                        WOLFSSL_CLIENT_END,
-                    #ifdef HAVE_PK_CALLBACKS
-                        ssl->EccSharedSecretCtx
-                    #else
-                        NULL
-                    #endif
+                        WOLFSSL_CLIENT_END
                     );
+                #ifdef WOLFSSL_ASYNC_CRYPT
+                    if (ret != WC_PENDING_E)
+                #endif
+                    {
+                        FreeKey(ssl, DYNAMIC_TYPE_ECC,
+                                                      (void**)&ssl->peerEccKey);
+                        ssl->peerEccKeyPresent = 0;
+                    }
                     break;
                 }
@@ -19173,11 +20100,15 @@
                             ssl->arrays->preMasterSecret,
                             &ssl->arrays->preMasterSz,
-                            WOLFSSL_CLIENT_END,
-                        #ifdef HAVE_PK_CALLBACKS
-                            ssl->EccSharedSecretCtx
-                        #else
-                            NULL
+                            WOLFSSL_CLIENT_END
+                        );
+                        if (!ssl->specs.static_ecdh
+                        #ifdef WOLFSSL_ASYNC_CRYPT
+                            && ret != WC_PENDING_E
                         #endif
-                        );
+                        ) {
+                            FreeKey(ssl, DYNAMIC_TYPE_CURVE25519,
+                                                   (void**)&ssl->peerX25519Key);
+                            ssl->peerX25519KeyPresent = 0;
+                        }
                         break;
                     }
@@ -19192,11 +20123,15 @@
                         ssl->arrays->preMasterSecret,
                         &ssl->arrays->preMasterSz,
-                        WOLFSSL_CLIENT_END,
-                    #ifdef HAVE_PK_CALLBACKS
-                        ssl->EccSharedSecretCtx
-                    #else
-                        NULL
-                    #endif
+                        WOLFSSL_CLIENT_END
                     );
+                    if (!ssl->specs.static_ecdh
+                #ifdef WOLFSSL_ASYNC_CRYPT
+                        && ret != WC_PENDING_E
+                #endif
+                    ) {
+                        FreeKey(ssl, DYNAMIC_TYPE_ECC,
+                                                      (void**)&ssl->peerEccKey);
+                        ssl->peerEccKeyPresent = 0;
+                    }
                 #endif
 
@@ -19269,5 +20204,6 @@
                 }
             #endif /* !NO_DH && !NO_PSK */
-            #if defined(HAVE_ECC) && !defined(NO_PSK)
+            #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \
+                                                                !defined(NO_PSK)
                 case ecdhe_psk_kea:
                 {
@@ -19283,5 +20219,5 @@
                     args->encSz += args->length + OPAQUE8_LEN;
 
-                    /* Create pre master secret is the concatination of
+                    /* Create pre master secret is the concatenation of
                        eccSize + eccSharedKey + pskSize + pskKey */
                     c16toa((word16)ssl->arrays->preMasterSz, pms);
@@ -19299,5 +20235,5 @@
                     break;
                 }
-            #endif /* HAVE_ECC && !NO_PSK */
+            #endif /* (HAVE_ECC || HAVE_CURVE25519) && !NO_PSK */
             #ifdef HAVE_NTRU
                 case ntru_kea:
@@ -19306,5 +20242,5 @@
                 }
             #endif /* HAVE_NTRU */
-            #ifdef HAVE_ECC
+            #if defined(HAVE_ECC) || defined(HAVE_CURVE25519)
                 case ecc_diffie_hellman_kea:
                 {
@@ -19314,5 +20250,5 @@
                     break;
                 }
-            #endif /* HAVE_ECC */
+            #endif /* HAVE_ECC || HAVE_CURVE25519 */
 
                 default:
@@ -19467,10 +20403,10 @@
         #endif
 
-        #ifdef WOLFSSL_CALLBACKS
+        #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
             if (ssl->hsInfoOn)
-                AddPacketName("ClientKeyExchange", &ssl->handShakeInfo);
+                AddPacketName(ssl, "ClientKeyExchange");
             if (ssl->toInfoOn)
-                AddPacketInfo("ClientKeyExchange", &ssl->timeoutInfo,
-                              args->output, args->sendSz, ssl->heap);
+                AddPacketInfo(ssl, "ClientKeyExchange", handshake,
+                            args->output, args->sendSz, WRITE_PROTO, ssl->heap);
         #endif
 
@@ -19496,4 +20432,5 @@
 
     WOLFSSL_LEAVE("SendClientKeyExchange", ret);
+    WOLFSSL_END(WC_FUNC_CLIENT_KEY_EXCHANGE_SEND);
 
 #ifdef WOLFSSL_ASYNC_CRYPT
@@ -19504,5 +20441,7 @@
 
     /* No further need for PMS */
+    if (ssl->arrays->preMasterSecret != NULL) {
     ForceZero(ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz);
+    }
     ssl->arrays->preMasterSz = 0;
 
@@ -19514,147 +20453,48 @@
 }
 
+#endif /* !WOLFSSL_NO_TLS12 */
 
 #ifndef NO_CERTS
-/* Decode the private key - RSA, ECC, or Ed25519 - and creates a key object.
- * The signature type is set as well.
- * The maximum length of a signature is returned.
- *
- * ssl     The SSL/TLS object.
- * length  The length of a signature.
- * returns 0 on success, otherwise failure.
- */
-int DecodePrivateKey(WOLFSSL *ssl, word16* length)
-{
-    int      ret;
-    int      keySz;
-    word32   idx;
-
-    /* make sure private key exists */
-    if (ssl->buffers.key == NULL || ssl->buffers.key->buffer == NULL) {
-        WOLFSSL_MSG("Private key missing!");
-        ERROR_OUT(NO_PRIVATE_KEY, exit_dpk);
-    }
-
+
+#ifdef HAVE_PK_CALLBACKS
+    int GetPrivateKeySigSize(WOLFSSL* ssl)
+    {
+        int sigSz = 0;
+
+        if (ssl == NULL)
+            return 0;
+
+        switch (ssl->buffers.keyType) {
 #ifndef NO_RSA
-    ssl->hsType = DYNAMIC_TYPE_RSA;
-    ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey);
-    if (ret != 0) {
-        goto exit_dpk;
-    }
-
-    WOLFSSL_MSG("Trying RSA private key");
-
-    /* Set start of data to beginning of buffer. */
-    idx = 0;
-    /* Decode the key assuming it is an RSA private key. */
-    ret = wc_RsaPrivateKeyDecode(ssl->buffers.key->buffer, &idx,
-                (RsaKey*)ssl->hsKey, ssl->buffers.key->length);
-    if (ret == 0) {
-        WOLFSSL_MSG("Using RSA private key");
-
-        /* It worked so check it meets minimum key size requirements. */
-        keySz = wc_RsaEncryptSize((RsaKey*)ssl->hsKey);
-        if (keySz < 0) { /* check if keySz has error case */
-            ERROR_OUT(keySz, exit_dpk);
-        }
-
-        if (keySz < ssl->options.minRsaKeySz) {
-            WOLFSSL_MSG("RSA key size too small");
-            ERROR_OUT(RSA_KEY_SIZE_E, exit_dpk);
-        }
-
-        /* Return the maximum signature length. */
-        *length = (word16)keySz;
-
-        goto exit_dpk;
-    }
-#endif /* !NO_RSA */
-
-#ifdef HAVE_ECC
-#ifndef NO_RSA
-    FreeKey(ssl, ssl->hsType, (void**)&ssl->hsKey);
-#endif /* !NO_RSA */
-
-    ssl->hsType = DYNAMIC_TYPE_ECC;
-    ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey);
-    if (ret != 0) {
-        goto exit_dpk;
-    }
-
-#ifndef NO_RSA
-    WOLFSSL_MSG("Trying ECC private key, RSA didn't work");
-#else
-    WOLFSSL_MSG("Trying ECC private key");
-#endif
-
-    /* Set start of data to beginning of buffer. */
-    idx = 0;
-    /* Decode the key assuming it is an ECC private key. */
-    ret = wc_EccPrivateKeyDecode(ssl->buffers.key->buffer, &idx,
-                                 (ecc_key*)ssl->hsKey,
-                                 ssl->buffers.key->length);
-    if (ret == 0) {
-        WOLFSSL_MSG("Using ECC private key");
-
-        /* Check it meets the minimum ECC key size requirements. */
-        keySz = wc_ecc_size((ecc_key*)ssl->hsKey);
-        if (keySz < ssl->options.minEccKeySz) {
-            WOLFSSL_MSG("ECC key size too small");
-            ERROR_OUT(ECC_KEY_SIZE_E, exit_dpk);
-        }
-
-        /* Return the maximum signature length. */
-        *length = (word16)wc_ecc_sig_size((ecc_key*)ssl->hsKey);
-
-        goto exit_dpk;
-    }
-#endif
-#ifdef HAVE_ED25519
-#if !defined(NO_RSA) || defined(HAVE_ECC)
-    FreeKey(ssl, ssl->hsType, (void**)&ssl->hsKey);
-#endif
-
-    ssl->hsType = DYNAMIC_TYPE_ED25519;
-    ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey);
-    if (ret != 0) {
-        goto exit_dpk;
-    }
-
-#ifdef HAVE_ECC
-    WOLFSSL_MSG("Trying ED25519 private key, ECC didn't work");
-#elif !defined(NO_RSA)
-    WOLFSSL_MSG("Trying ED25519 private key, RSA didn't work");
-#else
-    WOLFSSL_MSG("Trying ED25519 private key");
-#endif
-
-    /* Set start of data to beginning of buffer. */
-    idx = 0;
-    /* Decode the key assuming it is an ED25519 private key. */
-    ret = wc_Ed25519PrivateKeyDecode(ssl->buffers.key->buffer, &idx,
-                                     (ed25519_key*)ssl->hsKey,
-                                     ssl->buffers.key->length);
-    if (ret == 0) {
-        WOLFSSL_MSG("Using ED25519 private key");
-
-        /* Check it meets the minimum ECC key size requirements. */
-        (void)keySz;
-        if (ED25519_KEY_SIZE < ssl->options.minEccKeySz) {
-            WOLFSSL_MSG("ED25519 key size too small");
-            ERROR_OUT(ECC_KEY_SIZE_E, exit_dpk);
-        }
-
-        /* Return the maximum signature length. */
-        *length = ED25519_SIG_SIZE;
-
-        goto exit_dpk;
-    }
-#endif
-
-exit_dpk:
-    return ret;
+        #ifdef WC_RSA_PSS
+            case rsa_pss_sa_algo:
+#endif
+            case rsa_sa_algo:
+                sigSz = ssl->buffers.keySz;
+                ssl->hsType = DYNAMIC_TYPE_RSA;
+                break;
+#endif
+        #ifdef HAVE_ECC
+            case ecc_dsa_sa_algo:
+                sigSz = wc_ecc_sig_size_calc(ssl->buffers.keySz);
+                ssl->hsType = DYNAMIC_TYPE_ECC;
+                break;
+        #endif
+        #ifdef HAVE_ED25519
+            case ed25519_sa_algo:
+                sigSz = ED25519_SIG_SIZE; /* fixed known value */
+                ssl->hsType = DYNAMIC_TYPE_ED25519;
+                break;
+        #endif
+            default:
+                break;
 }
-
-
+        return sigSz;
+    }
+#endif /* HAVE_PK_CALLBACKS */
+
+#ifndef WOLFSSL_NO_TLS12
+
+#ifndef WOLFSSL_NO_CLIENT_AUTH
 typedef struct ScvArgs {
     byte*  output; /* not allocated */
@@ -19691,4 +20531,5 @@
 }
 
+/* handle generation of certificate_verify (15) */
 int SendCertificateVerify(WOLFSSL* ssl)
 {
@@ -19702,4 +20543,5 @@
 #endif
 
+    WOLFSSL_START(WC_FUNC_CERTIFICATE_VERIFY_SEND);
     WOLFSSL_ENTER("SendCertificateVerify");
 
@@ -19731,5 +20573,5 @@
             }
 
-            args->sendSz = MAX_CERT_VERIFY_SZ;
+            args->sendSz = MAX_CERT_VERIFY_SZ + MAX_MSG_EXTRA;
             if (IsEncryptionOn(ssl, 1)) {
                 args->sendSz += MAX_MSG_EXTRA;
@@ -19757,8 +20599,22 @@
             }
 
+            if (ssl->buffers.key == NULL) {
+            #ifdef HAVE_PK_CALLBACKS
+                if (wolfSSL_CTX_IsPrivatePkSet(ssl->ctx))
+                    args->length = GetPrivateKeySigSize(ssl);
+                else
+            #endif
+                    ERROR_OUT(NO_PRIVATE_KEY, exit_scv);
+            }
+            else {
             /* Decode private key. */
             ret = DecodePrivateKey(ssl, &args->length);
             if (ret != 0) {
                 goto exit_scv;
+            }
+            }
+
+            if (args->length <= 0) {
+                ERROR_OUT(NO_PRIVATE_KEY, exit_scv);
             }
 
@@ -19849,4 +20705,11 @@
             }
         #endif /* !NO_RSA */
+        #if defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)
+            if (args->sigAlgo == ed25519_sa_algo) {
+                ret = Ed25519CheckPubKey(ssl);
+                if (ret != 0)
+                    goto exit_scv;
+            }
+        #endif /* HAVE_ED25519 && !NO_ED25519_CLIENT_AUTH */
 
             /* Advance state and proceed */
@@ -19865,32 +20728,28 @@
                     ssl->buffers.sig.buffer, &ssl->buffers.sig.length,
                     key,
-            #if defined(HAVE_PK_CALLBACKS)
-                    ssl->buffers.key->buffer,
-                    ssl->buffers.key->length,
-                    ssl->EccSignCtx
+            #ifdef HAVE_PK_CALLBACKS
+                    ssl->buffers.key
             #else
-                    NULL, 0, NULL
+                    NULL
             #endif
                 );
             }
         #endif /* HAVE_ECC */
-        #ifdef HAVE_ED25519
+        #if defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)
            if (ssl->hsType == DYNAMIC_TYPE_ED25519) {
                 ed25519_key* key = (ed25519_key*)ssl->hsKey;
 
                 ret = Ed25519Sign(ssl,
-                    ssl->buffers.digest.buffer, ssl->buffers.digest.length,
+                    ssl->hsHashes->messages, ssl->hsHashes->length,
                     ssl->buffers.sig.buffer, &ssl->buffers.sig.length,
                     key,
-            #if defined(HAVE_PK_CALLBACKS)
-                    ssl->buffers.key->buffer,
-                    ssl->buffers.key->length,
-                    ssl->Ed25519SignCtx
+            #ifdef HAVE_PK_CALLBACKS
+                    ssl->buffers.key
             #else
-                    NULL, 0, NULL
+                    NULL
             #endif
                 );
             }
-        #endif /* HAVE_ECC */
+        #endif /* HAVE_ED25519 && !NO_ED25519_CLIENT_AUTH */
         #ifndef NO_RSA
             if (ssl->hsType == DYNAMIC_TYPE_RSA) {
@@ -19904,10 +20763,5 @@
                     args->verify + args->extraSz + VERIFY_HEADER, &args->sigSz,
                     args->sigAlgo, ssl->suites->hashAlgo, key,
-                    ssl->buffers.key->buffer, ssl->buffers.key->length,
-                #ifdef HAVE_PK_CALLBACKS
-                    ssl->RsaSignCtx
-                #else
-                    NULL
-                #endif
+                    ssl->buffers.key
                 );
             }
@@ -19938,5 +20792,5 @@
             }
         #endif /* HAVE_ECC */
-        #ifdef HAVE_ECC
+        #ifdef HAVE_ED25519
             if (ssl->hsType == DYNAMIC_TYPE_ED25519) {
                 args->length = (word16)ssl->buffers.sig.length;
@@ -19946,5 +20800,5 @@
                         ssl->buffers.sig.buffer, ssl->buffers.sig.length);
             }
-        #endif /* HAVE_ECC */
+        #endif /* HAVE_ED25519 */
         #ifndef NO_RSA
             if (ssl->hsType == DYNAMIC_TYPE_RSA) {
@@ -19965,5 +20819,6 @@
                     args->verifySig, args->sigSz,
                     ssl->buffers.sig.buffer, ssl->buffers.sig.length,
-                    args->sigAlgo, ssl->suites->hashAlgo, key
+                    args->sigAlgo, ssl->suites->hashAlgo, key,
+                    ssl->buffers.key
                 );
             }
@@ -20054,10 +20909,10 @@
 
 
-        #ifdef WOLFSSL_CALLBACKS
+        #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
             if (ssl->hsInfoOn)
-                AddPacketName("CertificateVerify", &ssl->handShakeInfo);
+                AddPacketName(ssl, "CertificateVerify");
             if (ssl->toInfoOn)
-                AddPacketInfo("CertificateVerify", &ssl->timeoutInfo,
-                              args->output, args->sendSz, ssl->heap);
+                AddPacketInfo(ssl, "CertificateVerify", handshake,
+                            args->output, args->sendSz, WRITE_PROTO, ssl->heap);
         #endif
 
@@ -20076,4 +20931,5 @@
 
     WOLFSSL_LEAVE("SendCertificateVerify", ret);
+    WOLFSSL_END(WC_FUNC_CERTIFICATE_VERIFY_SEND);
 
 #ifdef WOLFSSL_ASYNC_CRYPT
@@ -20094,4 +20950,7 @@
     return ret;
 }
+#endif /* WOLFSSL_NO_CLIENT_AUTH */
+
+#endif /* WOLFSSL_NO_TLS12 */
 
 #endif /* NO_CERTS */
@@ -20116,5 +20975,5 @@
         ssl->session.isDynamic = 1;
     }
-    ssl->session.ticketLen = length;
+    ssl->session.ticketLen = (word16)length;
 
     if (length > 0) {
@@ -20128,4 +20987,11 @@
          * supercede the existing session cache info. */
         ssl->options.haveSessionId = 1;
+#ifdef WOLFSSL_TLS13
+        if (ssl->options.tls1_3) {
+            XMEMCPY(ssl->session.sessionID,
+                                 ssl->session.ticket + length - ID_LEN, ID_LEN);
+        }
+        else
+#endif
         XMEMCPY(ssl->arrays->sessionID,
                                  ssl->session.ticket + length - ID_LEN, ID_LEN);
@@ -20135,4 +21001,7 @@
 }
 
+#ifndef WOLFSSL_NO_TLS12
+
+/* handle processing of session_ticket (4) */
 static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
     word32 size)
@@ -20181,4 +21050,7 @@
     return 0;
 }
+
+#endif /* !WOLFSSL_NO_TLS12 */
+
 #endif /* HAVE_SESSION_TICKET */
 
@@ -20187,13 +21059,20 @@
 #ifndef NO_WOLFSSL_SERVER
 
+#ifndef WOLFSSL_NO_TLS12
+
+    /* handle generation of server_hello (2) */
     int SendServerHello(WOLFSSL* ssl)
     {
+        int    ret;
         byte              *output;
-        word32             length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+        word16 length;
+        word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
         int                sendSz;
-        int                ret;
         byte               sessIdSz = ID_LEN;
         byte               echoId   = 0;  /* ticket echo id flag */
         byte               cacheOff = 0;  /* session cache off flag */
+
+        WOLFSSL_START(WC_FUNC_SERVER_HELLO_SEND);
+        WOLFSSL_ENTER("SendServerHello");
 
         length = VERSION_SZ + RAN_LEN
@@ -20203,5 +21082,7 @@
 
 #ifdef HAVE_TLS_EXTENSIONS
-        length += TLSX_GetResponseSize(ssl, server_hello);
+        ret = TLSX_GetResponseSize(ssl, server_hello, &length);
+        if (ret != 0)
+            return ret;
     #ifdef HAVE_SESSION_TICKET
         if (ssl->options.useTicket) {
@@ -20223,5 +21104,5 @@
 #endif
 
-        /* is the session cahce off at build or runtime */
+        /* is the session cache off at build or runtime */
 #ifdef NO_SESSION_CACHE
         cacheOff = 1;
@@ -20238,12 +21119,4 @@
             sessIdSz = 0;
         }
-
-        /* check for avalaible size */
-        if ((ret = CheckAvailableSize(ssl, MAX_HELLO_SZ)) != 0)
-            return ret;
-
-        /* get output buffer */
-        output = ssl->buffers.outputBuffer.buffer +
-                 ssl->buffers.outputBuffer.length;
 
         sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
@@ -20258,10 +21131,22 @@
         }
         #endif /* WOLFSSL_DTLS */
+
+        if (IsEncryptionOn(ssl, 1))
+            sendSz += MAX_MSG_EXTRA;
+
+        /* check for available size */
+        if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
+            return ret;
+
+        /* get output buffer */
+        output = ssl->buffers.outputBuffer.buffer +
+                 ssl->buffers.outputBuffer.length;
+
         AddHeaders(output, length, server_hello, ssl);
 
         /* now write to output */
         /* first version */
-        output[idx++] = ssl->version.major;
-        output[idx++] = ssl->version.minor;
+        output[idx++] = (byte)ssl->version.major;
+        output[idx++] = (byte)ssl->version.minor;
 
         /* then random and session id */
@@ -20278,5 +21163,5 @@
                 XMEMCPY(output + idx + RAN_LEN - (TLS13_DOWNGRADE_SZ + 1),
                         tls13Downgrade, TLS13_DOWNGRADE_SZ);
-                output[idx + RAN_LEN - 1] = IsAtLeastTLSv1_2(ssl);
+                output[idx + RAN_LEN - 1] = (byte)IsAtLeastTLSv1_2(ssl);
             }
             else
@@ -20329,5 +21214,11 @@
         /* last, extensions */
 #ifdef HAVE_TLS_EXTENSIONS
-        TLSX_WriteResponse(ssl, output + idx, server_hello);
+        {
+            word16 offset = 0;
+            ret = TLSX_WriteResponse(ssl, output + idx, server_hello, &offset);
+            if (ret != 0)
+                return ret;
+            idx += offset;
+        }
 #else
 #ifdef HAVE_EXTENDED_MASTER
@@ -20341,44 +21232,69 @@
             /*idx += HELLO_EXT_SZ_SZ;*/
             /* idx is not used after this point. uncomment the line above
-             * if adding any more extentions in the future. */
-        }
-#endif
-#endif
-
-        ssl->buffers.outputBuffer.length += sendSz;
-        #ifdef WOLFSSL_DTLS
-            if (IsDtlsNotSctpMode(ssl)) {
-                if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0)
-                    return ret;
-            }
-
-            if (ssl->options.dtls) {
+             * if adding any more extensions in the future. */
+        }
+#endif
+#endif
+
+        if (IsEncryptionOn(ssl, 1)) {
+            byte* input;
+            int   inputSz = idx - RECORD_HEADER_SZ; /* build msg adds rec hdr */
+
+            input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+            if (input == NULL)
+                return MEMORY_E;
+
+            XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
+            sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
+                                  handshake, 1, 0, 0);
+            XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+
+            if (sendSz < 0)
+                return sendSz;
+        } else {
+            #ifdef WOLFSSL_DTLS
+                if (ssl->options.dtls)
                 DtlsSEQIncrement(ssl, CUR_ORDER);
-            }
         #endif
-
         ret = HashOutput(ssl, output, sendSz, 0);
         if (ret != 0)
             return ret;
-
-
-    #ifdef WOLFSSL_CALLBACKS
+        }
+
+    #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
         if (ssl->hsInfoOn)
-            AddPacketName("ServerHello", &ssl->handShakeInfo);
+            AddPacketName(ssl, "ServerHello");
         if (ssl->toInfoOn)
-            AddPacketInfo("ServerHello", &ssl->timeoutInfo, output, sendSz,
-                          ssl->heap);
+            AddPacketInfo(ssl, "ServerHello", handshake, output, sendSz,
+                          WRITE_PROTO, ssl->heap);
     #endif
 
         ssl->options.serverState = SERVER_HELLO_COMPLETE;
+        ssl->buffers.outputBuffer.length += sendSz;
+
+    #ifdef WOLFSSL_DTLS
+        if (IsDtlsNotSctpMode(ssl)) {
+            if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0)
+                return ret;
+        }
+
+        if (ssl->options.dtls) {
+            DtlsSEQIncrement(ssl, CUR_ORDER);
+        }
+    #endif
 
         if (ssl->options.groupMessages)
-            return 0;
+            ret = 0;
         else
-            return SendBuffered(ssl);
-    }
-
-
-#ifdef HAVE_ECC
+            ret = SendBuffered(ssl);
+
+        WOLFSSL_LEAVE("SendServerHello", ret);
+        WOLFSSL_END(WC_FUNC_SERVER_HELLO_SEND);
+
+        return ret;
+    }
+
+
+#if defined(HAVE_ECC)
 
     static byte SetCurveId(ecc_key* key)
@@ -20439,8 +21355,4 @@
     #endif
     #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
-        #ifdef HAVE_CURVE25519
-            case ECC_X25519_OID:
-                return WOLFSSL_ECC_X25519;
-        #endif
         #ifndef NO_ECC_SECP
             case ECC_SECP384R1_OID:
@@ -20469,12 +21381,13 @@
     }
 
-#endif /* HAVE_ECC */
+#endif /* HAVE_ECC || HAVE_CURVE25519 */
 
     typedef struct SskeArgs {
         byte*  output; /* not allocated */
-    #if defined(HAVE_ECC) || (!defined(NO_DH) && !defined(NO_RSA))
+    #if defined(HAVE_ECC) || defined(HAVE_ED25519) || \
+                                           (!defined(NO_DH) && !defined(NO_RSA))
         byte*  sigDataBuf;
     #endif
-    #if defined(HAVE_ECC)
+    #if defined(HAVE_ECC) || defined(HAVE_CURVE25519)
         byte*  exportBuf;
     #endif
@@ -20482,12 +21395,14 @@
         byte*  verifySig;
     #endif
+        byte*  input;
         word32 idx;
         word32 tmpSigSz;
         word32 length;
         word32 sigSz;
-    #if defined(HAVE_ECC) || (!defined(NO_DH) && !defined(NO_RSA))
+    #if defined(HAVE_ECC) || defined(HAVE_ED25519) || \
+                                           (!defined(NO_DH) && !defined(NO_RSA))
         word32 sigDataSz;
     #endif
-    #if defined(HAVE_ECC)
+    #if defined(HAVE_ECC) || defined(HAVE_CURVE25519)
         word32 exportSz;
     #endif
@@ -20496,4 +21411,5 @@
     #endif
         int    sendSz;
+        int    inputSz;
     } SskeArgs;
 
@@ -20504,5 +21420,5 @@
         (void)ssl;
 
-    #if defined(HAVE_ECC)
+    #if defined(HAVE_ECC) || defined(HAVE_CURVE25519)
         if (args->exportBuf) {
             XFREE(args->exportBuf, ssl->heap, DYNAMIC_TYPE_DER);
@@ -20510,5 +21426,6 @@
         }
     #endif
-    #if defined(HAVE_ECC) || (!defined(NO_DH) && !defined(NO_RSA))
+    #if defined(HAVE_ECC) || defined(HAVE_ED25519) || \
+                                           (!defined(NO_DH) && !defined(NO_RSA))
         if (args->sigDataBuf) {
             XFREE(args->sigDataBuf, ssl->heap, DYNAMIC_TYPE_SIGNATURE);
@@ -20525,4 +21442,5 @@
     }
 
+    /* handle generation of server_key_exchange (12) */
     int SendServerKeyExchange(WOLFSSL* ssl)
     {
@@ -20536,4 +21454,5 @@
     #endif
 
+        WOLFSSL_START(WC_FUNC_SERVER_KEY_EXCHANGE_SEND);
         WOLFSSL_ENTER("SendServerKeyExchange");
 
@@ -20570,5 +21489,6 @@
                 switch(ssl->specs.kea)
                 {
-                #if defined(HAVE_ECC) && !defined(NO_PSK)
+                #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \
+                                                                !defined(NO_PSK)
                     case ecdhe_psk_kea:
                     {
@@ -20576,6 +21496,6 @@
                         break;
                     }
-                #endif /* HAVE_ECC && !NO_PSK */
-                #ifdef HAVE_ECC
+                #endif /* (HAVE_ECC || CURVE25519) && !NO_PSK */
+                #if defined(HAVE_ECC)
                     case ecc_diffie_hellman_kea:
                     {
@@ -20583,10 +21503,4 @@
                             WOLFSSL_MSG("Using Static ECDH, not sending ServerKeyExchange");
                             ERROR_OUT(0, exit_sske);
-                        }
-
-                        /* make sure private key exists */
-                        if (ssl->buffers.key == NULL ||
-                                            ssl->buffers.key->buffer == NULL) {
-                            ERROR_OUT(NO_PRIVATE_KEY, exit_sske);
                         }
 
@@ -20650,4 +21564,25 @@
                         }
 
+                        #if !defined(WOLFSSL_OLD_PRIME_CHECK) && \
+                            !defined(HAVE_FIPS) && \
+                            !defined(HAVE_SELFTEST)
+                        if (ssl->options.dhDoKeyTest &&
+                            !ssl->options.dhKeyTested)
+                        {
+                            ret = wc_DhSetCheckKey(
+                                ssl->buffers.serverDH_Key,
+                                ssl->buffers.serverDH_P.buffer,
+                                ssl->buffers.serverDH_P.length,
+                                ssl->buffers.serverDH_G.buffer,
+                                ssl->buffers.serverDH_G.length,
+                                NULL, 0, 0, ssl->rng);
+                            if (ret != 0) {
+                                goto exit_sske;
+                            }
+                            ssl->options.dhKeyTested = 1;
+                        }
+                        else
+                        #endif
+                        {
                         ret = wc_DhSetKey(ssl->buffers.serverDH_Key,
                             ssl->buffers.serverDH_P.buffer,
@@ -20658,4 +21593,5 @@
                             goto exit_sske;
                         }
+                        }
 
                         ret = DhGenKeyPair(ssl, ssl->buffers.serverDH_Key,
@@ -20667,8 +21603,9 @@
                     }
                 #endif /* !NO_DH && (!NO_PSK || !NO_RSA) */
-                #if defined(HAVE_ECC) && !defined(NO_PSK)
+                #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \
+                                                                !defined(NO_PSK)
                     case ecdhe_psk_kea:
                         /* Fall through to create temp ECC key */
-                #endif /* HAVE_ECC && !NO_PSK */
+                #endif /* (HAVE_ECC || CURVE25519) && !NO_PSK */
                 #if defined(HAVE_ECC) || defined(HAVE_CURVE25519)
                     case ecc_diffie_hellman_kea:
@@ -20709,6 +21646,4 @@
 
                         if (ssl->eccTempKeyPresent == 0) {
-                            /* TODO: Need to first do wc_EccPrivateKeyDecode,
-                                then we know curve dp */
                             ret = EccMakeKey(ssl, ssl->eccTempKey, NULL);
                             if (ret == 0 || ret == WC_PENDING_E) {
@@ -20737,5 +21672,6 @@
             case TLS_ASYNC_BUILD:
             {
-            #if (!defined(NO_DH) && !defined(NO_RSA)) || defined(HAVE_ECC)
+            #if (!defined(NO_DH) && !defined(NO_RSA)) || (defined(HAVE_ECC) || \
+                                                       defined(HAVE_CURVE25519))
                 word32 preSigSz, preSigIdx;
             #endif
@@ -20773,4 +21709,9 @@
                         }
                     #endif
+
+                        if (IsEncryptionOn(ssl, 1)) {
+                            args->sendSz += MAX_MSG_EXTRA;
+                        }
+
                         /* check for available size */
                         if ((ret = CheckAvailableSize(ssl, args->sendSz)) != 0) {
@@ -20831,4 +21772,8 @@
                         }
                     #endif
+
+                        if (IsEncryptionOn(ssl, 1)) {
+                            args->sendSz += MAX_MSG_EXTRA;
+                        }
 
                         /* check for available size */
@@ -20881,5 +21826,6 @@
                     }
                 #endif /* !defined(NO_DH) && !defined(NO_PSK) */
-                #if defined(HAVE_ECC) && !defined(NO_PSK)
+                #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \
+                                                                !defined(NO_PSK)
                     case ecdhe_psk_kea:
                     {
@@ -20933,4 +21879,9 @@
                         }
                     #endif
+
+                        if (IsEncryptionOn(ssl, 1)) {
+                            args->sendSz += MAX_MSG_EXTRA;
+                        }
+
                         /* check for available size */
                         if ((ret = CheckAvailableSize(ssl, args->sendSz)) != 0) {
@@ -20958,6 +21909,8 @@
                     #endif
                         {
+                    #ifdef HAVE_ECC
                             args->output[args->idx++] =
                                                     SetCurveId(ssl->eccTempKey);
+                    #endif
                         }
                         args->output[args->idx++] = (byte)args->exportSz;
@@ -20966,6 +21919,6 @@
                         break;
                     }
-                #endif /* HAVE_ECC && !NO_PSK */
-                #ifdef HAVE_ECC
+                #endif /* (HAVE_ECC || HAVE_CURVE25519) && !NO_PSK */
+                #if defined(HAVE_ECC) || defined(HAVE_CURVE25519)
                     case ecc_diffie_hellman_kea:
                     {
@@ -20995,8 +21948,10 @@
                     #endif
                         {
+                    #if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT)
                             if (wc_ecc_export_x963(ssl->eccTempKey,
                                        args->exportBuf, &args->exportSz) != 0) {
                                 ERROR_OUT(ECC_EXPORT_ERROR, exit_sske);
                             }
+                     #endif
                        }
                         args->length += args->exportSz;
@@ -21005,6 +21960,18 @@
                         preSigIdx = args->idx;
 
-                        switch(ssl->suites->sigAlgo)
-                        {
+                        if (ssl->buffers.key == NULL) {
+                        #ifdef HAVE_PK_CALLBACKS
+                            if (wolfSSL_CTX_IsPrivatePkSet(ssl->ctx)) {
+                                args->tmpSigSz = GetPrivateKeySigSize(ssl);
+                                if (args->tmpSigSz <= 0) {
+                                    ERROR_OUT(NO_PRIVATE_KEY, exit_sske);
+                                }
+                            }
+                            else
+                        #endif
+                                ERROR_OUT(NO_PRIVATE_KEY, exit_sske);
+                        }
+                        else {
+                            switch(ssl->suites->sigAlgo) {
                         #ifndef NO_RSA
                         #ifdef WC_RSA_PSS
@@ -21043,4 +22010,5 @@
                             }
                         #endif /* !NO_RSA */
+                        #ifdef HAVE_ECC
                             case ecc_dsa_sa_algo:
                             {
@@ -21069,9 +22037,9 @@
                                         ssl->options.minEccKeySz) {
                                     WOLFSSL_MSG("ECC key size too small");
-                                    ret = ECC_KEY_SIZE_E;
-                                    goto exit_sske;
+                                    ERROR_OUT(ECC_KEY_SIZE_E, exit_sske);
                                 }
                                 break;
                             }
+                        #endif
                         #ifdef HAVE_ED25519
                             case ed25519_sa_algo:
@@ -21093,4 +22061,5 @@
                                     goto exit_sske;
                                 }
+
                                 /* worst case estimate */
                                 args->tmpSigSz = ED25519_SIG_SIZE;
@@ -21100,13 +22069,13 @@
                                         ssl->options.minEccKeySz) {
                                     WOLFSSL_MSG("Ed25519 key size too small");
-                                    ret = ECC_KEY_SIZE_E;
-                                    goto exit_sske;
+                                    ERROR_OUT(ECC_KEY_SIZE_E, exit_sske);
                                 }
                                 break;
                             }
-                        #endif
+                        #endif /* HAVE_ED25519 */
                             default:
                                 ERROR_OUT(ALGO_ID_E, exit_sske);  /* unsupported type */
                         } /* switch(ssl->specs.sig_algo) */
+                        }
 
                         /* sig length */
@@ -21131,4 +22100,8 @@
                         }
                     #endif
+                        if (IsEncryptionOn(ssl, 1)) {
+                            args->sendSz += MAX_MSG_EXTRA;
+                        }
+
                         /* check for available size */
                         if ((ret = CheckAvailableSize(ssl, args->sendSz)) != 0) {
@@ -21152,6 +22125,8 @@
                     #endif
                         {
+                    #ifdef HAVE_ECC
                             args->output[args->idx++] =
                                                     SetCurveId(ssl->eccTempKey);
+                    #endif
                         }
                         args->output[args->idx++] = (byte)args->exportSz;
@@ -21270,15 +22245,19 @@
                         #endif
                         #endif /* !NO_RSA */
-                        #ifdef HAVE_ED25519
-                            case ed25519_sa_algo:
-                        #endif
                             case ecc_dsa_sa_algo:
                             {
                                 break;
                             }
+                        #ifdef  HAVE_ED25519
+                            case ed25519_sa_algo:
+                                ret = Ed25519CheckPubKey(ssl);
+                                if (ret != 0)
+                                    goto exit_sske;
+                                break;
+                        #endif /* HAVE_ED25519 */
                         } /* switch(ssl->specs.sig_algo) */
                         break;
                     }
-                #endif /* HAVE_ECC */
+                #endif /* HAVE_ECC || HAVE_CURVE25519 */
                 #if !defined(NO_DH) && !defined(NO_RSA)
                     case diffie_hellman_kea:
@@ -21296,12 +22275,20 @@
 
                         if (!ssl->options.usingAnon_cipher) {
-                            word32   i = 0;
                             int      keySz;
 
-                            /* make sure private key exists */
-                            if (ssl->buffers.key == NULL ||
-                                            ssl->buffers.key->buffer == NULL) {
+                            /* sig length */
+                            args->length += LENGTH_SZ;
+
+                            if (ssl->buffers.key == NULL) {
+                            #ifdef HAVE_PK_CALLBACKS
+                                if (wolfSSL_CTX_IsPrivatePkSet(ssl->ctx))
+                                    keySz = (word32)GetPrivateKeySigSize(ssl);
+                                else
+                            #endif
                                 ERROR_OUT(NO_PRIVATE_KEY, exit_sske);
                             }
+                            else
+                            {
+                                word32 i = 0;
 
                             ssl->hsType = DYNAMIC_TYPE_RSA;
@@ -21311,17 +22298,18 @@
                             }
 
-                            /* sig length */
-                            args->length += LENGTH_SZ;
-
                             ret = wc_RsaPrivateKeyDecode(
                                 ssl->buffers.key->buffer, &i,
-                                (RsaKey*)ssl->hsKey, ssl->buffers.key->length);
+                                    (RsaKey*)ssl->hsKey,
+                                    ssl->buffers.key->length);
                             if (ret != 0) {
                                 goto exit_sske;
                             }
                             keySz = wc_RsaEncryptSize((RsaKey*)ssl->hsKey);
-                            if (keySz < 0) { /* test if keySz has error */
+                            }
+
+                            if (keySz <= 0) { /* test if keySz has error */
                                 ERROR_OUT(keySz, exit_sske);
                             }
+
                             args->tmpSigSz = (word32)keySz;
                             args->length += args->tmpSigSz;
@@ -21351,4 +22339,8 @@
                         }
                     #endif
+
+                        if (IsEncryptionOn(ssl, 1)) {
+                            args->sendSz += MAX_MSG_EXTRA;
+                        }
 
                         /* check for available size */
@@ -21526,11 +22518,12 @@
                     }
                 #endif /* !defined(NO_DH) && !defined(NO_PSK) */
-                #if defined(HAVE_ECC) && !defined(NO_PSK)
+                #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \
+                                                                !defined(NO_PSK)
                     case ecdhe_psk_kea:
                     {
                         break;
                     }
-                #endif /* HAVE_ECC && !NO_PSK */
-                #ifdef HAVE_ECC
+                #endif /* (HAVE_ECC || HAVE_CURVE25519) && !NO_PSK */
+                #if defined(HAVE_ECC) || defined(HAVE_CURVE25519)
                     case ecc_diffie_hellman_kea:
                     {
@@ -21553,8 +22546,22 @@
                                     ssl->suites->sigAlgo, ssl->suites->hashAlgo,
                                     key,
-                                    ssl->buffers.key->buffer,
-                                    ssl->buffers.key->length,
+                                    ssl->buffers.key
+                                );
+                                break;
+                            }
+                        #endif /* !NO_RSA */
+                        #ifdef HAVE_ECC
+                            case ecc_dsa_sa_algo:
+                            {
+                                ecc_key* key = (ecc_key*)ssl->hsKey;
+
+                                ret = EccSign(ssl,
+                                    ssl->buffers.sig.buffer,
+                                    ssl->buffers.sig.length,
+                                    args->output + LENGTH_SZ + args->idx,
+                                    &args->sigSz,
+                                    key,
                             #ifdef HAVE_PK_CALLBACKS
-                                    ssl->RsaSignCtx
+                                    ssl->buffers.key
                             #else
                                     NULL
@@ -21563,25 +22570,5 @@
                                 break;
                             }
-                        #endif /* !NO_RSA */
-                            case ecc_dsa_sa_algo:
-                            {
-                                ecc_key* key = (ecc_key*)ssl->hsKey;
-
-                                ret = EccSign(ssl,
-                                    ssl->buffers.sig.buffer,
-                                    ssl->buffers.sig.length,
-                                    args->output + LENGTH_SZ + args->idx,
-                                    &args->sigSz,
-                                    key,
-                            #if defined(HAVE_PK_CALLBACKS)
-                                    ssl->buffers.key->buffer,
-                                    ssl->buffers.key->length,
-                                    ssl->EccSignCtx
-                            #else
-                                    NULL, 0, NULL
-                            #endif
-                                );
-                                break;
-                            }
+                        #endif /* HAVE_ECC */
                         #ifdef HAVE_ED25519
                             case ed25519_sa_algo:
@@ -21594,10 +22581,8 @@
                                     &args->sigSz,
                                     key,
-                            #if defined(HAVE_PK_CALLBACKS)
-                                    ssl->buffers.key->buffer,
-                                    ssl->buffers.key->length,
-                                    ssl->Ed25519SignCtx
+                            #ifdef HAVE_PK_CALLBACKS
+                                    ssl->buffers.key
                             #else
-                                    NULL, 0, NULL
+                                    NULL
                             #endif
                                 );
@@ -21608,5 +22593,5 @@
                         break;
                     }
-                #endif /* HAVE_ECC */
+                #endif /* HAVE_ECC || HAVE_CURVE25519 */
                 #if !defined(NO_DH) && !defined(NO_RSA)
                     case diffie_hellman_kea:
@@ -21634,11 +22619,5 @@
                                     ssl->suites->sigAlgo, ssl->suites->hashAlgo,
                                     key,
-                                    ssl->buffers.key->buffer,
-                                    ssl->buffers.key->length,
-                                #ifdef HAVE_PK_CALLBACKS
-                                    ssl->RsaSignCtx
-                                #else
-                                    NULL
-                                #endif
+                                    ssl->buffers.key
                                 );
                                 break;
@@ -21680,5 +22659,6 @@
                     }
                 #endif /* !defined(NO_DH) && !defined(NO_PSK) */
-                #if defined(HAVE_ECC) && !defined(NO_PSK)
+                #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \
+                                                                !defined(NO_PSK)
                     case ecdhe_psk_kea:
                     {
@@ -21686,6 +22666,6 @@
                         break;
                     }
-                #endif /* HAVE_ECC && !NO_PSK */
-                #ifdef HAVE_ECC
+                #endif /* (HAVE_ECC || HAVE_CURVE25519) && !NO_PSK */
+                #if defined(HAVE_ECC) || defined(HAVE_CURVE25519)
                     case ecc_diffie_hellman_kea:
                     {
@@ -21720,5 +22700,5 @@
                                     ssl->buffers.sig.length,
                                     ssl->suites->sigAlgo, ssl->suites->hashAlgo,
-                                    key
+                                    key, ssl->buffers.key
                                 );
                                 break;
@@ -21726,4 +22706,7 @@
                         #endif
                             case ecc_dsa_sa_algo:
+                        #ifdef HAVE_ED25519
+                            case ed25519_sa_algo:
+                        #endif
                             {
                                 /* Now that we know the real sig size, write it. */
@@ -21736,17 +22719,4 @@
                                 break;
                             }
-                        #ifdef HAVE_ED25519
-                            case ed25519_sa_algo:
-                            {
-                                /* Now that we know the real sig size, write it. */
-                                c16toa((word16)args->sigSz,
-                                                    args->output + args->idx);
-
-                                /* And adjust length and sendSz from estimates */
-                                args->length += args->sigSz - args->tmpSigSz;
-                                args->sendSz += args->sigSz - args->tmpSigSz;
-                                break;
-                            }
-                        #endif
                             default:
                                 ERROR_OUT(ALGO_ID_E, exit_sske);  /* unsupported type */
@@ -21754,5 +22724,5 @@
                         break;
                     }
-                #endif /* HAVE_ECC */
+                #endif /* HAVE_ECC || HAVE_CURVE25519 */
                 #if !defined(NO_DH) && !defined(NO_RSA)
                     case diffie_hellman_kea:
@@ -21792,5 +22762,5 @@
                                     ssl->buffers.sig.length,
                                     ssl->suites->sigAlgo, ssl->suites->hashAlgo,
-                                    key
+                                    key, ssl->buffers.key
                                 );
                                 break;
@@ -21838,5 +22808,5 @@
             #endif
 
-            #if defined(HAVE_ECC)
+            #if defined(HAVE_ECC) || defined(HAVE_CURVE25519)
                 if (ssl->specs.kea == ecdhe_psk_kea ||
                     ssl->specs.kea == ecc_diffie_hellman_kea) {
@@ -21850,9 +22820,33 @@
                     }
                 }
-            #endif /* HAVE_ECC */
-
+            #endif /* HAVE_ECC || HAVE_CURVE25519 */
+
+                if (IsEncryptionOn(ssl, 1)) {
+                    args->inputSz = args->length + HANDSHAKE_HEADER_SZ;
+                                                     /* buildmsg adds rechdr */
+                    args->input = (byte*)XMALLOC(args->inputSz, ssl->heap,
+                                                        DYNAMIC_TYPE_IN_BUFFER);
+                    if (args->input == NULL) {
+                        ERROR_OUT(MEMORY_E, exit_sske);
+                    }
+
+                    XMEMCPY(args->input, args->output + RECORD_HEADER_SZ,
+                                                                 args->inputSz);
+                    ret = BuildMessage(ssl, args->output, args->sendSz,
+                                args->input, args->inputSz, handshake, 1, 0, 0);
+                    XFREE(args->input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+                    args->input = NULL;
+                        /* make sure its not double free'd on cleanup */
+
+                    if (ret >= 0) {
+                        args->sendSz = ret;
+                        ret = 0;
+                    }
+                }
+                else {
             #ifdef WOLFSSL_DTLS
                 if (IsDtlsNotSctpMode(ssl)) {
-                    if ((ret = DtlsMsgPoolSave(ssl, args->output, args->sendSz)) != 0) {
+                        if ((ret = DtlsMsgPoolSave(ssl,
+                                            args->output, args->sendSz)) != 0) {
                         goto exit_sske;
                     }
@@ -21867,12 +22861,13 @@
                     goto exit_sske;
                 }
-
-            #ifdef WOLFSSL_CALLBACKS
+                }
+
+            #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
                 if (ssl->hsInfoOn) {
-                    AddPacketName("ServerKeyExchange", &ssl->handShakeInfo);
+                    AddPacketName(ssl, "ServerKeyExchange");
                 }
                 if (ssl->toInfoOn) {
-                    AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo,
-                        args->output, args->sendSz, ssl->heap);
+                    AddPacketInfo(ssl, "ServerKeyExchange", handshake,
+                        args->output, args->sendSz, WRITE_PROTO, ssl->heap);
                 }
             #endif
@@ -21900,4 +22895,5 @@
 
         WOLFSSL_LEAVE("SendServerKeyExchange", ret);
+        WOLFSSL_END(WC_FUNC_SERVER_KEY_EXCHANGE_SEND);
 
     #ifdef WOLFSSL_ASYNC_CRYPT
@@ -21936,4 +22932,6 @@
 
 #endif
+
+#endif /* !WOLFSSL_NO_TLS12 */
 
     /* Make sure server cert/key are valid for this suite, true on success */
@@ -22019,5 +23017,6 @@
         }
 
-#ifdef HAVE_SUPPORTED_CURVES
+#if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \
+                                                  defined(HAVE_SUPPORTED_CURVES)
         if (!TLSX_ValidateSupportedCurves(ssl, first, second)) {
             WOLFSSL_MSG("Don't have matching curves");
@@ -22035,5 +23034,6 @@
             }
             else {
-                WOLFSSL_MSG("Version of SSL connection does not support TLS_QSH");
+                WOLFSSL_MSG("Version of SSL connection does not support "
+                            "TLS_QSH");
             }
             return 0;
@@ -22047,7 +23047,12 @@
             int ret = TLSX_KeyShare_Establish(ssl);
             if (ret == KEY_SHARE_ERROR)
-                ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST;
+                ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE;
             else if (ret != 0)
                 return 0;
+        }
+        else if (first == TLS13_BYTE) {
+            /* Can't negotiate TLS 1.3 cipher suites with lower protocol
+             * version. */
+            return 0;
         }
 #endif
@@ -22133,4 +23138,5 @@
         ProtocolVersion pv;
         Suites          clSuites;
+        int ret = -1;
 
         (void)inSz;
@@ -22138,5 +23144,5 @@
 #ifdef WOLFSSL_CALLBACKS
         if (ssl->hsInfoOn)
-            AddPacketName("ClientHello", &ssl->handShakeInfo);
+            AddPacketName(ssl, "ClientHello");
         if (ssl->toInfoOn)
             AddLateName("ClientHello", &ssl->timeoutInfo);
@@ -22172,4 +23178,6 @@
             byte haveRSA = 0;
             byte havePSK = 0;
+            int  keySz   = 0;
+
             if (!ssl->options.downgrade) {
                 WOLFSSL_MSG("Client trying to connect with lesser version");
@@ -22207,6 +23215,9 @@
             havePSK = ssl->options.havePSK;
 #endif
-
-            InitSuites(ssl->suites, ssl->version, ssl->keySz, haveRSA, havePSK,
+#ifndef NO_CERTS
+            keySz = ssl->buffers.keySz;
+#endif
+
+            InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK,
                        ssl->options.haveDH, ssl->options.haveNTRU,
                        ssl->options.haveECDSAsig, ssl->options.haveECC,
@@ -22266,4 +23277,5 @@
 
         ssl->options.clientState = CLIENT_HELLO_COMPLETE;
+        ssl->cbmode = SSL_CB_MODE_WRITE;
         *inOutIdx = idx;
 
@@ -22271,5 +23283,4 @@
         /* DoClientHello uses same resume code */
         if (ssl->options.resuming) {  /* let's try */
-            int ret = -1;
             WOLFSSL_SESSION* session = GetSession(ssl,
                                                   ssl->arrays->masterSecret, 1);
@@ -22313,10 +23324,85 @@
         }
 
-        return MatchSuite(ssl, &clSuites);
+        ret = MatchSuite(ssl, &clSuites);
+        if (ret != 0)return ret;
+        return SanityCheckMsgReceived(ssl, client_hello);
     }
 
 #endif /* OLD_HELLO_ALLOWED */
 
-
+#ifndef WOLFSSL_NO_TLS12
+
+    int HandleTlsResumption(WOLFSSL* ssl, int bogusID, Suites* clSuites)
+    {
+        int ret = 0;
+        WOLFSSL_SESSION* session = GetSession(ssl,
+                                                  ssl->arrays->masterSecret, 1);
+
+        (void)bogusID;
+
+        #ifdef HAVE_SESSION_TICKET
+            if (ssl->options.useTicket == 1) {
+                session = &ssl->session;
+            } else if (bogusID == 1 && ssl->options.rejectTicket == 0) {
+                WOLFSSL_MSG("Bogus session ID without session ticket");
+                return BUFFER_ERROR;
+            }
+        #endif
+
+        if (!session) {
+            WOLFSSL_MSG("Session lookup for resume failed");
+            ssl->options.resuming = 0;
+        }
+        else if (session->haveEMS != ssl->options.haveEMS) {
+            /* RFC 7627, 5.3, server-side */
+            /* if old sess didn't have EMS, but new does, full handshake */
+            if (!session->haveEMS && ssl->options.haveEMS) {
+                WOLFSSL_MSG("Attempting to resume a session that didn't "
+                            "use EMS with a new session with EMS. Do full "
+                            "handshake.");
+                ssl->options.resuming = 0;
+            }
+            /* if old sess used EMS, but new doesn't, MUST abort */
+            else if (session->haveEMS && !ssl->options.haveEMS) {
+                WOLFSSL_MSG("Trying to resume a session with EMS without "
+                            "using EMS");
+                return EXT_MASTER_SECRET_NEEDED_E;
+            }
+        #ifdef HAVE_EXT_CACHE
+            wolfSSL_SESSION_free(session);
+        #endif
+        }
+        else {
+        #ifdef HAVE_EXT_CACHE
+            wolfSSL_SESSION_free(session);
+        #endif
+            if (MatchSuite(ssl, clSuites) < 0) {
+                WOLFSSL_MSG("Unsupported cipher suite, ClientHello");
+                return UNSUPPORTED_SUITE;
+            }
+
+            ret = wc_RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom,
+                                                                       RAN_LEN);
+            if (ret != 0)
+                return ret;
+
+            #ifdef NO_OLD_TLS
+                ret = DeriveTlsKeys(ssl);
+            #else
+                #ifndef NO_TLS
+                    if (ssl->options.tls)
+                        ret = DeriveTlsKeys(ssl);
+                #endif
+                    if (!ssl->options.tls)
+                        ret = DeriveKeys(ssl);
+            #endif
+            ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE;
+        }
+
+        return ret;
+    }
+
+
+    /* handle processing of client_hello (1) */
     int DoClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
                              word32 helloSz)
@@ -22328,4 +23414,5 @@
         word32          i = *inOutIdx;
         word32          begin = i;
+        int             ret = 0;
 #ifdef WOLFSSL_DTLS
         Hmac            cookieHmac;
@@ -22338,9 +23425,11 @@
 #endif /* WOLFSSL_DTLS */
 
+        WOLFSSL_START(WC_FUNC_CLIENT_HELLO_DO);
+        WOLFSSL_ENTER("DoClientHello");
+
 #ifdef WOLFSSL_CALLBACKS
-        if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo);
+        if (ssl->hsInfoOn) AddPacketName(ssl, "ClientHello");
         if (ssl->toInfoOn) AddLateName("ClientHello", &ssl->timeoutInfo);
 #endif
-
         /* protocol version, random and session id length check */
         if ((i - begin) + OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz)
@@ -22352,5 +23441,4 @@
 #ifdef WOLFSSL_DTLS
         if (IsDtlsNotSctpMode(ssl)) {
-            int ret;
             #if defined(NO_SHA) && defined(NO_SHA256)
                 #error "DTLS needs either SHA or SHA-256"
@@ -22379,4 +23467,8 @@
         i += OPAQUE16_LEN;
 
+        /* Legacy protocol version cannot negotiate TLS 1.3 or higher. */
+        if (pv.major == SSLv3_MAJOR && pv.minor >= TLSv1_3_MINOR)
+            pv.minor = TLSv1_2_MINOR;
+
         if ((!ssl->options.dtls && ssl->version.minor > pv.minor) ||
             (ssl->options.dtls && ssl->version.minor != DTLS_MINOR
@@ -22499,5 +23591,5 @@
 #ifdef WOLFSSL_DTLS
         if (IsDtlsNotSctpMode(ssl)) {
-            int ret = wc_HmacUpdate(&cookieHmac, input + i, RAN_LEN);
+            ret = wc_HmacUpdate(&cookieHmac, input + i, RAN_LEN);
             if (ret != 0) return ret;
         }
@@ -22532,5 +23624,5 @@
 #ifdef WOLFSSL_DTLS
             if (IsDtlsNotSctpMode(ssl)) {
-                int ret = wc_HmacUpdate(&cookieHmac, input + i - 1, b + 1);
+                ret = wc_HmacUpdate(&cookieHmac, input + i - 1, b + 1);
                 if (ret != 0) return ret;
             }
@@ -22588,9 +23680,8 @@
         /* check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV suite */
         if (FindSuite(&clSuites, 0, TLS_EMPTY_RENEGOTIATION_INFO_SCSV) >= 0) {
-            int ret = 0;
-
-            ret = TLSX_AddEmptyRenegotiationInfo(&ssl->extensions, ssl->heap);
+            ret = TLSX_AddEmptyRenegotiationInfo(&ssl->extensions);
             if (ret != WOLFSSL_SUCCESS)
                 return ret;
+            ssl->secure_renegotiation->enabled = 1;
         }
 #endif /* HAVE_SERVER_RENEGOTIATION_INFO */
@@ -22598,5 +23689,5 @@
 #ifdef WOLFSSL_DTLS
         if (IsDtlsNotSctpMode(ssl)) {
-            int ret = wc_HmacUpdate(&cookieHmac,
+            ret = wc_HmacUpdate(&cookieHmac,
                                     input + i - OPAQUE16_LEN,
                                     clSuites.suiteSz + OPAQUE16_LEN);
@@ -22621,5 +23712,4 @@
         if (IsDtlsNotSctpMode(ssl)) {
             byte newCookie[MAX_COOKIE_LEN];
-            int ret;
 
             ret = wc_HmacUpdate(&cookieHmac, input + i - 1, b + 1);
@@ -22658,5 +23748,5 @@
 
         {
-            /* copmression match types */
+            /* compression match types */
             int matchNo = 0;
             int matchZlib = 0;
@@ -22694,9 +23784,9 @@
             QSH_Init(ssl);
         #endif
-            if (TLSX_SupportExtensions(ssl)) {
-                int ret = 0;
+            if (TLSX_SupportExtensions(ssl))
 #else
-            if (IsAtLeastTLSv1_2(ssl)) {
-#endif
+            if (IsAtLeastTLSv1_2(ssl))
+#endif
+            {
                 /* Process the hello extension. Skip unsupported. */
                 word16 totalExtSz;
@@ -22730,9 +23820,9 @@
                 }
     #endif
-#if defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+    #if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
                 if((ret=SNI_Callback(ssl)))
                     return ret;
                 ssl->options.side = WOLFSSL_SERVER_END;
-#endif /*HAVE_STUNNEL*/
+    #endif
 
                 i += totalExtSz;
@@ -22753,16 +23843,23 @@
 
                     if (extId == HELLO_EXT_SIG_ALGO) {
-                        ato16(&input[i], &clSuites.hashSigAlgoSz);
+                        word16 hashSigAlgoSz;
+
+                        ato16(&input[i], &hashSigAlgoSz);
                         i += OPAQUE16_LEN;
 
-                        if (OPAQUE16_LEN + clSuites.hashSigAlgoSz > extSz)
+                        if (OPAQUE16_LEN + hashSigAlgoSz > extSz)
                             return BUFFER_ERROR;
 
+                        clSuites.hashSigAlgoSz = hashSigAlgoSz;
+                        if (clSuites.hashSigAlgoSz > WOLFSSL_MAX_SIGALGO) {
+                            WOLFSSL_MSG("ClientHello SigAlgo list exceeds max, "
+                                                                  "truncating");
+                            clSuites.hashSigAlgoSz = WOLFSSL_MAX_SIGALGO;
+                        }
+
                         XMEMCPY(clSuites.hashSigAlgo, &input[i],
-                            min(clSuites.hashSigAlgoSz, HELLO_EXT_SIGALGO_MAX));
-                        i += clSuites.hashSigAlgoSz;
-
-                        if (clSuites.hashSigAlgoSz > HELLO_EXT_SIGALGO_MAX)
-                            clSuites.hashSigAlgoSz = HELLO_EXT_SIGALGO_MAX;
+                                                      clSuites.hashSigAlgoSz);
+
+                        i += hashSigAlgoSz;
                     }
 #ifdef HAVE_EXTENDED_MASTER
@@ -22787,73 +23884,31 @@
         /* ProcessOld uses same resume code */
         if (ssl->options.resuming) {
-            int ret = -1;
-            WOLFSSL_SESSION* session = GetSession(ssl,
-                                                  ssl->arrays->masterSecret, 1);
-            #ifdef HAVE_SESSION_TICKET
-                if (ssl->options.useTicket == 1) {
-                    session = &ssl->session;
-                } else if (bogusID == 1 && ssl->options.rejectTicket == 0) {
-                    WOLFSSL_MSG("Bogus session ID without session ticket");
-                    return BUFFER_ERROR;
+            ret = HandleTlsResumption(ssl, bogusID, &clSuites);
+            if (ret != 0)
+                return ret;
+            if (ssl->options.clientState == CLIENT_KEYEXCHANGE_COMPLETE) {
+                WOLFSSL_LEAVE("DoClientHello", ret);
+                WOLFSSL_END(WC_FUNC_CLIENT_HELLO_DO);
+
+                return ret;
+            }
                 }
-            #endif
-
-            if (!session) {
-                WOLFSSL_MSG("Session lookup for resume failed");
-                ssl->options.resuming = 0;
-            }
-            else if (session->haveEMS != ssl->options.haveEMS) {
-                /* RFC 7627, 5.3, server-side */
-                /* if old sess didn't have EMS, but new does, full handshake */
-                if (!session->haveEMS && ssl->options.haveEMS) {
-                    WOLFSSL_MSG("Attempting to resume a session that didn't "
-                                "use EMS with a new session with EMS. Do full "
-                                "handshake.");
-                    ssl->options.resuming = 0;
-                }
-                /* if old sess used EMS, but new doesn't, MUST abort */
-                else if (session->haveEMS && !ssl->options.haveEMS) {
-                    WOLFSSL_MSG("Trying to resume a session with EMS without "
-                                "using EMS");
-                    return EXT_MASTER_SECRET_NEEDED_E;
-                }
-#ifdef HAVE_EXT_CACHE
-                wolfSSL_SESSION_free(session);
-#endif
-            }
-            else {
-#ifdef HAVE_EXT_CACHE
-                wolfSSL_SESSION_free(session);
-#endif
-                if (MatchSuite(ssl, &clSuites) < 0) {
-                    WOLFSSL_MSG("Unsupported cipher suite, ClientHello");
-                    return UNSUPPORTED_SUITE;
-                }
-
-                ret = wc_RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom,
-                                                                       RAN_LEN);
-                if (ret != 0)
-                    return ret;
-
-                #ifdef NO_OLD_TLS
-                    ret = DeriveTlsKeys(ssl);
-                #else
-                    #ifndef NO_TLS
-                        if (ssl->options.tls)
-                            ret = DeriveTlsKeys(ssl);
-                    #endif
-                        if (!ssl->options.tls)
-                            ret = DeriveKeys(ssl);
+        ret = MatchSuite(ssl, &clSuites);
+
+#ifdef HAVE_SECURE_RENEGOTIATION
+    if (ssl->secure_renegotiation && ssl->secure_renegotiation->enabled &&
+            IsEncryptionOn(ssl, 0)) {
+        ssl->secure_renegotiation->startScr = 1;
+    }
                 #endif
-                ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE;
+        WOLFSSL_LEAVE("DoClientHello", ret);
+        WOLFSSL_END(WC_FUNC_CLIENT_HELLO_DO);
 
                 return ret;
             }
-        }
-        return MatchSuite(ssl, &clSuites);
-    }
-
-
-#if !defined(NO_RSA) || defined(HAVE_ECC)
+
+
+#if (!defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519)) && \
+                                                !defined(WOLFSSL_NO_CLIENT_AUTH)
 
     typedef struct DcvArgs {
@@ -22876,4 +23931,5 @@
     }
 
+    /* handle processing of certificate_verify (15) */
     static int DoCertificateVerify(WOLFSSL* ssl, byte* input,
                                 word32* inOutIdx, word32 size)
@@ -22888,4 +23944,5 @@
     #endif
 
+        WOLFSSL_START(WC_FUNC_CERTIFICATE_VERIFY_DO);
         WOLFSSL_ENTER("DoCertificateVerify");
 
@@ -22919,5 +23976,5 @@
             #ifdef WOLFSSL_CALLBACKS
                 if (ssl->hsInfoOn)
-                    AddPacketName("CertificateVerify", &ssl->handShakeInfo);
+                    AddPacketName(ssl, "CertificateVerify");
                 if (ssl->toInfoOn)
                     AddLateName("CertificateVerify", &ssl->timeoutInfo);
@@ -22948,8 +24005,8 @@
                     args->sigAlgo = ecc_dsa_sa_algo;
             #endif
-            #ifdef HAVE_ED25519
+            #if defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)
                 else if (ssl->peerEd25519KeyPresent)
                     args->sigAlgo = ed25519_sa_algo;
-            #endif
+            #endif /* HAVE_ED25519 && !NO_ED25519_CLIENT_AUTH */
 
                 if ((args->idx - args->begin) + OPAQUE16_LEN > size) {
@@ -22992,5 +24049,5 @@
                 }
             #endif /* HAVE_ECC */
-            #ifdef HAVE_ED25519
+            #if defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)
                 if (ssl->peerEd25519KeyPresent) {
                     WOLFSSL_MSG("Doing ED25519 peer cert verify");
@@ -23001,5 +24058,5 @@
                     }
                 }
-            #endif /* HAVE_ED25519 */
+            #endif /* HAVE_ED25519 && !NO_ED25519_CLIENT_AUTH */
 
                 /* Advance state and proceed */
@@ -23021,9 +24078,7 @@
                         ssl->peerRsaKey,
                     #ifdef HAVE_PK_CALLBACKS
-                        ssl->buffers.peerRsaKey.buffer,
-                        ssl->buffers.peerRsaKey.length,
-                        ssl->RsaVerifyCtx
+                        &ssl->buffers.peerRsaKey
                     #else
-                        NULL, 0, NULL
+                        NULL
                     #endif
                     );
@@ -23048,13 +24103,27 @@
                         ssl->peerEccDsaKey,
                     #ifdef HAVE_PK_CALLBACKS
-                        ssl->buffers.peerEccDsaKey.buffer,
-                        ssl->buffers.peerEccDsaKey.length,
-                        ssl->EccVerifyCtx
+                        &ssl->buffers.peerEccDsaKey
                     #else
-                        NULL, 0, NULL
+                        NULL
                     #endif
                     );
                 }
             #endif /* HAVE_ECC */
+            #if defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)
+                if (ssl->peerEd25519KeyPresent) {
+                    WOLFSSL_MSG("Doing Ed25519 peer cert verify");
+
+                    ret = Ed25519Verify(ssl,
+                        input + args->idx, args->sz,
+                        ssl->hsHashes->messages, ssl->hsHashes->prevLen,
+                        ssl->peerEd25519Key,
+                    #ifdef HAVE_PK_CALLBACKS
+                        &ssl->buffers.peerEd25519Key
+                    #else
+                        NULL
+                    #endif
+                    );
+                }
+            #endif /* HAVE_ED25519 && !NO_ED25519_CLIENT_AUTH */
 
                 /* Check for error */
@@ -23083,5 +24152,5 @@
                                              HashAlgoToType(args->hashAlgo));
                             if (ret != 0)
-                                return ret;
+                                goto exit_dcv;
                         }
                         else
@@ -23141,4 +24210,8 @@
             case TLS_ASYNC_FINALIZE:
             {
+                if (IsEncryptionOn(ssl, 0)) {
+                    args->idx += ssl->keys.padSz;
+                }
+
                 ssl->options.havePeerVerify = 1;
 
@@ -23162,9 +24235,10 @@
 
         WOLFSSL_LEAVE("DoCertificateVerify", ret);
+        WOLFSSL_END(WC_FUNC_CERTIFICATE_VERIFY_DO);
 
     #ifdef WOLFSSL_ASYNC_CRYPT
         /* Handle async operation */
         if (ret == WC_PENDING_E) {
-            /* Mark message as not recevied so it can process again */
+            /* Mark message as not received so it can process again */
             ssl->msgsReceived.got_certificate_verify = 0;
 
@@ -23172,5 +24246,9 @@
         }
     #endif /* WOLFSSL_ASYNC_CRYPT */
-
+    #ifdef OPENSSL_EXTRA
+        if (ret != 0){
+             SendAlert(ssl, alert_fatal, bad_certificate);
+        }
+    #endif
         /* Digest is not allocated, so do this to prevent free */
         ssl->buffers.digest.buffer = NULL;
@@ -23184,6 +24262,7 @@
     }
 
-#endif /* !NO_RSA || HAVE_ECC */
-
+#endif /* (!NO_RSA || HAVE_ECC || HAVE_ED25519) && !WOLFSSL_NO_CLIENT_AUTH */
+
+    /* handle generation of server_hello_done (14) */
     int SendServerHelloDone(WOLFSSL* ssl)
     {
@@ -23192,4 +24271,7 @@
         int   ret;
 
+        WOLFSSL_START(WC_FUNC_SERVER_HELLO_DONE_SEND);
+        WOLFSSL_ENTER("SendServerHelloDone");
+
     #ifdef WOLFSSL_DTLS
         if (ssl->options.dtls)
@@ -23197,4 +24279,7 @@
     #endif
 
+        if (IsEncryptionOn(ssl, 1))
+            sendSz += MAX_MSG_EXTRA;
+
         /* check for available size */
         if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
@@ -23207,24 +24292,39 @@
         AddHeaders(output, 0, server_hello_done, ssl);
 
+        if (IsEncryptionOn(ssl, 1)) {
+            byte* input;
+            int   inputSz = HANDSHAKE_HEADER_SZ; /* build msg adds rec hdr */
+
+            input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+            if (input == NULL)
+                return MEMORY_E;
+
+            XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
+            sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
+                                  handshake, 1, 0, 0);
+            XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+
+            if (sendSz < 0)
+                return sendSz;
+        } else {
     #ifdef WOLFSSL_DTLS
         if (IsDtlsNotSctpMode(ssl)) {
             if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0)
-                return 0;
-        }
-
+                        return ret;
+        }
         if (ssl->options.dtls)
             DtlsSEQIncrement(ssl, CUR_ORDER);
     #endif
-
         ret = HashOutput(ssl, output, sendSz, 0);
             if (ret != 0)
                 return ret;
-
-    #ifdef WOLFSSL_CALLBACKS
+        }
+
+    #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
         if (ssl->hsInfoOn)
-            AddPacketName("ServerHelloDone", &ssl->handShakeInfo);
+            AddPacketName(ssl, "ServerHelloDone");
         if (ssl->toInfoOn)
-            AddPacketInfo("ServerHelloDone", &ssl->timeoutInfo, output, sendSz,
-                          ssl->heap);
+            AddPacketInfo(ssl, "ServerHelloDone", handshake, output, sendSz,
+                    WRITE_PROTO, ssl->heap);
     #endif
         ssl->options.serverState = SERVER_HELLODONE_COMPLETE;
@@ -23232,7 +24332,13 @@
         ssl->buffers.outputBuffer.length += sendSz;
 
-        return SendBuffered(ssl);
-    }
-
+        ret = SendBuffered(ssl);
+
+        WOLFSSL_LEAVE("SendServerHelloDone", ret);
+        WOLFSSL_END(WC_FUNC_SERVER_HELLO_DONE_SEND);
+
+        return ret;
+    }
+
+#endif /* !WOLFSSL_NO_TLS12 */
 
 #ifdef HAVE_SESSION_TICKET
@@ -23251,5 +24357,8 @@
 #ifdef WOLFSSL_TLS13
         word32          ageAdd;                /* Obfuscation of age */
-        byte            namedGroup;            /* Named group used */
+        word16          namedGroup;            /* Named group used */
+    #ifndef WOLFSSL_TLS13_DRAFT_18
+        TicketNonce     ticketNonce;           /* Ticket nonce */
+    #endif
     #ifdef WOLFSSL_EARLY_DATA
         word32          maxEarlyDataSz;        /* Max size of early data */
@@ -23307,4 +24416,8 @@
             /* Resumption master secret. */
             XMEMCPY(it.msecret, ssl->session.masterSecret, SECRET_LEN);
+    #ifndef WOLFSSL_TLS13_DRAFT_18
+            XMEMCPY(&it.ticketNonce, &ssl->session.ticketNonce,
+                                                           sizeof(TicketNonce));
+    #endif
 #endif
         }
@@ -23375,4 +24488,7 @@
         word16          inLen;
 
+        WOLFSSL_START(WC_FUNC_TICKET_DO);
+        WOLFSSL_ENTER("DoClientTicket");
+
         if (len > SESSION_TICKET_LEN ||
              len < (word32)(sizeof(InternalTicket) + WOLFSSL_TICKET_FIXED_SZ)) {
@@ -23401,4 +24517,21 @@
         /* get master secret */
         if (ret == WOLFSSL_TICKET_RET_OK || ret == WOLFSSL_TICKET_RET_CREATE) {
+            if (ssl->version.minor < it->pv.minor) {
+                WOLFSSL_MSG("Ticket has greater version");
+                return VERSION_ERROR;
+            }
+            else if (ssl->version.minor > it->pv.minor) {
+                if (!ssl->options.downgrade) {
+                    WOLFSSL_MSG("Ticket has lesser version");
+                    return VERSION_ERROR;
+                }
+
+                WOLFSSL_MSG("Downgrading protocol due to ticket");
+
+                if (it->pv.minor < ssl->options.minDowngrade)
+                    return VERSION_ERROR;
+                ssl->version.minor = it->pv.minor;
+            }
+
             if (!IsAtLeastTLSv1_3(ssl->version)) {
                 XMEMCPY(ssl->arrays->masterSecret, it->msecret, SECRET_LEN);
@@ -23419,8 +24552,15 @@
                 /* Resumption master secret. */
                 XMEMCPY(ssl->session.masterSecret, it->msecret, SECRET_LEN);
+    #ifndef WOLFSSL_TLS13_DRAFT_18
+                XMEMCPY(&ssl->session.ticketNonce, &it->ticketNonce,
+                                                           sizeof(TicketNonce));
+    #endif
                 ssl->session.namedGroup = it->namedGroup;
 #endif
             }
         }
+
+        WOLFSSL_LEAVE("DoClientTicket", ret);
+        WOLFSSL_END(WC_FUNC_TICKET_DO);
 
         return ret;
@@ -23437,4 +24577,7 @@
         word32             idx    = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
 
+        WOLFSSL_START(WC_FUNC_TICKET_SEND);
+        WOLFSSL_ENTER("SendTicket");
+
         if (ssl->options.createTicket) {
             ret = CreateTicket(ssl);
@@ -23445,10 +24588,14 @@
         sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
 
+        if (!ssl->options.dtls) {
+            if (IsEncryptionOn(ssl, 1) && ssl->options.handShakeDone)
+                sendSz += MAX_MSG_EXTRA;
+        }
+        else {
         #ifdef WOLFSSL_DTLS
-        if (ssl->options.dtls) {
             sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
             idx    += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
-        }
         #endif
+        }
         /* check for available size */
         if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
@@ -23471,6 +24618,23 @@
         /* ticket */
         XMEMCPY(output + idx, ssl->session.ticket, ssl->session.ticketLen);
-        /* idx += ssl->session.ticketLen; */
-
+        idx += ssl->session.ticketLen;
+
+        if (IsEncryptionOn(ssl, 1) && ssl->options.handShakeDone) {
+            byte* input;
+            int   inputSz = idx - RECORD_HEADER_SZ; /* build msg adds rec hdr */
+
+            input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+            if (input == NULL)
+                return MEMORY_E;
+
+            XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
+            sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
+                                  handshake, 1, 0, 0);
+            XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+
+            if (sendSz < 0)
+                return sendSz;
+        }
+        else {
         #ifdef WOLFSSL_DTLS
         if (ssl->options.dtls) {
@@ -23481,16 +24645,81 @@
         }
         #endif
-
         ret = HashOutput(ssl, output, sendSz, 0);
-        if (ret != 0) return ret;
+            if (ret != 0)
+                return ret;
+        }
+
         ssl->buffers.outputBuffer.length += sendSz;
 
-        return SendBuffered(ssl);
+        ret = SendBuffered(ssl);
+
+        WOLFSSL_LEAVE("SendTicket", ret);
+        WOLFSSL_END(WC_FUNC_TICKET_SEND);
+
+        return ret;
     }
 
 #endif /* HAVE_SESSION_TICKET */
 
+#ifndef WOLFSSL_NO_TLS12
+
+#if defined(HAVE_SECURE_RENEGOTIATION) && \
+    defined(HAVE_SERVER_RENEGOTIATION_INFO) && \
+    !defined(WOLFSSL_NO_SERVER)
+
+    /* handle generation of server's hello_request (0) */
+    int SendHelloRequest(WOLFSSL* ssl)
+    {
+        byte* output;
+        int sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+        int ret;
+
+        WOLFSSL_START(WC_FUNC_HELLO_REQUEST_SEND);
+        WOLFSSL_ENTER("SendHelloRequest");
+
+        if (IsEncryptionOn(ssl, 1))
+            sendSz += MAX_MSG_EXTRA;
+
+        /* check for available size */
+        if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
+            return ret;
+
+        /* get output buffer */
+        output = ssl->buffers.outputBuffer.buffer +
+                 ssl->buffers.outputBuffer.length;
+
+        AddHeaders(output, 0, hello_request, ssl);
+
+        if (IsEncryptionOn(ssl, 1)) {
+            byte* input;
+            int   inputSz = HANDSHAKE_HEADER_SZ; /* build msg adds rec hdr */
+
+            input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+            if (input == NULL)
+                return MEMORY_E;
+
+            XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
+            sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
+                                  handshake, 0, 0, 0);
+            XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+
+            if (sendSz < 0)
+                return sendSz;
+        }
+
+        ssl->buffers.outputBuffer.length += sendSz;
+
+        ret = SendBuffered(ssl);
+
+        WOLFSSL_LEAVE("SendHelloRequest", ret);
+        WOLFSSL_END(WC_FUNC_HELLO_REQUEST_SEND);
+
+        return ret;
+    }
+
+#endif /* HAVE_SECURE_RENEGOTIATION && HAVE_SERVER_RENEGOTIATION_INFO */
 
 #ifdef WOLFSSL_DTLS
+    /* handle generation of DTLS hello_verify_request (3) */
     static int SendHelloVerifyRequest(WOLFSSL* ssl,
                                       const byte* cookie, byte cookieSz)
@@ -23530,10 +24759,10 @@
         XMEMCPY(output + idx, cookie, cookieSz);
 
-#ifdef WOLFSSL_CALLBACKS
+#if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
         if (ssl->hsInfoOn)
-            AddPacketName("HelloVerifyRequest", &ssl->handShakeInfo);
+            AddPacketName(ssl, "HelloVerifyRequest");
         if (ssl->toInfoOn)
-            AddPacketInfo("HelloVerifyRequest", &ssl->timeoutInfo, output,
-                          sendSz, ssl->heap);
+            AddPacketInfo(ssl, "HelloVerifyRequest", handshake, output,
+                          sendSz, WRITE_PROTO, ssl->heap);
 #endif
 
@@ -23550,4 +24779,7 @@
         word32 begin;
         word32 sigSz;
+    #ifndef NO_RSA
+        int    lastErr;
+    #endif
     } DckeArgs;
 
@@ -23560,4 +24792,5 @@
     }
 
+    /* handle processing client_key_exchange (16) */
     static int DoClientKeyExchange(WOLFSSL* ssl, byte* input, word32* inOutIdx,
                                                                     word32 size)
@@ -23572,4 +24805,8 @@
     #endif
 
+        (void)size;
+        (void)input;
+
+        WOLFSSL_START(WC_FUNC_CLIENT_KEY_EXCHANGE_DO);
         WOLFSSL_ENTER("DoClientKeyExchange");
 
@@ -23630,7 +24867,7 @@
             #endif /* !NO_CERTS */
 
-            #ifdef WOLFSSL_CALLBACKS
+            #if defined(WOLFSSL_CALLBACKS)
                 if (ssl->hsInfoOn) {
-                    AddPacketName("ClientKeyExchange", &ssl->handShakeInfo);
+                    AddPacketName(ssl, "ClientKeyExchange");
                 }
                 if (ssl->toInfoOn) {
@@ -23639,13 +24876,17 @@
             #endif
 
+                if (ssl->arrays->preMasterSecret == NULL) {
+                    ssl->arrays->preMasterSecret = (byte*)XMALLOC(ENCRYPT_LEN,
+                                                ssl->heap, DYNAMIC_TYPE_SECRET);
+                    if (ssl->arrays->preMasterSecret == NULL) {
+                        ERROR_OUT(MEMORY_E, exit_dcke);
+                    }
+                    XMEMSET(ssl->arrays->preMasterSecret, 0, ENCRYPT_LEN);
+                }
+
                 switch (ssl->specs.kea) {
                 #ifndef NO_RSA
                     case rsa_kea:
                     {
-                        /* make sure private key exists */
-                        if (ssl->buffers.key == NULL ||
-                                            ssl->buffers.key->buffer == NULL) {
-                            ERROR_OUT(NO_PRIVATE_KEY, exit_dcke);
-                        }
                         break;
                     } /* rsa_kea */
@@ -23673,10 +24914,10 @@
                     }
                 #endif /* HAVE_NTRU */
-                #ifdef HAVE_ECC
+                #if defined(HAVE_ECC) || defined(HAVE_CURVE25519)
                     case ecc_diffie_hellman_kea:
                     {
                         break;
                     }
-                #endif /* HAVE_ECC */
+                #endif /* HAVE_ECC || HAVE_CURVE25519 */
                 #ifndef NO_DH
                     case diffie_hellman_kea:
@@ -23696,5 +24937,6 @@
                     }
                 #endif /* !NO_DH && !NO_PSK */
-                #if defined(HAVE_ECC) && !defined(NO_PSK)
+                #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \
+                                                                !defined(NO_PSK)
                     case ecdhe_psk_kea:
                     {
@@ -23706,5 +24948,5 @@
                         break;
                     }
-                #endif /* HAVE_ECC && !NO_PSK */
+                #endif /* (HAVE_ECC || HAVE_CURVE25519) && !NO_PSK */
                     default:
                         WOLFSSL_MSG("Bad kea type");
@@ -23773,4 +25015,12 @@
                             WOLFSSL_MSG("RSA message too big");
                             ERROR_OUT(BUFFER_ERROR, exit_dcke);
+                        }
+
+                        /* pre-load PreMasterSecret with RNG data */
+                        ret = wc_RNG_GenerateBlock(ssl->rng,
+                            &ssl->arrays->preMasterSecret[VERSION_SZ],
+                            SECRET_LEN - VERSION_SZ);
+                        if (ret != 0) {
+                            goto exit_dcke;
                         }
 
@@ -24087,5 +25337,6 @@
                     }
                 #endif /* !NO_DH && !NO_PSK */
-                #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && !defined(NO_PSK)
+                #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \
+                                                                !defined(NO_PSK)
                     case ecdhe_psk_kea:
                     {
@@ -24225,4 +25476,5 @@
                     {
                         RsaKey* key = (RsaKey*)ssl->hsKey;
+
                         ret = RsaDec(ssl,
                             input + args->idx,
@@ -24231,12 +25483,24 @@
                             &args->sigSz,
                             key,
-                        #if defined(HAVE_PK_CALLBACKS)
-                            ssl->buffers.key->buffer,
-                            ssl->buffers.key->length,
-                            ssl->RsaDecCtx
+                        #ifdef HAVE_PK_CALLBACKS
+                            ssl->buffers.key
                         #else
-                            NULL, 0, NULL
+                            NULL
                         #endif
                         );
+
+                        /*  Errors that can occur here that should be
+                         *  indistinguishable:
+                         *       RSA_BUFFER_E, RSA_PAD_E and RSA_PRIVATE_ERROR
+                         */
+                        if (ret < 0 && ret != BAD_FUNC_ARG) {
+                        #ifdef WOLFSSL_ASYNC_CRYPT
+                            if (ret == WC_PENDING_E)
+                                goto exit_dcke;
+                        #endif
+                            /* store error code for handling below */
+                            args->lastErr = ret;
+                            ret = 0;
+                        }
                         break;
                     } /* rsa_kea */
@@ -24258,4 +25522,5 @@
                     {
                         void* private_key = ssl->eccTempKey;
+                        (void)private_key;
 
                     #ifdef HAVE_CURVE25519
@@ -24267,10 +25532,5 @@
                                 ssl->arrays->preMasterSecret,
                                 &ssl->arrays->preMasterSz,
-                                WOLFSSL_SERVER_END,
-                            #ifdef HAVE_PK_CALLBACKS
-                                ssl->EccSharedSecretCtx
-                            #else
-                                NULL
-                            #endif
+                                WOLFSSL_SERVER_END
                             );
                             break;
@@ -24288,11 +25548,14 @@
                             ssl->arrays->preMasterSecret,
                             &ssl->arrays->preMasterSz,
-                            WOLFSSL_SERVER_END,
-                        #ifdef HAVE_PK_CALLBACKS
-                            ssl->EccSharedSecretCtx
-                        #else
-                            NULL
-                        #endif
+                            WOLFSSL_SERVER_END
                         );
+                    #ifdef WOLFSSL_ASYNC_CRYPT
+                        if (ret != WC_PENDING_E)
+                    #endif
+                        {
+                            FreeKey(ssl, DYNAMIC_TYPE_ECC,
+                                                      (void**)&ssl->peerEccKey);
+                            ssl->peerEccKeyPresent = 0;
+                        }
                     #endif
                         break;
@@ -24325,5 +25588,6 @@
                     }
                 #endif /* !NO_DH && !NO_PSK */
-                #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && !defined(NO_PSK)
+                #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \
+                                                                !defined(NO_PSK)
                     case ecdhe_psk_kea:
                     {
@@ -24336,11 +25600,14 @@
                                 ssl->arrays->preMasterSecret + OPAQUE16_LEN,
                                 &args->sigSz,
-                                WOLFSSL_SERVER_END,
-                            #ifdef HAVE_PK_CALLBACKS
-                                ssl->EccSharedSecretCtx
-                            #else
-                                NULL
-                            #endif
+                                WOLFSSL_SERVER_END
                             );
+                        #ifdef WOLFSSL_ASYNC_CRYPT
+                            if (ret != WC_PENDING_E)
+                        #endif
+                            {
+                                FreeKey(ssl, DYNAMIC_TYPE_CURVE25519,
+                                                   (void**)&ssl->peerX25519Key);
+                                ssl->peerX25519KeyPresent = 0;
+                            }
                             break;
                         }
@@ -24352,11 +25619,15 @@
                             ssl->arrays->preMasterSecret + OPAQUE16_LEN,
                             &args->sigSz,
-                            WOLFSSL_SERVER_END,
-                        #ifdef HAVE_PK_CALLBACKS
-                            ssl->EccSharedSecretCtx
-                        #else
-                            NULL
-                        #endif
+                            WOLFSSL_SERVER_END
                         );
+                        if (!ssl->specs.static_ecdh
+                    #ifdef WOLFSSL_ASYNC_CRYPT
+                            && ret != WC_PENDING_E
+                    #endif
+                        ) {
+                            FreeKey(ssl, DYNAMIC_TYPE_ECC,
+                                                      (void**)&ssl->peerEccKey);
+                            ssl->peerEccKeyPresent = 0;
+                        }
                         break;
                     }
@@ -24385,14 +25656,36 @@
                         args->idx += args->length;
 
-                        if (args->sigSz == SECRET_LEN && args->output != NULL) {
-                            XMEMCPY(ssl->arrays->preMasterSecret, args->output, SECRET_LEN);
-                            if (ssl->arrays->preMasterSecret[0] != ssl->chVersion.major ||
-                                ssl->arrays->preMasterSecret[1] != ssl->chVersion.minor) {
-                                ERROR_OUT(PMS_VERSION_ERROR, exit_dcke);
-                            }
+                    #ifdef DEBUG_WOLFSSL
+                        /* check version (debug warning message only) */
+                        if (args->output != NULL) {
+                            if (args->output[0] != ssl->chVersion.major ||
+                                args->output[1] != ssl->chVersion.minor) {
+                                WOLFSSL_MSG("preMasterSecret version mismatch");
                         }
-                        else {
-                            ERROR_OUT(RSA_PRIVATE_ERROR, exit_dcke);
                         }
+                    #endif
+
+                        /* RFC5246 7.4.7.1:
+                         * Treat incorrectly formatted message blocks and/or
+                         * mismatched version numbers in a manner
+                         * indistinguishable from correctly formatted RSA blocks
+                         */
+
+                        args->lastErr = 0; /* reset */
+
+                        /* build PreMasterSecret */
+                        ssl->arrays->preMasterSecret[0] = ssl->chVersion.major;
+                        ssl->arrays->preMasterSecret[1] = ssl->chVersion.minor;
+                        if (args->output != NULL) {
+                            XMEMCPY(&ssl->arrays->preMasterSecret[VERSION_SZ],
+                                    &args->output[VERSION_SZ],
+                                    SECRET_LEN - VERSION_SZ);
+                        }
+                        /* preMasterSecret has RNG and version set
+                         * return proper length and ignore error
+                         * error will be caught as decryption error
+                         */
+                        args->sigSz = SECRET_LEN;
+                        ret = 0;
                         break;
                     } /* rsa_kea */
@@ -24410,5 +25703,5 @@
                     }
                 #endif /* HAVE_NTRU */
-                #ifdef HAVE_ECC
+                #if defined(HAVE_ECC) || defined(HAVE_CURVE25519)
                     case ecc_diffie_hellman_kea:
                     {
@@ -24417,5 +25710,5 @@
                         break;
                     }
-                #endif /* HAVE_ECC */
+                #endif /* HAVE_ECC || HAVE_CURVE25519 */
                 #ifndef NO_DH
                     case diffie_hellman_kea:
@@ -24457,5 +25750,6 @@
                     }
                 #endif /* !NO_DH && !NO_PSK */
-                #if defined(HAVE_ECC) && !defined(NO_PSK)
+                #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \
+                                                                !defined(NO_PSK)
                     case ecdhe_psk_kea:
                     {
@@ -24490,5 +25784,5 @@
                         break;
                     }
-                #endif /* HAVE_ECC && !NO_PSK */
+                #endif /* (HAVE_ECC || HAVE_CURVE25519) && !NO_PSK */
                     default:
                         ret = BAD_KEA_TYPE_E;
@@ -24507,4 +25801,8 @@
             case TLS_ASYNC_FINALIZE:
             {
+                if (IsEncryptionOn(ssl, 0)) {
+                    args->idx += ssl->keys.padSz;
+                }
+
             #ifdef HAVE_QSH
                 word16 name;
@@ -24564,9 +25862,10 @@
 
         WOLFSSL_LEAVE("DoClientKeyExchange", ret);
+        WOLFSSL_END(WC_FUNC_CLIENT_KEY_EXCHANGE_DO);
 
     #ifdef WOLFSSL_ASYNC_CRYPT
         /* Handle async operation */
         if (ret == WC_PENDING_E) {
-            /* Mark message as not recevied so it can process again */
+            /* Mark message as not received so it can process again */
             ssl->msgsReceived.got_client_key_exchange = 0;
 
@@ -24576,5 +25875,7 @@
 
         /* Cleanup PMS */
+        if (ssl->arrays->preMasterSecret != NULL) {
         ForceZero(ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz);
+        }
         ssl->arrays->preMasterSz = 0;
 
@@ -24586,6 +25887,8 @@
     }
 
-
-#if defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+#endif /* !WOLFSSL_NO_TLS12 */
+
+#if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \
+    defined(WOLFSSL_HAPROXY)
     int SNI_Callback(WOLFSSL* ssl)
     {
@@ -24603,5 +25906,6 @@
         return 0;
     }
-#endif /* HAVE_STUNNEL || WOLGSSL_NGINX */
+#endif /* OPENSSL_ALL || HAVE_STUNNEL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */
+
 #endif /* NO_WOLFSSL_SERVER */
 
@@ -24699,4 +26003,28 @@
 
 
+/* return the max record size */
+int wolfSSL_GetMaxRecordSize(WOLFSSL* ssl, int maxFragment)
+{
+    (void) ssl; /* Avoid compiler warnings */
+
+    if (maxFragment > MAX_RECORD_SIZE) {
+        maxFragment = MAX_RECORD_SIZE;
+    }
+
+#ifdef HAVE_MAX_FRAGMENT
+    if ((ssl->max_fragment != 0) && (maxFragment > ssl->max_fragment)) {
+        maxFragment = ssl->max_fragment;
+    }
+#endif /* HAVE_MAX_FRAGMENT */
+#ifdef WOLFSSL_DTLS
+    if ((ssl->options.dtls) && (maxFragment > MAX_UDP_SIZE)) {
+        maxFragment = MAX_UDP_SIZE;
+    }
+#endif
+
+    return maxFragment;
+}
+
+
 #undef ERROR_OUT
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/keys.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/keys.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/keys.c	(revision 372)
@@ -245,5 +245,5 @@
     switch (ssl->options.cipherSuite) {
 
-#ifdef HAVE_ECC
+#if defined(HAVE_ECC) || defined(HAVE_CURVE25519)
 
 #ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
@@ -260,6 +260,168 @@
         ssl->specs.iv_size               = AES_IV_SIZE;
         ssl->specs.block_size            = AES_BLOCK_SIZE;
+
     break;
 #endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
+    case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha384_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = WC_SHA384_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = AES_256_KEY_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+
+    break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+    case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = WC_SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = AES_128_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+    break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+    case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_triple_des;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = WC_SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = DES3_KEY_SIZE;
+        ssl->specs.block_size            = DES_BLOCK_SIZE;
+        ssl->specs.iv_size               = DES_IV_SIZE;
+
+    break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA
+    case TLS_ECDHE_RSA_WITH_RC4_128_SHA :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_rc4;
+        ssl->specs.cipher_type           = stream;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = WC_SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = RC4_KEY_SIZE;
+        ssl->specs.iv_size               = 0;
+        ssl->specs.block_size            = 0;
+
+    break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+    case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = WC_SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = AES_256_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+    break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+    case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm;
+        ssl->specs.cipher_type           = aead;
+        ssl->specs.mac_algorithm         = sha256_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = WC_SHA256_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = AES_128_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AESGCM_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_GCM_AUTH_SZ;
+
+    break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+    case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm;
+        ssl->specs.cipher_type           = aead;
+        ssl->specs.mac_algorithm         = sha384_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = WC_SHA384_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = AES_256_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AESGCM_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_GCM_AUTH_SZ;
+
+    break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_PSK_WITH_NULL_SHA256
+    case TLS_ECDHE_PSK_WITH_NULL_SHA256 :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_cipher_null;
+        ssl->specs.cipher_type           = stream;
+        ssl->specs.mac_algorithm         = sha256_mac;
+        ssl->specs.kea                   = ecdhe_psk_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = WC_SHA256_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = 0;
+        ssl->specs.block_size            = 0;
+        ssl->specs.iv_size               = 0;
+
+        ssl->options.usingPSK_cipher     = 1;
+        break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256
+    case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha256_mac;
+        ssl->specs.kea                   = ecdhe_psk_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = WC_SHA256_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = AES_128_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        ssl->options.usingPSK_cipher     = 1;
+        break;
+#endif
+
+#endif /* HAVE_ECC || HAVE_CURVE25519 */
+
+#if defined(HAVE_ECC) || (defined(HAVE_CURVE25519) && defined(HAVE_ED25519))
 
 #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
@@ -276,6 +438,203 @@
         ssl->specs.iv_size               = AES_IV_SIZE;
         ssl->specs.block_size            = AES_BLOCK_SIZE;
-    break;
-#endif
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
+    case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha384_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
+        ssl->specs.hash_size             = WC_SHA384_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = AES_256_KEY_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
+    case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_triple_des;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
+        ssl->specs.hash_size             = WC_SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = DES3_KEY_SIZE;
+        ssl->specs.block_size            = DES_BLOCK_SIZE;
+        ssl->specs.iv_size               = DES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
+    case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_rc4;
+        ssl->specs.cipher_type           = stream;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
+        ssl->specs.hash_size             = WC_SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = RC4_KEY_SIZE;
+        ssl->specs.iv_size               = 0;
+        ssl->specs.block_size            = 0;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+    case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
+        ssl->specs.hash_size             = WC_SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = AES_128_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+    case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
+        ssl->specs.hash_size             = WC_SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = AES_256_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+    case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm;
+        ssl->specs.cipher_type           = aead;
+        ssl->specs.mac_algorithm         = sha256_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
+        ssl->specs.hash_size             = WC_SHA256_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = AES_128_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AESGCM_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_GCM_AUTH_SZ;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+    case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm;
+        ssl->specs.cipher_type           = aead;
+        ssl->specs.mac_algorithm         = sha384_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
+        ssl->specs.hash_size             = WC_SHA384_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = AES_256_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AESGCM_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_GCM_AUTH_SZ;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM
+    case TLS_ECDHE_ECDSA_WITH_AES_128_CCM :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_aes_ccm;
+        ssl->specs.cipher_type           = aead;
+        ssl->specs.mac_algorithm         = sha256_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
+        ssl->specs.hash_size             = WC_SHA256_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = AES_128_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AESGCM_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_CCM_16_AUTH_SZ;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
+    case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_aes_ccm;
+        ssl->specs.cipher_type           = aead;
+        ssl->specs.mac_algorithm         = sha256_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
+        ssl->specs.hash_size             = WC_SHA256_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = AES_128_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AESGCM_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_CCM_8_AUTH_SZ;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
+    case TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_aes_ccm;
+        ssl->specs.cipher_type           = aead;
+        ssl->specs.mac_algorithm         = sha256_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
+        ssl->specs.hash_size             = WC_SHA256_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = AES_256_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AESGCM_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_CCM_8_AUTH_SZ;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_NULL_SHA
+    case TLS_ECDHE_ECDSA_WITH_NULL_SHA :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_cipher_null;
+        ssl->specs.cipher_type           = stream;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
+        ssl->specs.hash_size             = WC_SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = 0;
+        ssl->specs.block_size            = 0;
+        ssl->specs.iv_size               = 0;
+
+        break;
+#endif
+
+#endif /* HAVE_ECC || (HAVE_CURVE25519 && HAVE_ED25519) */
+
+#if defined(HAVE_ECC)
 
 #ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
@@ -292,5 +651,6 @@
         ssl->specs.iv_size               = AES_IV_SIZE;
         ssl->specs.block_size            = AES_BLOCK_SIZE;
-    break;
+
+        break;
 #endif
 
@@ -308,37 +668,6 @@
         ssl->specs.iv_size               = AES_IV_SIZE;
         ssl->specs.block_size            = AES_BLOCK_SIZE;
-    break;
-#endif
-
-#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
-    case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 :
-        ssl->specs.bulk_cipher_algorithm = wolfssl_aes;
-        ssl->specs.cipher_type           = block;
-        ssl->specs.mac_algorithm         = sha384_mac;
-        ssl->specs.kea                   = ecc_diffie_hellman_kea;
-        ssl->specs.sig_algo              = rsa_sa_algo;
-        ssl->specs.hash_size             = WC_SHA384_DIGEST_SIZE;
-        ssl->specs.pad_size              = PAD_SHA;
-        ssl->specs.static_ecdh           = 0;
-        ssl->specs.key_size              = AES_256_KEY_SIZE;
-        ssl->specs.iv_size               = AES_IV_SIZE;
-        ssl->specs.block_size            = AES_BLOCK_SIZE;
-    break;
-#endif
-
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
-    case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 :
-        ssl->specs.bulk_cipher_algorithm = wolfssl_aes;
-        ssl->specs.cipher_type           = block;
-        ssl->specs.mac_algorithm         = sha384_mac;
-        ssl->specs.kea                   = ecc_diffie_hellman_kea;
-        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
-        ssl->specs.hash_size             = WC_SHA384_DIGEST_SIZE;
-        ssl->specs.pad_size              = PAD_SHA;
-        ssl->specs.static_ecdh           = 0;
-        ssl->specs.key_size              = AES_256_KEY_SIZE;
-        ssl->specs.iv_size               = AES_IV_SIZE;
-        ssl->specs.block_size            = AES_BLOCK_SIZE;
-    break;
+
+        break;
 #endif
 
@@ -356,5 +685,6 @@
         ssl->specs.iv_size               = AES_IV_SIZE;
         ssl->specs.block_size            = AES_BLOCK_SIZE;
-    break;
+
+        break;
 #endif
 
@@ -372,20 +702,4 @@
         ssl->specs.iv_size               = AES_IV_SIZE;
         ssl->specs.block_size            = AES_BLOCK_SIZE;
-    break;
-#endif
-
-#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
-    case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA :
-        ssl->specs.bulk_cipher_algorithm = wolfssl_aes;
-        ssl->specs.cipher_type           = block;
-        ssl->specs.mac_algorithm         = sha_mac;
-        ssl->specs.kea                   = ecc_diffie_hellman_kea;
-        ssl->specs.sig_algo              = rsa_sa_algo;
-        ssl->specs.hash_size             = WC_SHA_DIGEST_SIZE;
-        ssl->specs.pad_size              = PAD_SHA;
-        ssl->specs.static_ecdh           = 0;
-        ssl->specs.key_size              = AES_128_KEY_SIZE;
-        ssl->specs.block_size            = AES_BLOCK_SIZE;
-        ssl->specs.iv_size               = AES_IV_SIZE;
 
         break;
@@ -405,21 +719,4 @@
         ssl->specs.block_size            = AES_BLOCK_SIZE;
         ssl->specs.iv_size               = AES_IV_SIZE;
-
-        break;
-#endif
-
-#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
-    case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA :
-        ssl->specs.bulk_cipher_algorithm = wolfssl_triple_des;
-        ssl->specs.cipher_type           = block;
-        ssl->specs.mac_algorithm         = sha_mac;
-        ssl->specs.kea                   = ecc_diffie_hellman_kea;
-        ssl->specs.sig_algo              = rsa_sa_algo;
-        ssl->specs.hash_size             = WC_SHA_DIGEST_SIZE;
-        ssl->specs.pad_size              = PAD_SHA;
-        ssl->specs.static_ecdh           = 0;
-        ssl->specs.key_size              = DES3_KEY_SIZE;
-        ssl->specs.block_size            = DES_BLOCK_SIZE;
-        ssl->specs.iv_size               = DES_IV_SIZE;
 
         break;
@@ -443,21 +740,4 @@
 #endif
 
-#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA
-    case TLS_ECDHE_RSA_WITH_RC4_128_SHA :
-        ssl->specs.bulk_cipher_algorithm = wolfssl_rc4;
-        ssl->specs.cipher_type           = stream;
-        ssl->specs.mac_algorithm         = sha_mac;
-        ssl->specs.kea                   = ecc_diffie_hellman_kea;
-        ssl->specs.sig_algo              = rsa_sa_algo;
-        ssl->specs.hash_size             = WC_SHA_DIGEST_SIZE;
-        ssl->specs.pad_size              = PAD_SHA;
-        ssl->specs.static_ecdh           = 0;
-        ssl->specs.key_size              = RC4_KEY_SIZE;
-        ssl->specs.iv_size               = 0;
-        ssl->specs.block_size            = 0;
-
-        break;
-#endif
-
 #ifdef BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA
     case TLS_ECDH_RSA_WITH_RC4_128_SHA :
@@ -477,21 +757,4 @@
 #endif
 
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
-    case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA :
-        ssl->specs.bulk_cipher_algorithm = wolfssl_triple_des;
-        ssl->specs.cipher_type           = block;
-        ssl->specs.mac_algorithm         = sha_mac;
-        ssl->specs.kea                   = ecc_diffie_hellman_kea;
-        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
-        ssl->specs.hash_size             = WC_SHA_DIGEST_SIZE;
-        ssl->specs.pad_size              = PAD_SHA;
-        ssl->specs.static_ecdh           = 0;
-        ssl->specs.key_size              = DES3_KEY_SIZE;
-        ssl->specs.block_size            = DES_BLOCK_SIZE;
-        ssl->specs.iv_size               = DES_IV_SIZE;
-
-        break;
-#endif
-
 #ifdef BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
     case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA :
@@ -511,21 +774,4 @@
 #endif
 
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
-    case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA :
-        ssl->specs.bulk_cipher_algorithm = wolfssl_rc4;
-        ssl->specs.cipher_type           = stream;
-        ssl->specs.mac_algorithm         = sha_mac;
-        ssl->specs.kea                   = ecc_diffie_hellman_kea;
-        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
-        ssl->specs.hash_size             = WC_SHA_DIGEST_SIZE;
-        ssl->specs.pad_size              = PAD_SHA;
-        ssl->specs.static_ecdh           = 0;
-        ssl->specs.key_size              = RC4_KEY_SIZE;
-        ssl->specs.iv_size               = 0;
-        ssl->specs.block_size            = 0;
-
-        break;
-#endif
-
 #ifdef BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA
     case TLS_ECDH_ECDSA_WITH_RC4_128_SHA :
@@ -545,21 +791,4 @@
 #endif
 
-#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
-    case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA :
-        ssl->specs.bulk_cipher_algorithm = wolfssl_aes;
-        ssl->specs.cipher_type           = block;
-        ssl->specs.mac_algorithm         = sha_mac;
-        ssl->specs.kea                   = ecc_diffie_hellman_kea;
-        ssl->specs.sig_algo              = rsa_sa_algo;
-        ssl->specs.hash_size             = WC_SHA_DIGEST_SIZE;
-        ssl->specs.pad_size              = PAD_SHA;
-        ssl->specs.static_ecdh           = 0;
-        ssl->specs.key_size              = AES_256_KEY_SIZE;
-        ssl->specs.block_size            = AES_BLOCK_SIZE;
-        ssl->specs.iv_size               = AES_IV_SIZE;
-
-        break;
-#endif
-
 #ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
     case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA :
@@ -579,21 +808,4 @@
 #endif
 
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
-    case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA :
-        ssl->specs.bulk_cipher_algorithm = wolfssl_aes;
-        ssl->specs.cipher_type           = block;
-        ssl->specs.mac_algorithm         = sha_mac;
-        ssl->specs.kea                   = ecc_diffie_hellman_kea;
-        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
-        ssl->specs.hash_size             = WC_SHA_DIGEST_SIZE;
-        ssl->specs.pad_size              = PAD_SHA;
-        ssl->specs.static_ecdh           = 0;
-        ssl->specs.key_size              = AES_128_KEY_SIZE;
-        ssl->specs.block_size            = AES_BLOCK_SIZE;
-        ssl->specs.iv_size               = AES_IV_SIZE;
-
-        break;
-#endif
-
 #ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
     case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA :
@@ -613,21 +825,4 @@
 #endif
 
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
-    case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA :
-        ssl->specs.bulk_cipher_algorithm = wolfssl_aes;
-        ssl->specs.cipher_type           = block;
-        ssl->specs.mac_algorithm         = sha_mac;
-        ssl->specs.kea                   = ecc_diffie_hellman_kea;
-        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
-        ssl->specs.hash_size             = WC_SHA_DIGEST_SIZE;
-        ssl->specs.pad_size              = PAD_SHA;
-        ssl->specs.static_ecdh           = 0;
-        ssl->specs.key_size              = AES_256_KEY_SIZE;
-        ssl->specs.block_size            = AES_BLOCK_SIZE;
-        ssl->specs.iv_size               = AES_IV_SIZE;
-
-        break;
-#endif
-
 #ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
     case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA :
@@ -647,76 +842,4 @@
 #endif
 
-#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
-    case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 :
-        ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm;
-        ssl->specs.cipher_type           = aead;
-        ssl->specs.mac_algorithm         = sha256_mac;
-        ssl->specs.kea                   = ecc_diffie_hellman_kea;
-        ssl->specs.sig_algo              = rsa_sa_algo;
-        ssl->specs.hash_size             = WC_SHA256_DIGEST_SIZE;
-        ssl->specs.pad_size              = PAD_SHA;
-        ssl->specs.static_ecdh           = 0;
-        ssl->specs.key_size              = AES_128_KEY_SIZE;
-        ssl->specs.block_size            = AES_BLOCK_SIZE;
-        ssl->specs.iv_size               = AESGCM_IMP_IV_SZ;
-        ssl->specs.aead_mac_size         = AES_GCM_AUTH_SZ;
-
-        break;
-#endif
-
-#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
-    case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 :
-        ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm;
-        ssl->specs.cipher_type           = aead;
-        ssl->specs.mac_algorithm         = sha384_mac;
-        ssl->specs.kea                   = ecc_diffie_hellman_kea;
-        ssl->specs.sig_algo              = rsa_sa_algo;
-        ssl->specs.hash_size             = WC_SHA384_DIGEST_SIZE;
-        ssl->specs.pad_size              = PAD_SHA;
-        ssl->specs.static_ecdh           = 0;
-        ssl->specs.key_size              = AES_256_KEY_SIZE;
-        ssl->specs.block_size            = AES_BLOCK_SIZE;
-        ssl->specs.iv_size               = AESGCM_IMP_IV_SZ;
-        ssl->specs.aead_mac_size         = AES_GCM_AUTH_SZ;
-
-        break;
-#endif
-
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
-    case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 :
-        ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm;
-        ssl->specs.cipher_type           = aead;
-        ssl->specs.mac_algorithm         = sha256_mac;
-        ssl->specs.kea                   = ecc_diffie_hellman_kea;
-        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
-        ssl->specs.hash_size             = WC_SHA256_DIGEST_SIZE;
-        ssl->specs.pad_size              = PAD_SHA;
-        ssl->specs.static_ecdh           = 0;
-        ssl->specs.key_size              = AES_128_KEY_SIZE;
-        ssl->specs.block_size            = AES_BLOCK_SIZE;
-        ssl->specs.iv_size               = AESGCM_IMP_IV_SZ;
-        ssl->specs.aead_mac_size         = AES_GCM_AUTH_SZ;
-
-        break;
-#endif
-
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
-    case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 :
-        ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm;
-        ssl->specs.cipher_type           = aead;
-        ssl->specs.mac_algorithm         = sha384_mac;
-        ssl->specs.kea                   = ecc_diffie_hellman_kea;
-        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
-        ssl->specs.hash_size             = WC_SHA384_DIGEST_SIZE;
-        ssl->specs.pad_size              = PAD_SHA;
-        ssl->specs.static_ecdh           = 0;
-        ssl->specs.key_size              = AES_256_KEY_SIZE;
-        ssl->specs.block_size            = AES_BLOCK_SIZE;
-        ssl->specs.iv_size               = AESGCM_IMP_IV_SZ;
-        ssl->specs.aead_mac_size         = AES_GCM_AUTH_SZ;
-
-        break;
-#endif
-
 #ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
     case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 :
@@ -791,110 +914,4 @@
 #endif
 
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM
-    case TLS_ECDHE_ECDSA_WITH_AES_128_CCM :
-        ssl->specs.bulk_cipher_algorithm = wolfssl_aes_ccm;
-        ssl->specs.cipher_type           = aead;
-        ssl->specs.mac_algorithm         = sha256_mac;
-        ssl->specs.kea                   = ecc_diffie_hellman_kea;
-        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
-        ssl->specs.hash_size             = WC_SHA256_DIGEST_SIZE;
-        ssl->specs.pad_size              = PAD_SHA;
-        ssl->specs.static_ecdh           = 0;
-        ssl->specs.key_size              = AES_128_KEY_SIZE;
-        ssl->specs.block_size            = AES_BLOCK_SIZE;
-        ssl->specs.iv_size               = AESGCM_IMP_IV_SZ;
-        ssl->specs.aead_mac_size         = AES_CCM_16_AUTH_SZ;
-
-        break;
-#endif
-
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
-    case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 :
-        ssl->specs.bulk_cipher_algorithm = wolfssl_aes_ccm;
-        ssl->specs.cipher_type           = aead;
-        ssl->specs.mac_algorithm         = sha256_mac;
-        ssl->specs.kea                   = ecc_diffie_hellman_kea;
-        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
-        ssl->specs.hash_size             = WC_SHA256_DIGEST_SIZE;
-        ssl->specs.pad_size              = PAD_SHA;
-        ssl->specs.static_ecdh           = 0;
-        ssl->specs.key_size              = AES_128_KEY_SIZE;
-        ssl->specs.block_size            = AES_BLOCK_SIZE;
-        ssl->specs.iv_size               = AESGCM_IMP_IV_SZ;
-        ssl->specs.aead_mac_size         = AES_CCM_8_AUTH_SZ;
-
-        break;
-#endif
-
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
-    case TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 :
-        ssl->specs.bulk_cipher_algorithm = wolfssl_aes_ccm;
-        ssl->specs.cipher_type           = aead;
-        ssl->specs.mac_algorithm         = sha256_mac;
-        ssl->specs.kea                   = ecc_diffie_hellman_kea;
-        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
-        ssl->specs.hash_size             = WC_SHA256_DIGEST_SIZE;
-        ssl->specs.pad_size              = PAD_SHA;
-        ssl->specs.static_ecdh           = 0;
-        ssl->specs.key_size              = AES_256_KEY_SIZE;
-        ssl->specs.block_size            = AES_BLOCK_SIZE;
-        ssl->specs.iv_size               = AESGCM_IMP_IV_SZ;
-        ssl->specs.aead_mac_size         = AES_CCM_8_AUTH_SZ;
-
-        break;
-#endif
-
-#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_NULL_SHA
-    case TLS_ECDHE_ECDSA_WITH_NULL_SHA :
-        ssl->specs.bulk_cipher_algorithm = wolfssl_cipher_null;
-        ssl->specs.cipher_type           = stream;
-        ssl->specs.mac_algorithm         = sha_mac;
-        ssl->specs.kea                   = ecc_diffie_hellman_kea;
-        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
-        ssl->specs.hash_size             = WC_SHA_DIGEST_SIZE;
-        ssl->specs.pad_size              = PAD_SHA;
-        ssl->specs.static_ecdh           = 0;
-        ssl->specs.key_size              = 0;
-        ssl->specs.block_size            = 0;
-        ssl->specs.iv_size               = 0;
-
-    break;
-#endif
-
-#ifdef BUILD_TLS_ECDHE_PSK_WITH_NULL_SHA256
-    case TLS_ECDHE_PSK_WITH_NULL_SHA256 :
-        ssl->specs.bulk_cipher_algorithm = wolfssl_cipher_null;
-        ssl->specs.cipher_type           = stream;
-        ssl->specs.mac_algorithm         = sha256_mac;
-        ssl->specs.kea                   = ecdhe_psk_kea;
-        ssl->specs.sig_algo              = anonymous_sa_algo;
-        ssl->specs.hash_size             = WC_SHA256_DIGEST_SIZE;
-        ssl->specs.pad_size              = PAD_SHA;
-        ssl->specs.static_ecdh           = 0;
-        ssl->specs.key_size              = 0;
-        ssl->specs.block_size            = 0;
-        ssl->specs.iv_size               = 0;
-
-        ssl->options.usingPSK_cipher     = 1;
-        break;
-#endif
-
-#ifdef BUILD_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256
-    case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 :
-        ssl->specs.bulk_cipher_algorithm = wolfssl_aes;
-        ssl->specs.cipher_type           = block;
-        ssl->specs.mac_algorithm         = sha256_mac;
-        ssl->specs.kea                   = ecdhe_psk_kea;
-        ssl->specs.sig_algo              = anonymous_sa_algo;
-        ssl->specs.hash_size             = WC_SHA256_DIGEST_SIZE;
-        ssl->specs.pad_size              = PAD_SHA;
-        ssl->specs.static_ecdh           = 0;
-        ssl->specs.key_size              = AES_128_KEY_SIZE;
-        ssl->specs.block_size            = AES_BLOCK_SIZE;
-        ssl->specs.iv_size               = AES_IV_SIZE;
-
-        ssl->options.usingPSK_cipher     = 1;
-        break;
-#endif
 #endif /* HAVE_ECC */
 
@@ -1418,4 +1435,23 @@
 #endif
 
+#ifdef BUILD_TLS_DH_anon_WITH_AES_256_GCM_SHA384
+    case TLS_DH_anon_WITH_AES_256_GCM_SHA384:
+        ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm;
+        ssl->specs.cipher_type           = aead;
+        ssl->specs.mac_algorithm         = sha384_mac;
+        ssl->specs.kea                   = diffie_hellman_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = WC_SHA384_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = AES_256_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AESGCM_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_GCM_AUTH_SZ;
+
+         ssl->options.usingAnon_cipher    = 1;
+        break;
+#endif
+
 #ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256
     case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 :
@@ -2107,5 +2143,7 @@
 #ifndef NO_TLS
         ssl->options.tls = 1;
+    #if !defined(WOLFSSL_NO_TLS12) && !defined(WOLFSSL_AEAD_ONLY)
         ssl->hmac = TLS_hmac;
+    #endif
         if (ssl->version.minor >= 2) {
             ssl->options.tls1_1 = 1;
@@ -2116,5 +2154,5 @@
     }
 
-#ifdef WOLFSSL_DTLS
+#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_AEAD_ONLY)
     if (ssl->options.dtls)
         ssl->hmac = TLS_hmac;
@@ -2985,6 +3023,8 @@
 
         if (clientCopy) {
+    #ifndef WOLFSSL_AEAD_ONLY
             XMEMCPY(ssl->keys.client_write_MAC_secret,
-                    keys->client_write_MAC_secret, MAX_DIGEST_SIZE);
+                    keys->client_write_MAC_secret, WC_MAX_DIGEST_SIZE);
+    #endif
             XMEMCPY(ssl->keys.client_write_key,
                     keys->client_write_key, AES_256_KEY_SIZE);
@@ -2992,6 +3032,8 @@
                     keys->client_write_IV, MAX_WRITE_IV_SZ);
         } else {
+    #ifndef WOLFSSL_AEAD_ONLY
             XMEMCPY(ssl->keys.server_write_MAC_secret,
-                    keys->server_write_MAC_secret, MAX_DIGEST_SIZE);
+                    keys->server_write_MAC_secret, WC_MAX_DIGEST_SIZE);
+    #endif
             XMEMCPY(ssl->keys.server_write_key,
                     keys->server_write_key, AES_256_KEY_SIZE);
@@ -3062,6 +3104,8 @@
         if (ssl->specs.cipher_type != aead) {
             sz = ssl->specs.hash_size;
+    #ifndef WOLFSSL_AEAD_ONLY
             XMEMCPY(keys->client_write_MAC_secret,&keyData[i], sz);
             XMEMCPY(keys->server_write_MAC_secret,&keyData[i], sz);
+    #endif
             i += sz;
         }
@@ -3089,9 +3133,13 @@
         sz = ssl->specs.hash_size;
         if (side & PROVISION_CLIENT) {
+    #ifndef WOLFSSL_AEAD_ONLY
             XMEMCPY(keys->client_write_MAC_secret,&keyData[i], sz);
+    #endif
             i += sz;
         }
         if (side & PROVISION_SERVER) {
+    #ifndef WOLFSSL_AEAD_ONLY
             XMEMCPY(keys->server_write_MAC_secret,&keyData[i], sz);
+    #endif
             i += sz;
         }
@@ -3244,4 +3292,7 @@
         ssl->arrays->preMasterSecret[i] = 0;
 
+    XFREE(ssl->arrays->preMasterSecret, ssl->heap, DYNAMIC_TYPE_SECRET);
+    ssl->arrays->preMasterSecret = NULL;
+
     return 0;
 }
@@ -3422,12 +3473,12 @@
 #endif
 
-#ifdef NO_OLD_TLS
+#ifndef NO_OLD_TLS
+    if (ssl->options.tls) return MakeTlsMasterSecret(ssl);
+    return MakeSslMasterSecret(ssl);
+#elif !defined(WOLFSSL_NO_TLS12)
     return MakeTlsMasterSecret(ssl);
-#elif !defined(NO_TLS)
-    if (ssl->options.tls) return MakeTlsMasterSecret(ssl);
-#endif
-
-#ifndef NO_OLD_TLS
-    return MakeSslMasterSecret(ssl);
+#else
+    (void)ssl;
+    return 0;
 #endif
 }
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/ocsp.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/ocsp.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/ocsp.c	(revision 372)
@@ -225,7 +225,9 @@
     else if (*status) {
 #ifndef NO_ASN_TIME
-        if (ValidateDate((*status)->thisDate, (*status)->thisDateFormat, BEFORE)
+        if (XVALIDATE_DATE((*status)->thisDate,
+                                             (*status)->thisDateFormat, BEFORE)
         &&  ((*status)->nextDate[0] != 0)
-        &&  ValidateDate((*status)->nextDate, (*status)->nextDateFormat, AFTER))
+        &&  XVALIDATE_DATE((*status)->nextDate,
+                                             (*status)->nextDateFormat, AFTER))
 #endif
         {
@@ -417,5 +419,5 @@
                                         ssl->ocspIOCtx : ocsp->cm->ocspIOCtx;
 
-#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
     if (ocsp->statusCb != NULL && ssl != NULL) {
         ret = ocsp->statusCb(ssl, ioCtx);
@@ -460,5 +462,5 @@
     }
     if (responseSz == WOLFSSL_CBIO_ERR_WANT_READ) {
-        ret = WANT_READ;
+        ret = OCSP_WANT_READ;
     }
 
@@ -477,5 +479,5 @@
 }
 
-#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
 
 int wolfSSL_OCSP_resp_find_status(WOLFSSL_OCSP_BASICRESP *bs,
@@ -605,4 +607,9 @@
         return WOLFSSL_SUCCESS;
 
+#ifdef OPENSSL_EXTRA
+    if (bs->verifyError != OCSP_VERIFY_ERROR_NONE)
+        return WOLFSSL_FAILURE;
+#endif
+
     InitDecodedCert(&cert, bs->cert, bs->certSz, NULL);
     if (ParseCertRelative(&cert, CERT_TYPE, VERIFY, st->cm) < 0)
@@ -634,5 +641,5 @@
         return NULL;
 
-    if (bio->type == BIO_MEMORY) {
+    if (bio->type == WOLFSSL_BIO_MEMORY) {
         len = wolfSSL_BIO_get_mem_data(bio, &data);
         if (len <= 0 || data == NULL) {
@@ -640,5 +647,6 @@
         }
     }
-    else if (bio->type == BIO_FILE) {
+#ifndef NO_FILESYSTEM
+    else if (bio->type == WOLFSSL_BIO_FILE) {
         long i;
         long l;
@@ -647,11 +655,13 @@
         if (i < 0)
             return NULL;
-        XFSEEK(bio->file, 0, SEEK_END);
+        if(XFSEEK(bio->file, 0, SEEK_END) != 0)
+            return NULL;
         l = XFTELL(bio->file);
         if (l < 0)
             return NULL;
-        XFSEEK(bio->file, i, SEEK_SET);
-
-        /* check calulated length */
+        if (XFSEEK(bio->file, i, SEEK_SET) != 0)
+            return NULL;
+
+        /* check calculated length */
         if (l - i <= 0)
             return NULL;
@@ -664,4 +674,5 @@
         len = wolfSSL_BIO_read(bio, (char *)data, (int)l);
     }
+#endif
     else
         return NULL;
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/sniffer.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/sniffer.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/sniffer.c	(revision 372)
@@ -246,5 +246,6 @@
     /* 81 */
     "Bad Decrypt Size",
-    "Extended Master Secret Hash Error"
+    "Extended Master Secret Hash Error",
+    "Handshake Message Split Across TLS Records"
 };
 
@@ -253,5 +254,6 @@
 static void GetError(int idx, char* str)
 {
-    XSTRNCPY(str, msgTable[idx - 1], MAX_ERROR_LEN);
+    XSTRNCPY(str, msgTable[idx - 1], MAX_ERROR_LEN-1);
+    str[MAX_ERROR_LEN-1] = '\0';
 }
 
@@ -1016,4 +1018,21 @@
 
 
+/* Show SSLInfo if provided and is valid. */
+static void TraceSessionInfo(SSLInfo* sslInfo)
+{
+    if (TraceOn) {
+        if (sslInfo != NULL && sslInfo->isValid) {
+            fprintf(TraceFile,
+                    "\tver:(%u %u) suiteId:(%02x %02x) suiteName:(%s)\n",
+                    sslInfo->protocolVersionMajor,
+                    sslInfo->protocolVersionMinor,
+                    sslInfo->serverCipherSuite0,
+                    sslInfo->serverCipherSuite,
+                    sslInfo->serverCipherSuiteName);
+        }
+    }
+}
+
+
 /* Set user error string */
 static void SetError(int idx, char* error, SnifferSession* session, int fatal)
@@ -1166,5 +1185,5 @@
     file = XFOPEN(keyFile, "rb");
     if (file == XBADFILE) return -1;
-    XFSEEK(file, 0, XSEEK_END);
+    if(XFSEEK(file, 0, XSEEK_END) != 0) return -1;
     fileSz = XFTELL(file);
     XREWIND(file);
@@ -1190,5 +1209,5 @@
         ret = -1;
         if (saveBuf != NULL) {
-            saveBufSz = wolfSSL_KeyPemToDer(loadBuf, (int)fileSz,
+            saveBufSz = wc_KeyPemToDer(loadBuf, (int)fileSz,
                                                 saveBuf, (int)fileSz, password);
             if (saveBufSz < 0) {
@@ -1249,9 +1268,8 @@
 
         namedKey->nameSz = (word32)XSTRLEN(name);
-        XSTRNCPY(namedKey->name, name, sizeof(namedKey->name));
-        if (namedKey->nameSz >= sizeof(namedKey->name)) {
+        if (namedKey->nameSz > sizeof(namedKey->name)-1)
             namedKey->nameSz = sizeof(namedKey->name) - 1;
-            namedKey->name[namedKey->nameSz] = '\0';
-        }
+        XSTRNCPY(namedKey->name, name, namedKey->nameSz);
+        namedKey->name[MAX_SERVER_NAME-1] = '\0';
 
         ret = LoadKeyFile(&namedKey->key, &namedKey->keySz,
@@ -1289,5 +1307,5 @@
         sniffer->port = port;
 
-        sniffer->ctx = SSL_CTX_new(TLSv1_client_method());
+        sniffer->ctx = SSL_CTX_new(TLSv1_2_client_method());
         if (!sniffer->ctx) {
             SetError(MEMORY_STR, error, NULL, 0);
@@ -1302,7 +1320,9 @@
     if (name == NULL) {
         if (password) {
+    #ifdef WOLFSSL_ENCRYPTED_KEYS
             SSL_CTX_set_default_passwd_cb(sniffer->ctx, SetPassword);
             SSL_CTX_set_default_passwd_cb_userdata(
                                                  sniffer->ctx, (void*)password);
+    #endif
         }
         ret = SSL_CTX_use_PrivateKey_file(sniffer->ctx, keyFile, type);
@@ -1829,5 +1849,5 @@
             NamedKey* namedKey;
 
-            if (nameSz >= sizeof(name))
+            if (nameSz > sizeof(name) - 1)
                 nameSz = sizeof(name) - 1;
             name[nameSz] = 0;
@@ -2059,6 +2079,7 @@
 
     if (*sslBytes < size) {
-        SetError(HANDSHAKE_INPUT_STR, error, session, FATAL_ERROR_STATE);
-        return -1;
+        Trace(SPLIT_HANDSHAKE_MSG_STR);
+        *sslBytes = 0;
+        return ret;
     }
 
@@ -3462,7 +3483,40 @@
 
 
+/* Copies the session's infomation to the provided sslInfo. Skip copy if
+ * SSLInfo is not provided. */
+static void CopySessionInfo(SnifferSession* session, SSLInfo* sslInfo)
+{
+    if (NULL != sslInfo) {
+        XMEMSET(sslInfo, 0, sizeof(SSLInfo));
+
+        /* Pass back Session Info after we have processed the Server Hello. */
+        if (0 != session->sslServer->options.cipherSuite) {
+            const char* pCipher;
+
+            sslInfo->isValid = 1;
+            sslInfo->protocolVersionMajor = session->sslServer->version.major;
+            sslInfo->protocolVersionMinor = session->sslServer->version.minor;
+            sslInfo->serverCipherSuite0 =
+                        session->sslServer->options.cipherSuite0;
+            sslInfo->serverCipherSuite =
+                        session->sslServer->options.cipherSuite;
+
+            pCipher = wolfSSL_get_cipher(session->sslServer);
+            if (NULL != pCipher) {
+                XSTRNCPY((char*)sslInfo->serverCipherSuiteName, pCipher,
+                         sizeof(sslInfo->serverCipherSuiteName));
+                sslInfo->serverCipherSuiteName
+                         [sizeof(sslInfo->serverCipherSuiteName) - 1] = '\0';
+            }
+            TraceSessionInfo(sslInfo);
+        }
+    }
+}
+
+
 /* Passes in an IP/TCP packet for decoding (ethernet/localhost frame) removed */
 /* returns Number of bytes on success, 0 for no data yet, and -1 on error */
-int ssl_DecodePacket(const byte* packet, int length, byte** data, char* error)
+static int ssl_DecodePacketInternal(const byte* packet, int length,
+                                    byte** data, SSLInfo* sslInfo, char* error)
 {
     TcpInfo           tcpInfo;
@@ -3497,5 +3551,26 @@
     if (RemoveFatalSession(&ipInfo, &tcpInfo, session, error)) return -1;
     CheckFinCapture(&ipInfo, &tcpInfo, session);
+
+    CopySessionInfo(session, sslInfo);
+
     return ret;
+}
+
+
+/* Passes in an IP/TCP packet for decoding (ethernet/localhost frame) removed */
+/* returns Number of bytes on success, 0 for no data yet, and -1 on error */
+/* Also returns Session Info if available */
+int ssl_DecodePacketWithSessionInfo(const unsigned char* packet, int length,
+    unsigned char** data, SSLInfo* sslInfo, char* error)
+{
+    return ssl_DecodePacketInternal(packet, length, data, sslInfo, error);
+}
+
+
+/* Passes in an IP/TCP packet for decoding (ethernet/localhost frame) removed */
+/* returns Number of bytes on success, 0 for no data yet, and -1 on error */
+int ssl_DecodePacket(const byte* packet, int length, byte** data, char* error)
+{
+    return ssl_DecodePacketInternal(packet, length, data, NULL, error);
 }
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/ssl.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/ssl.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/ssl.c	(revision 372)
@@ -46,22 +46,26 @@
 #ifndef WOLFSSL_ALLOW_NO_SUITES
     #if defined(NO_DH) && !defined(HAVE_ECC) && !defined(WOLFSSL_STATIC_RSA) \
-                  && !defined(WOLFSSL_STATIC_DH) && !defined(WOLFSSL_STATIC_PSK)
+                && !defined(WOLFSSL_STATIC_DH) && !defined(WOLFSSL_STATIC_PSK) \
+                && !defined(HAVE_ED25519)
         #error "No cipher suites defined because DH disabled, ECC disabled, and no static suites defined. Please see top of README"
     #endif
 #endif
 
-#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) || \
-                              defined(WOLFSSL_KEY_GEN)
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \
+        defined(HAVE_WEBSERVER) || defined(WOLFSSL_KEY_GEN)
     #include <wolfssl/openssl/evp.h>
     /* openssl headers end, wolfssl internal headers next */
-    #include <wolfssl/wolfcrypt/wc_encrypt.h>
-#endif
+#endif
+
+#include <wolfssl/wolfcrypt/wc_encrypt.h>
 
 #ifdef OPENSSL_EXTRA
     /* openssl headers begin */
+    #include <wolfssl/openssl/aes.h>
     #include <wolfssl/openssl/hmac.h>
     #include <wolfssl/openssl/crypto.h>
     #include <wolfssl/openssl/des.h>
     #include <wolfssl/openssl/bn.h>
+    #include <wolfssl/openssl/buffer.h>
     #include <wolfssl/openssl/dh.h>
     #include <wolfssl/openssl/rsa.h>
@@ -72,4 +76,5 @@
     #include <wolfssl/openssl/ecdsa.h>
     #include <wolfssl/openssl/ecdh.h>
+    #include <wolfssl/openssl/rc4.h>
     /* openssl headers end, wolfssl internal headers next */
     #include <wolfssl/wolfcrypt/hmac.h>
@@ -82,10 +87,17 @@
     #include <wolfssl/wolfcrypt/curve25519.h>
     #include <wolfssl/wolfcrypt/ed25519.h>
-    #ifdef HAVE_STUNNEL
+    #if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL)
         #include <wolfssl/openssl/ocsp.h>
     #endif /* WITH_STUNNEL */
-    #ifdef WOLFSSL_SHA512
+    #if defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384)
         #include <wolfssl/wolfcrypt/sha512.h>
     #endif
+    #if defined(WOLFCRYPT_HAVE_SRP) && !defined(NO_SHA256) \
+        && !defined(WC_NO_RNG)
+        #include <wolfssl/wolfcrypt/srp.h>
+    #endif
+    #if defined(OPENSSL_ALL) && defined(HAVE_PKCS7)
+        #include <wolfssl/openssl/pkcs7.h>
+    #endif /* OPENSSL_ALL && HAVE_PKCS7 */
 #endif
 
@@ -94,24 +106,4 @@
 #endif
 
-
-#ifndef WOLFSSL_LEANPSK
-char* mystrnstr(const char* s1, const char* s2, unsigned int n)
-{
-    unsigned int s2_len = (unsigned int)XSTRLEN(s2);
-
-    if (s2_len == 0)
-        return (char*)s1;
-
-    while (n >= s2_len && s1[0]) {
-        if (s1[0] == s2[0])
-            if (XMEMCMP(s1, s2, s2_len) == 0)
-                return (char*)s1;
-        s1++;
-        n--;
-    }
-
-    return NULL;
-}
-#endif
 
 #ifdef WOLFSSL_SESSION_EXPORT
@@ -250,5 +242,4 @@
 static wolfSSL_Mutex count_mutex;   /* init ref count mutex */
 
-
 /* Create a new WOLFSSL_CTX struct and return the pointer to created struct.
    WOLFSSL_METHOD pointer passed in is given to ctx to manage.
@@ -260,5 +251,5 @@
     WOLFSSL_CTX* ctx = NULL;
 
-    WOLFSSL_ENTER("WOLFSSL_CTX_new_ex");
+    WOLFSSL_ENTER("wolfSSL_CTX_new_ex");
 
     if (initRefCount == 0) {
@@ -285,4 +276,16 @@
             ctx = NULL;
         }
+#if defined(OPENSSL_EXTRA) && defined(WOLFCRYPT_HAVE_SRP) \
+                           && !defined(NO_SHA256) && !defined(WC_NO_RNG)
+        else {
+            ctx->srp = (Srp*) XMALLOC(sizeof(Srp), heap, DYNAMIC_TYPE_SRP);
+            if (ctx->srp == NULL){
+                WOLFSSL_MSG("Init CTX failed");
+                wolfSSL_CTX_free(ctx);
+                return NULL;
+            }
+            XMEMSET(ctx->srp, 0, sizeof(Srp));
+        }
+#endif
     }
     else {
@@ -290,4 +293,5 @@
         XFREE(method, heap, DYNAMIC_TYPE_METHOD);
     }
+
 
     WOLFSSL_LEAVE("WOLFSSL_CTX_new", 0);
@@ -310,6 +314,20 @@
 {
     WOLFSSL_ENTER("SSL_CTX_free");
-    if (ctx)
+    if (ctx) {
+#if defined(OPENSSL_EXTRA) && defined(WOLFCRYPT_HAVE_SRP) \
+&& !defined(NO_SHA256) && !defined(WC_NO_RNG)
+        if (ctx->srp != NULL){
+            if (ctx->srp_password != NULL){
+                XFREE(ctx->srp_password, ctx->heap, DYNAMIC_TYPE_SRP);
+                ctx->srp_password = NULL;
+            }
+            wc_SrpTerm(ctx->srp);
+            XFREE(ctx->srp, ctx->heap, DYNAMIC_TYPE_SRP);
+            ctx->srp = NULL;
+        }
+#endif
         FreeSSL_Ctx(ctx);
+    }
+
     WOLFSSL_LEAVE("SSL_CTX_free", 0);
 }
@@ -552,4 +570,8 @@
 int wolfSSL_use_old_poly(WOLFSSL* ssl, int value)
 {
+    (void)ssl;
+    (void)value;
+
+#ifndef WOLFSSL_NO_TLS12
     WOLFSSL_ENTER("SSL_use_old_poly");
     WOLFSSL_MSG("Warning SSL connection auto detects old/new and this function"
@@ -557,4 +579,5 @@
     ssl->options.oldPoly = (word16)value;
     WOLFSSL_LEAVE("SSL_use_old_poly", 0);
+#endif
     return 0;
 }
@@ -632,5 +655,5 @@
 char* wolfSSL_get_cipher_list(int priority)
 {
-    const char* const* ciphers = GetCipherNames();
+    const CipherSuiteInfo* ciphers = GetCipherNames();
 
     if (priority >= GetCipherNamesSize() || priority < 0) {
@@ -638,5 +661,5 @@
     }
 
-    return (char*)ciphers[priority];
+    return (char*)ciphers[priority].name;
 }
 
@@ -671,10 +694,8 @@
 int wolfSSL_get_ciphers(char* buf, int len)
 {
-    const char* const* ciphers = GetCipherNames();
-    int  totalInc = 0;
-    int  step     = 0;
-    char delim    = ':';
-    int  size     = GetCipherNamesSize();
+    const CipherSuiteInfo* ciphers = GetCipherNames();
+    int ciphersSz = GetCipherNamesSize();
     int  i;
+    int cipherNameSz;
 
     if (buf == NULL || len <= 0)
@@ -682,17 +703,15 @@
 
     /* Add each member to the buffer delimited by a : */
-    for (i = 0; i < size; i++) {
-        step = (int)(XSTRLEN(ciphers[i]) + 1);  /* delimiter */
-        totalInc += step;
-
-        /* Check to make sure buf is large enough and will not overflow */
-        if (totalInc < len) {
-            XSTRNCPY(buf, ciphers[i], XSTRLEN(ciphers[i]));
-            buf += XSTRLEN(ciphers[i]);
-
-            if (i < size - 1)
-                *buf++ = delim;
-            else
-                *buf++ = '\0';
+    for (i = 0; i < ciphersSz; i++) {
+        cipherNameSz = (int)XSTRLEN(ciphers[i].name);
+        if (cipherNameSz + 1 < len) {
+            XSTRNCPY(buf, ciphers[i].name, len);
+            buf += cipherNameSz;
+
+            if (i < ciphersSz - 1)
+                *buf++ = ':';
+            *buf = 0;
+
+            len -= cipherNameSz + 1;
         }
         else
@@ -709,6 +728,5 @@
         return NULL;
 
-    cipher = wolfSSL_get_cipher_name_from_suite(ssl->options.cipherSuite,
-                                                ssl->options.cipherSuite0);
+    cipher = wolfSSL_get_cipher_name_iana(ssl);
     len = min(len, (int)(XSTRLEN(cipher) + 1));
     XMEMCPY(buf, cipher, len);
@@ -718,15 +736,11 @@
 int wolfSSL_get_fd(const WOLFSSL* ssl)
 {
+    int fd = -1;
     WOLFSSL_ENTER("SSL_get_fd");
-    WOLFSSL_LEAVE("SSL_get_fd", ssl->rfd);
-    return ssl->rfd;
-}
-
-
-int wolfSSL_get_using_nonblock(WOLFSSL* ssl)
-{
-    WOLFSSL_ENTER("wolfSSL_get_using_nonblock");
-    WOLFSSL_LEAVE("wolfSSL_get_using_nonblock", ssl->options.usingNonblock);
-    return ssl->options.usingNonblock;
+    if (ssl) {
+        fd = ssl->rfd;
+}
+    WOLFSSL_LEAVE("SSL_get_fd", fd);
+    return fd;
 }
 
@@ -734,23 +748,26 @@
 int wolfSSL_dtls(WOLFSSL* ssl)
 {
-    return ssl->options.dtls;
+    int dtlsOpt = 0;
+    if (ssl)
+        dtlsOpt = ssl->options.dtls;
+    return dtlsOpt;
 }
 
 
 #ifndef WOLFSSL_LEANPSK
-void wolfSSL_set_using_nonblock(WOLFSSL* ssl, int nonblock)
-{
-    WOLFSSL_ENTER("wolfSSL_set_using_nonblock");
-    ssl->options.usingNonblock = (nonblock != 0);
-}
-
-
 int wolfSSL_dtls_set_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz)
 {
 #ifdef WOLFSSL_DTLS
-    void* sa = (void*)XMALLOC(peerSz, ssl->heap, DYNAMIC_TYPE_SOCKADDR);
+    void* sa;
+
+    if (ssl == NULL)
+        return WOLFSSL_FAILURE;
+
+    sa = (void*)XMALLOC(peerSz, ssl->heap, DYNAMIC_TYPE_SOCKADDR);
     if (sa != NULL) {
-        if (ssl->buffers.dtlsCtx.peer.sa != NULL)
+        if (ssl->buffers.dtlsCtx.peer.sa != NULL) {
             XFREE(ssl->buffers.dtlsCtx.peer.sa,ssl->heap,DYNAMIC_TYPE_SOCKADDR);
+            ssl->buffers.dtlsCtx.peer.sa = NULL;
+        }
         XMEMCPY(sa, peer, peerSz);
         ssl->buffers.dtlsCtx.peer.sa = sa;
@@ -903,5 +920,5 @@
 
 #ifdef WOLFSSL_DTLS
-static INLINE word32 UpdateHighwaterMark(word32 cur, word32 first,
+static WC_INLINE word32 UpdateHighwaterMark(word32 cur, word32 first,
                                          word32 second, word32 max)
 {
@@ -1145,4 +1162,6 @@
 #endif
 
+    (void)ssl;
+
     WOLFSSL_LEAVE("wolfSSL_negotiate", err);
 
@@ -1354,6 +1373,4 @@
 int wolfSSL_GetMaxOutputSize(WOLFSSL* ssl)
 {
-    int maxSize = OUTPUT_RECORD_SIZE;
-
     WOLFSSL_ENTER("wolfSSL_GetMaxOutputSize");
 
@@ -1366,15 +1383,5 @@
     }
 
-#ifdef HAVE_MAX_FRAGMENT
-    maxSize = min(maxSize, ssl->max_fragment);
-#endif
-
-#ifdef WOLFSSL_DTLS
-    if (ssl->options.dtls) {
-        maxSize = min(maxSize, MAX_UDP_SIZE);
-    }
-#endif
-
-    return maxSize;
+    return wolfSSL_GetMaxRecordSize(ssl, OUTPUT_RECORD_SIZE);
 }
 
@@ -1460,16 +1467,23 @@
                     const unsigned char* g, int gSz)
 {
-    word16 havePSK = 0;
-    word16 haveRSA = 1;
-    int    keySz   = 0;
-
     WOLFSSL_ENTER("wolfSSL_SetTmpDH");
-    if (ssl == NULL || p == NULL || g == NULL) return BAD_FUNC_ARG;
+
+    if (ssl == NULL || p == NULL || g == NULL)
+        return BAD_FUNC_ARG;
 
     if (pSz < ssl->options.minDhKeySz)
         return DH_KEY_SIZE_E;
-
-    if (ssl->options.side != WOLFSSL_SERVER_END)
+    if (pSz > ssl->options.maxDhKeySz)
+        return DH_KEY_SIZE_E;
+
+    /* this function is for server only */
+    if (ssl->options.side == WOLFSSL_CLIENT_END)
         return SIDE_ERROR;
+
+    #if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \
+        !defined(HAVE_SELFTEST)
+        ssl->options.dhKeyTested = 0;
+        ssl->options.dhDoKeyTest = 1;
+    #endif
 
     if (ssl->buffers.serverDH_P.buffer && ssl->buffers.weOwnDH) {
@@ -1503,4 +1517,10 @@
 
     ssl->options.haveDH = 1;
+
+    if (ssl->options.side != WOLFSSL_NEITHER_END) {
+        word16 havePSK = 0;
+        word16 haveRSA = 1;
+        int    keySz   = 0;
+
     #ifndef NO_PSK
         havePSK = ssl->options.havePSK;
@@ -1516,8 +1536,32 @@
                ssl->options.haveECDSAsig, ssl->options.haveECC,
                ssl->options.haveStaticECC, ssl->options.side);
+    }
 
     WOLFSSL_LEAVE("wolfSSL_SetTmpDH", 0);
+
     return WOLFSSL_SUCCESS;
 }
+
+
+#if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \
+    !defined(HAVE_SELFTEST)
+/* Enables or disables the session's DH key prime test. */
+int wolfSSL_SetEnableDhKeyTest(WOLFSSL* ssl, int enable)
+{
+    WOLFSSL_ENTER("wolfSSL_SetEnableDhKeyTest");
+
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    if (!enable)
+        ssl->options.dhDoKeyTest = 0;
+    else
+        ssl->options.dhDoKeyTest = 1;
+
+    WOLFSSL_LEAVE("wolfSSL_SetEnableDhKeyTest", WOLFSSL_SUCCESS);
+    return WOLFSSL_SUCCESS;
+}
+#endif
+
 
 /* server ctx Diffie-Hellman parameters, WOLFSSL_SUCCESS on ok */
@@ -1530,7 +1574,36 @@
     if (pSz < ctx->minDhKeySz)
         return DH_KEY_SIZE_E;
+    if (pSz > ctx->maxDhKeySz)
+        return DH_KEY_SIZE_E;
+
+    #if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \
+        !defined(HAVE_SELFTEST)
+    {
+        DhKey checkKey;
+        WC_RNG rng;
+        int error, freeKey = 0;
+
+        error = wc_InitRng(&rng);
+        if (!error)
+            error = wc_InitDhKey(&checkKey);
+        if (!error) {
+            freeKey = 1;
+            error = wc_DhSetCheckKey(&checkKey,
+                                 p, pSz, g, gSz, NULL, 0, 0, &rng);
+        }
+        if (freeKey)
+            wc_FreeDhKey(&checkKey);
+        wc_FreeRng(&rng);
+        if (error)
+            return error;
+
+        ctx->dhKeyTested = 1;
+    }
+    #endif
 
     XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+    ctx->serverDH_P.buffer = NULL;
     XFREE(ctx->serverDH_G.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+    ctx->serverDH_G.buffer = NULL;
 
     ctx->serverDH_P.buffer = (byte*)XMALLOC(pSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
@@ -1541,4 +1614,5 @@
     if (ctx->serverDH_G.buffer == NULL) {
         XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+        ctx->serverDH_P.buffer = NULL;
         return MEMORY_E;
     }
@@ -1577,4 +1651,24 @@
 
 
+int wolfSSL_CTX_SetMaxDhKey_Sz(WOLFSSL_CTX* ctx, word16 keySz)
+{
+    if (ctx == NULL || keySz > 16000 || keySz % 8 != 0)
+        return BAD_FUNC_ARG;
+
+    ctx->maxDhKeySz = keySz / 8;
+    return WOLFSSL_SUCCESS;
+}
+
+
+int wolfSSL_SetMaxDhKey_Sz(WOLFSSL* ssl, word16 keySz)
+{
+    if (ssl == NULL || keySz > 16000 || keySz % 8 != 0)
+        return BAD_FUNC_ARG;
+
+    ssl->options.maxDhKeySz = keySz / 8;
+    return WOLFSSL_SUCCESS;
+}
+
+
 int wolfSSL_GetDhKey_Sz(WOLFSSL* ssl)
 {
@@ -1598,9 +1692,9 @@
 
 #ifdef WOLFSSL_EARLY_DATA
-    if (ssl->earlyData && (ret = wolfSSL_negotiate(ssl)) < 0) {
+    if (ssl->earlyData != no_early_data && (ret = wolfSSL_negotiate(ssl)) < 0) {
         ssl->error = ret;
         return WOLFSSL_FATAL_ERROR;
     }
-    ssl->earlyData = 0;
+    ssl->earlyData = no_early_data;
 #endif
 
@@ -1639,4 +1733,10 @@
 #endif
 
+    #ifdef OPENSSL_EXTRA
+    if (ssl->CBIS != NULL) {
+        ssl->CBIS(ssl, SSL_CB_WRITE, SSL_SUCCESS);
+        ssl->cbmode = SSL_CB_WRITE;
+    }
+    #endif
     ret = SendData(ssl, data, sz);
 
@@ -1679,14 +1779,15 @@
 #endif
 
-    sz = min(sz, OUTPUT_RECORD_SIZE);
-#ifdef HAVE_MAX_FRAGMENT
-    sz = min(sz, ssl->max_fragment);
-#endif
+    sz = wolfSSL_GetMaxRecordSize(ssl, sz);
+
     ret = ReceiveData(ssl, (byte*)data, sz, peek);
 
 #ifdef HAVE_WRITE_DUP
     if (ssl->dupWrite) {
-        if (ssl->error != 0 && ssl->error != WANT_READ &&
-                               ssl->error != WC_PENDING_E) {
+        if (ssl->error != 0 && ssl->error != WANT_READ
+        #ifdef WOLFSSL_ASYNC_CRYPT
+            && ssl->error != WC_PENDING_E
+        #endif
+        ) {
             int notifyErr;
 
@@ -1721,4 +1822,10 @@
     WOLFSSL_ENTER("wolfSSL_read()");
 
+    #ifdef OPENSSL_EXTRA
+    if (ssl->CBIS != NULL) {
+        ssl->CBIS(ssl, SSL_CB_READ, SSL_SUCCESS);
+        ssl->cbmode = SSL_CB_READ;
+    }
+    #endif
     return wolfSSL_read_internal(ssl, data, sz, FALSE);
 }
@@ -1744,8 +1851,7 @@
 #endif /* WOLFSSL_MULTICAST */
 
-#ifdef WOLFSSL_ASYNC_CRYPT
-
-/* let's use async hardware, WOLFSSL_SUCCESS on ok */
-int wolfSSL_UseAsync(WOLFSSL* ssl, int devId)
+
+/* helpers to set the device id, WOLFSSL_SUCCESS on ok */
+int wolfSSL_SetDevId(WOLFSSL* ssl, int devId)
 {
     if (ssl == NULL)
@@ -1756,8 +1862,5 @@
     return WOLFSSL_SUCCESS;
 }
-
-
-/* let's use async hardware, WOLFSSL_SUCCESS on ok */
-int wolfSSL_CTX_UseAsync(WOLFSSL_CTX* ctx, int devId)
+int wolfSSL_CTX_SetDevId(WOLFSSL_CTX* ctx, int devId)
 {
     if (ctx == NULL)
@@ -1768,6 +1871,4 @@
     return WOLFSSL_SUCCESS;
 }
-
-#endif /* WOLFSSL_ASYNC_CRYPT */
 
 /* helpers to get device id and heap */
@@ -1868,4 +1969,24 @@
         return BAD_FUNC_ARG;
 
+#ifdef WOLFSSL_ALLOW_MAX_FRAGMENT_ADJUST
+    /* The following is a non-standard way to reconfigure the max packet size
+        post-handshake for wolfSSL_write/woflSSL_read */
+    if (ssl->options.handShakeState == HANDSHAKE_DONE) {
+        switch (mfl) {
+            case WOLFSSL_MFL_2_8 : ssl->max_fragment =  256; break;
+            case WOLFSSL_MFL_2_9 : ssl->max_fragment =  512; break;
+            case WOLFSSL_MFL_2_10: ssl->max_fragment = 1024; break;
+            case WOLFSSL_MFL_2_11: ssl->max_fragment = 2048; break;
+            case WOLFSSL_MFL_2_12: ssl->max_fragment = 4096; break;
+            case WOLFSSL_MFL_2_13: ssl->max_fragment = 8192; break;
+            default: ssl->max_fragment = MAX_RECORD_SIZE; break;
+        }
+        return WOLFSSL_SUCCESS;
+    }
+#endif /* WOLFSSL_MAX_FRAGMENT_ADJUST */
+
+    /* This call sets the max fragment TLS extension, which gets sent to server.
+        The server_hello response is what sets the `ssl->max_fragment` in
+        TLSX_MFL_Parse */
     return TLSX_UseMaxFragment(&ssl->extensions, mfl, ssl->heap);
 }
@@ -1914,5 +2035,5 @@
 
     return TLSX_UseCertificateStatusRequest(&ssl->extensions, status_type,
-                                                options, ssl->heap, ssl->devId);
+                                          options, NULL, ssl->heap, ssl->devId);
 }
 
@@ -1925,5 +2046,5 @@
 
     return TLSX_UseCertificateStatusRequest(&ctx->extensions, status_type,
-                                                options, ctx->heap, ctx->devId);
+                                          options, NULL, ctx->heap, ctx->devId);
 }
 
@@ -1942,6 +2063,6 @@
 
 
-int wolfSSL_CTX_UseOCSPStaplingV2(WOLFSSL_CTX* ctx,
-                                                 byte status_type, byte options)
+int wolfSSL_CTX_UseOCSPStaplingV2(WOLFSSL_CTX* ctx, byte status_type,
+                                                                   byte options)
 {
     if (ctx == NULL || ctx->method->side != WOLFSSL_CLIENT_END)
@@ -2135,6 +2256,6 @@
     }
 
-    XMEMSET(list, 0, protocol_name_listSz+1);
     XSTRNCPY(list, protocol_name_list, protocol_name_listSz);
+    list[protocol_name_listSz] = '\0';
 
     /* read all protocol name from the list */
@@ -2243,4 +2364,9 @@
         return SECURE_RENEGOTIATION_E;
     }
+
+    /* If the client started the renegotiation, the server will already
+     * have processed the client's hello. */
+    if (ssl->options.side != WOLFSSL_SERVER_END ||
+        ssl->options.acceptState != ACCEPT_FIRST_REPLY_DONE) {
 
     if (ssl->options.handShakeState != HANDSHAKE_DONE) {
@@ -2270,8 +2396,16 @@
     ssl->secure_renegotiation->cache_status = SCR_CACHE_NEEDED;
 
-    ret = InitHandshakeHashes(ssl);
+#if !defined(NO_WOLFSSL_SERVER) && defined(HAVE_SERVER_RENEGOTIATION_INFO)
+        if (ssl->options.side == WOLFSSL_SERVER_END) {
+            ret = SendHelloRequest(ssl);
     if (ret !=0)
         return ret;
-
+        }
+#endif /* NO_WOLFSSL_SERVER && HAVE_SERVER_RENEGOTIATION_INFO */
+
+        ret = InitHandshakeHashes(ssl);
+        if (ret !=0)
+            return ret;
+    }
     ret = wolfSSL_negotiate(ssl);
     return ret;
@@ -2519,4 +2653,7 @@
                 ssl->error = WOLFSSL_ERROR_SYSCALL;   /* simulate OpenSSL behavior */
                 ret = WOLFSSL_SUCCESS;
+            } else if ((ssl->error == WOLFSSL_ERROR_NONE) &&
+                       (ret < WOLFSSL_SUCCESS)) {
+                ret = WOLFSSL_SHUTDOWN_NOT_DONE;
             }
         }
@@ -2606,5 +2743,5 @@
 char* wolfSSL_ERR_error_string(unsigned long errNumber, char* data)
 {
-    static const char* msg = "Please supply a buffer for error string";
+    static const char* const msg = "Please supply a buffer for error string";
 
     WOLFSSL_ENTER("ERR_error_string");
@@ -2716,4 +2853,5 @@
 const byte* wolfSSL_GetMacSecret(WOLFSSL* ssl, int verify)
 {
+#ifndef WOLFSSL_AEAD_ONLY
     if (ssl == NULL)
         return NULL;
@@ -2724,4 +2862,10 @@
     else
         return ssl->keys.server_write_MAC_secret;
+#else
+    (void)ssl;
+    (void)verify;
+
+    return NULL;
+#endif
 }
 
@@ -2904,57 +3048,4 @@
 
 #ifndef NO_CERTS
-int AllocDer(DerBuffer** pDer, word32 length, int type, void* heap)
-{
-    int ret = BAD_FUNC_ARG;
-    if (pDer) {
-        int dynType = 0;
-        DerBuffer* der;
-
-        /* Determine dynamic type */
-        switch (type) {
-            case CA_TYPE:   dynType = DYNAMIC_TYPE_CA;   break;
-            case CERT_TYPE: dynType = DYNAMIC_TYPE_CERT; break;
-            case CRL_TYPE:  dynType = DYNAMIC_TYPE_CRL;  break;
-            case DSA_TYPE:  dynType = DYNAMIC_TYPE_DSA;  break;
-            case ECC_TYPE:  dynType = DYNAMIC_TYPE_ECC;  break;
-            case RSA_TYPE:  dynType = DYNAMIC_TYPE_RSA;  break;
-            default:        dynType = DYNAMIC_TYPE_KEY;  break;
-        }
-
-        /* Setup new buffer */
-        *pDer = (DerBuffer*)XMALLOC(sizeof(DerBuffer) + length, heap, dynType);
-        if (*pDer == NULL) {
-            return MEMORY_ERROR;
-        }
-        XMEMSET(*pDer, 0, sizeof(DerBuffer) + length);
-
-        der = *pDer;
-        der->type = type;
-        der->dynType = dynType; /* Cache this for FreeDer */
-        der->heap = heap;
-        der->buffer = (byte*)der + sizeof(DerBuffer);
-        der->length = length;
-        ret = 0; /* Success */
-    }
-    return ret;
-}
-
-void FreeDer(DerBuffer** pDer)
-{
-    if (pDer && *pDer)
-    {
-        DerBuffer* der = (DerBuffer*)*pDer;
-
-        /* ForceZero private keys */
-        if (der->type == PRIVATEKEY_TYPE) {
-            ForceZero(der->buffer, der->length);
-        }
-        der->buffer = NULL;
-        der->length = 0;
-        XFREE(der, der->heap, der->dynType);
-
-        *pDer = NULL;
-    }
-}
 
 WOLFSSL_CERT_MANAGER* wolfSSL_CTX_GetCertManager(WOLFSSL_CTX* ctx)
@@ -3024,7 +3115,7 @@
                 FreeOCSP(cm->ocsp, 1);
             XFREE(cm->ocspOverrideURL, cm->heap, DYNAMIC_TYPE_URL);
-        #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \
-         || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) \
-         || defined(WOLFSSL_HAPROXY)
+        #if !defined(NO_WOLFSSL_SERVER) && \
+            (defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \
+             defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2))
             if (cm->ocsp_stapling)
                 FreeOCSP(cm->ocsp_stapling, 1);
@@ -3056,5 +3147,5 @@
         return BAD_MUTEX_E;
 
-    FreeSignerTable(cm->caTable, CA_TABLE_SIZE, NULL);
+    FreeSignerTable(cm->caTable, CA_TABLE_SIZE, cm->heap);
 
     wc_UnLockMutex(&cm->caLock);
@@ -3076,5 +3167,5 @@
         return BAD_MUTEX_E;
 
-    FreeTrustedPeerTable(cm->tpTable, TP_TABLE_SIZE, NULL);
+    FreeTrustedPeerTable(cm->tpTable, TP_TABLE_SIZE, cm->heap);
 
     wc_UnLockMutex(&cm->tpLock);
@@ -3085,70 +3176,10 @@
 #endif /* WOLFSSL_TRUST_PEER_CERT */
 
-
-/* Return bytes written to buff or < 0 for error */
-int wolfSSL_CertPemToDer(const unsigned char* pem, int pemSz,
-                        unsigned char* buff, int buffSz, int type)
-{
-    int            eccKey = 0;
-    int            ret;
-    DerBuffer*     der = NULL;
-#ifdef WOLFSSL_SMALL_STACK
-    EncryptedInfo* info = NULL;
-#else
-    EncryptedInfo  info[1];
-#endif
-
-    WOLFSSL_ENTER("wolfSSL_CertPemToDer");
-
-    if (pem == NULL || buff == NULL || buffSz <= 0) {
-        WOLFSSL_MSG("Bad pem der args");
-        return BAD_FUNC_ARG;
-    }
-
-    if (type != CERT_TYPE && type != CA_TYPE && type != CERTREQ_TYPE) {
-        WOLFSSL_MSG("Bad cert type");
-        return BAD_FUNC_ARG;
-    }
-
-#ifdef WOLFSSL_SMALL_STACK
-    info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), NULL,
-                                   DYNAMIC_TYPE_ENCRYPTEDINFO);
-    if (info == NULL)
-        return MEMORY_E;
-#endif
-
-    info->set      = 0;
-    info->ctx      = NULL;
-    info->consumed = 0;
-
-    ret = PemToDer(pem, pemSz, type, &der, NULL, info, &eccKey);
-
-#ifdef WOLFSSL_SMALL_STACK
-    XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO);
-#endif
-
-    if (ret < 0) {
-        WOLFSSL_MSG("Bad Pem To Der");
-    }
-    else {
-        if (der->length <= (word32)buffSz) {
-            XMEMCPY(buff, der->buffer, der->length);
-            ret = der->length;
-        }
-        else {
-            WOLFSSL_MSG("Bad der length");
-            ret = BAD_FUNC_ARG;
-        }
-    }
-
-    FreeDer(&der);
-    return ret;
-}
-
 #endif /* NO_CERTS */
 
-#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
-
-static struct cipher{
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \
+    defined(HAVE_WEBSERVER)
+
+static const struct cipher{
         unsigned char type;
         const char *name;
@@ -3156,15 +3187,33 @@
 
 #ifndef NO_AES
+    #ifdef WOLFSSL_AES_128
     {AES_128_CBC_TYPE, "AES-128-CBC"},
+    #endif
+    #ifdef WOLFSSL_AES_192
     {AES_192_CBC_TYPE, "AES-192-CBC"},
+    #endif
+    #ifdef WOLFSSL_AES_256
     {AES_256_CBC_TYPE, "AES-256-CBC"},
+    #endif
 #if defined(OPENSSL_EXTRA)
+    #ifdef WOLFSSL_AES_128
         {AES_128_CTR_TYPE, "AES-128-CTR"},
+    #endif
+    #ifdef WOLFSSL_AES_192
         {AES_192_CTR_TYPE, "AES-192-CTR"},
+    #endif
+    #ifdef WOLFSSL_AES_256
         {AES_256_CTR_TYPE, "AES-256-CTR"},
-
+    #endif
+
+    #ifdef WOLFSSL_AES_128
         {AES_128_ECB_TYPE, "AES-128-ECB"},
+    #endif
+    #ifdef WOLFSSL_AES_192
         {AES_192_ECB_TYPE, "AES-192-ECB"},
+    #endif
+    #ifdef WOLFSSL_AES_256
         {AES_256_ECB_TYPE, "AES-256-ECB"},
+#endif
 #endif
 
@@ -3177,4 +3226,8 @@
     {DES_EDE3_CBC_TYPE, "DES-EDE3-CBC"},
     {DES_EDE3_ECB_TYPE, "DES-EDE3-ECB"},
+#endif
+
+#ifndef NO_RC4
+    {ARC4_TYPE, "ARC4"},
 #endif
 
@@ -3193,17 +3246,50 @@
     } alias_tbl[] =
     {
+#ifndef NO_DES3
         {"DES-CBC", "DES"},
         {"DES-CBC", "des"},
+        {"DES-ECB", "DES-ECB"},
+        {"DES-ECB", "des-ecb"},
         {"DES-EDE3-CBC", "DES3"},
         {"DES-EDE3-CBC", "des3"},
+        {"DES-EDE3-ECB", "DES-EDE3"},
+        {"DES-EDE3-ECB", "des-ede3"},
         {"DES-EDE3-ECB", "des-ede3-ecb"},
+#endif
+#ifdef HAVE_IDEA
         {"IDEA-CBC", "IDEA"},
         {"IDEA-CBC", "idea"},
-        {"AES-128-CBC", "AES128"},
-        {"AES-128-CBC", "aes128"},
-        {"AES-192-CBC", "AES192"},
-        {"AES-192-CBC", "aes192"},
-        {"AES-256-CBC", "AES256"},
-        {"AES-256-CBC", "aes256"},
+#endif
+#ifndef NO_AES
+    #ifdef HAVE_AES_CBC
+        #ifdef WOLFSSL_AES_128
+        {"AES-128-CBC", "AES128-CBC"},
+        {"AES-128-CBC", "aes128-cbc"},
+        #endif
+        #ifdef WOLFSSL_AES_192
+        {"AES-192-CBC", "AES192-CBC"},
+        {"AES-192-CBC", "aes192-cbc"},
+        #endif
+        #ifdef WOLFSSL_AES_256
+        {"AES-256-CBC", "AES256-CBC"},
+        {"AES-256-CBC", "aes256-cbc"},
+        #endif
+    #endif
+    #ifdef WOLFSSL_AES_128
+        {"AES-128-ECB", "AES128-ECB"},
+        {"AES-128-ECB", "aes128-ecb"},
+    #endif
+    #ifdef WOLFSSL_AES_192
+        {"AES-192-ECB", "AES192-ECB"},
+        {"AES-192-ECB", "aes192-ecb"},
+    #endif
+    #ifdef WOLFSSL_AES_256
+        {"AES-256-ECB", "AES256-ECB"},
+        {"AES-256-EBC", "aes256-ecb"},
+    #endif
+#endif
+#ifndef NO_RC4
+        {"ARC4", "RC4"},
+#endif
         { NULL, NULL}
     };
@@ -3243,22 +3329,46 @@
 #if defined(OPENSSL_EXTRA)
 #ifndef NO_AES
+    #ifdef HAVE_AES_CBC
+        #ifdef WOLFSSL_AES_128
         case NID_aes_128_cbc:
             return wolfSSL_EVP_aes_128_cbc();
+        #endif
+        #ifdef WOLFSSL_AES_192
         case NID_aes_192_cbc:
             return wolfSSL_EVP_aes_192_cbc();
+        #endif
+        #ifdef WOLFSSL_AES_256
         case NID_aes_256_cbc:
             return wolfSSL_EVP_aes_256_cbc();
+        #endif
+    #endif
+    #ifdef WOLFSSL_AES_COUNTER
+        #ifdef WOLFSSL_AES_128
         case NID_aes_128_ctr:
             return wolfSSL_EVP_aes_128_ctr();
+        #endif
+        #ifdef WOLFSSL_AES_192
         case NID_aes_192_ctr:
             return wolfSSL_EVP_aes_192_ctr();
+        #endif
+        #ifdef WOLFSSL_AES_256
         case NID_aes_256_ctr:
             return wolfSSL_EVP_aes_256_ctr();
+        #endif
+    #endif /* WOLFSSL_AES_COUNTER */
+    #ifdef HAVE_AES_ECB
+        #ifdef WOLFSSL_AES_128
         case NID_aes_128_ecb:
             return wolfSSL_EVP_aes_128_ecb();
+        #endif
+        #ifdef WOLFSSL_AES_192
         case NID_aes_192_ecb:
             return wolfSSL_EVP_aes_192_ecb();
+        #endif
+        #ifdef WOLFSSL_AES_256
         case NID_aes_256_ecb:
             return wolfSSL_EVP_aes_256_ecb();
+#endif
+    #endif /* HAVE_AES_ECB */
 #endif
 
@@ -3292,17 +3402,37 @@
 
 #ifndef NO_AES
+    #ifdef HAVE_AES_CBC
+    #ifdef WOLFSSL_AES_128
 static char *EVP_AES_128_CBC;
+    #endif
+    #ifdef WOLFSSL_AES_192
 static char *EVP_AES_192_CBC;
+    #endif
+    #ifdef WOLFSSL_AES_256
 static char *EVP_AES_256_CBC;
+    #endif
+    #endif /* HAVE_AES_CBC */
 #if defined(OPENSSL_EXTRA)
+    #ifdef WOLFSSL_AES_128
     static char *EVP_AES_128_CTR;
+    #endif
+    #ifdef WOLFSSL_AES_192
     static char *EVP_AES_192_CTR;
+    #endif
+    #ifdef WOLFSSL_AES_256
     static char *EVP_AES_256_CTR;
-
+    #endif
+
+    #ifdef WOLFSSL_AES_128
     static char *EVP_AES_128_ECB;
+    #endif
+    #ifdef WOLFSSL_AES_192
     static char *EVP_AES_192_ECB;
+    #endif
+    #ifdef WOLFSSL_AES_256
     static char *EVP_AES_256_ECB;
 #endif
 static const int  EVP_AES_SIZE = 11;
+#endif
 #endif
 
@@ -3310,9 +3440,13 @@
 static char *EVP_DES_CBC;
 static char *EVP_DES_ECB;
-static const int  EVP_DES_SIZE = 7;
 
 static char *EVP_DES_EDE3_CBC;
 static char *EVP_DES_EDE3_ECB;
+
+#ifdef OPENSSL_EXTRA
+static const int  EVP_DES_SIZE = 7;
 static const int  EVP_DES_EDE3_SIZE = 12;
+#endif
+
 #endif
 
@@ -3327,16 +3461,36 @@
 {
 #ifndef NO_AES
+    #ifdef HAVE_AES_CBC
+        #ifdef WOLFSSL_AES_128
     EVP_AES_128_CBC = (char *)EVP_get_cipherbyname("AES-128-CBC");
+        #endif
+        #ifdef WOLFSSL_AES_192
     EVP_AES_192_CBC = (char *)EVP_get_cipherbyname("AES-192-CBC");
+        #endif
+        #ifdef WOLFSSL_AES_256
     EVP_AES_256_CBC = (char *)EVP_get_cipherbyname("AES-256-CBC");
+        #endif
+    #endif /* HAVE_AES_CBC */
 
 #if defined(OPENSSL_EXTRA)
+        #ifdef WOLFSSL_AES_128
         EVP_AES_128_CTR = (char *)EVP_get_cipherbyname("AES-128-CTR");
+        #endif
+        #ifdef WOLFSSL_AES_192
         EVP_AES_192_CTR = (char *)EVP_get_cipherbyname("AES-192-CTR");
+        #endif
+        #ifdef WOLFSSL_AES_256
         EVP_AES_256_CTR = (char *)EVP_get_cipherbyname("AES-256-CTR");
-
+        #endif
+
+        #ifdef WOLFSSL_AES_128
         EVP_AES_128_ECB = (char *)EVP_get_cipherbyname("AES-128-ECB");
+        #endif
+        #ifdef WOLFSSL_AES_192
         EVP_AES_192_ECB = (char *)EVP_get_cipherbyname("AES-192-ECB");
+        #endif
+        #ifdef WOLFSSL_AES_256
         EVP_AES_256_ECB = (char *)EVP_get_cipherbyname("AES-256-ECB");
+#endif
 #endif
 #endif
@@ -3355,102 +3509,10 @@
 }
 
-/* our KeyPemToDer password callback, password in userData */
-static INLINE int OurPasswordCb(char* passwd, int sz, int rw, void* userdata)
-{
-    (void)rw;
-
-    if (userdata == NULL)
-        return 0;
-
-    XSTRNCPY(passwd, (char*)userdata, sz);
-    return min((word32)sz, (word32)XSTRLEN((char*)userdata));
-}
-
-#endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */
-
-#ifndef NO_CERTS
-
-/* Return bytes written to buff or < 0 for error */
-int wolfSSL_KeyPemToDer(const unsigned char* pem, int pemSz,
-                        unsigned char* buff, int buffSz, const char* pass)
-{
-    int            eccKey = 0;
-    int            ret;
-    DerBuffer*     der = NULL;
-#ifdef WOLFSSL_SMALL_STACK
-    EncryptedInfo* info = NULL;
-#else
-    EncryptedInfo  info[1];
-#endif
-
-    WOLFSSL_ENTER("wolfSSL_KeyPemToDer");
-
-    if (pem == NULL || buff == NULL || buffSz <= 0) {
-        WOLFSSL_MSG("Bad pem der args");
-        return BAD_FUNC_ARG;
-    }
-
-#ifdef WOLFSSL_SMALL_STACK
-    info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), NULL,
-                                   DYNAMIC_TYPE_ENCRYPTEDINFO);
-    if (info == NULL)
-        return MEMORY_E;
-#endif
-
-    info->set      = 0;
-    info->ctx      = NULL;
-    info->consumed = 0;
-
-#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
-    if (pass) {
-        info->ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
-        if (info->ctx == NULL) {
-        #ifdef WOLFSSL_SMALL_STACK
-            XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO);
-        #endif
-            return MEMORY_E;
-        }
-
-        wolfSSL_CTX_set_default_passwd_cb(info->ctx, OurPasswordCb);
-        wolfSSL_CTX_set_default_passwd_cb_userdata(info->ctx, (void*)pass);
-    }
-#else
-    (void)pass;
-#endif
-
-    ret = PemToDer(pem, pemSz, PRIVATEKEY_TYPE, &der, NULL, info, &eccKey);
-
-    if (info->ctx)
-        wolfSSL_CTX_free(info->ctx);
-
-#ifdef WOLFSSL_SMALL_STACK
-    XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO);
-#endif
-
-    if (ret < 0) {
-        WOLFSSL_MSG("Bad Pem To Der");
-    }
-    else {
-        if (der->length <= (word32)buffSz) {
-            XMEMCPY(buff, der->buffer, der->length);
-            ret = der->length;
-        }
-        else {
-            WOLFSSL_MSG("Bad der length");
-            ret = BAD_FUNC_ARG;
-        }
-    }
-
-    FreeDer(&der);
-    return ret;
-}
-
-#endif /* !NO_CERTS */
-
+#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL || HAVE_WEBSERVER */
 
 
 #if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM)
 
-void wolfSSL_ERR_print_errors_fp(FILE* fp, int err)
+void wolfSSL_ERR_print_errors_fp(XFILE fp, int err)
 {
     char data[WOLFSSL_MAX_ERROR_SZ + 1];
@@ -3462,5 +3524,5 @@
 
 #if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE)
-void wolfSSL_ERR_dump_errors_fp(FILE* fp)
+void wolfSSL_ERR_dump_errors_fp(XFILE fp)
 {
     wc_ERR_print_errors_fp(fp);
@@ -3546,8 +3608,15 @@
             break;
     #endif
+    #ifndef WOLFSSL_NO_TLS12
         case WOLFSSL_TLSV1_2:
             *minVersion = TLSv1_2_MINOR;
             break;
 #endif
+#endif
+    #ifdef WOLFSSL_TLS13
+        case WOLFSSL_TLSV1_3:
+            *minVersion = TLSv1_3_MINOR;
+            break;
+    #endif
 
         default:
@@ -3587,4 +3656,30 @@
 }
 
+
+/* Function to get version as WOLFSSL_ enum value for wolfSSL_SetVersion */
+int wolfSSL_GetVersion(WOLFSSL* ssl)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    if (ssl->version.major == SSLv3_MAJOR) {
+        switch (ssl->version.minor) {
+            case SSLv3_MINOR :
+                return WOLFSSL_SSLV3;
+            case TLSv1_MINOR :
+                return WOLFSSL_TLSV1;
+            case TLSv1_1_MINOR :
+                return WOLFSSL_TLSV1_1;
+            case TLSv1_2_MINOR :
+                return WOLFSSL_TLSV1_2;
+            case TLSv1_3_MINOR :
+                return WOLFSSL_TLSV1_3;
+            default:
+                break;
+        }
+    }
+
+    return VERSION_ERROR;
+}
 
 int wolfSSL_SetVersion(WOLFSSL* ssl, int version)
@@ -3610,7 +3705,9 @@
 #ifndef NO_TLS
     #ifndef NO_OLD_TLS
+        #ifdef WOLFSSL_ALLOW_TLSV10
         case WOLFSSL_TLSV1:
             ssl->version = MakeTLSv1();
             break;
+        #endif
 
         case WOLFSSL_TLSV1_1:
@@ -3618,7 +3715,15 @@
             break;
     #endif
+    #ifndef WOLFSSL_NO_TLS12
         case WOLFSSL_TLSV1_2:
             ssl->version = MakeTLSv1_2();
             break;
+#endif
+#endif
+#ifdef WOLFSSL_TLS13
+        case WOLFSSL_TLSV1_3:
+            ssl->version = MakeTLSv1_3();
+            break;
+
 #endif
 
@@ -3651,8 +3756,8 @@
 
 /* Make a work from the front of random hash */
-static INLINE word32 MakeWordFromHash(const byte* hashID)
-{
-    return (hashID[0] << 24) | (hashID[1] << 16) | (hashID[2] <<  8) |
-            hashID[3];
+static WC_INLINE word32 MakeWordFromHash(const byte* hashID)
+{
+    return ((word32)hashID[0] << 24) | (hashID[1] << 16) |
+        (hashID[2] <<  8) | hashID[3];
 }
 
@@ -3663,5 +3768,5 @@
 
 /* hash is the SHA digest of name, just use first 32 bits as hash */
-static INLINE word32 HashSigner(const byte* hash)
+static WC_INLINE word32 HashSigner(const byte* hash)
 {
     return MakeWordFromHash(hash) % CA_TABLE_SIZE;
@@ -3709,5 +3814,5 @@
 #ifdef WOLFSSL_TRUST_PEER_CERT
 /* hash is the SHA digest of name, just use first 32 bits as hash */
-static INLINE word32 TrustedPeerHashSigner(const byte* hash)
+static WC_INLINE word32 TrustedPeerHashSigner(const byte* hash)
 {
     return MakeWordFromHash(hash) % TP_TABLE_SIZE;
@@ -4013,5 +4118,5 @@
 {
     int         ret;
-    Signer*     signer = 0;
+    Signer*     signer = NULL;
     word32      row;
     byte*       subjectHash;
@@ -4024,4 +4129,7 @@
 
     WOLFSSL_MSG("Adding a CA");
+
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
 
 #ifdef WOLFSSL_SMALL_STACK
@@ -4101,5 +4209,12 @@
         if (!signer)
             ret = MEMORY_ERROR;
-        else {
+    }
+    if (ret == 0 && signer != NULL) {
+    #ifdef WOLFSSL_SIGNER_DER_CERT
+        ret = AllocDer(&signer->derCert, der->length, der->type, NULL);
+    }
+    if (ret == 0 && signer != NULL) {
+        XMEMCPY(signer->derCert->buffer, der->buffer, der->length);
+    #endif
             signer->keyOID         = cert->keyOID;
             if (cert->pubKeyStored) {
@@ -4152,5 +4267,4 @@
             }
         }
-    }
 
     WOLFSSL_MSG("\tFreeing Parsed CA");
@@ -4275,439 +4389,6 @@
 
 
-#if (defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)) && !defined(NO_CERTS)
-
-/* WOLFSSL_SUCCESS if ok, <= 0 else */
-static int wolfssl_decrypt_buffer_key(DerBuffer* der, byte* password,
-                                      int passwordSz, EncryptedInfo* info)
-{
-    int ret = WOLFSSL_BAD_FILE;
-
-#ifdef WOLFSSL_SMALL_STACK
-    byte* key      = NULL;
-#else
-    byte  key[AES_256_KEY_SIZE];
-#endif
-
-    (void)passwordSz;
-    (void)key;
-
-    WOLFSSL_ENTER("wolfssl_decrypt_buffer_key");
-
-    if (der == NULL || password == NULL || info == NULL) {
-        WOLFSSL_MSG("bad arguments");
-        return WOLFSSL_FATAL_ERROR;
-    }
-
-    /* use file's salt for key derivation, hex decode first */
-    if (Base16_Decode(info->iv, info->ivSz, info->iv, &info->ivSz) != 0) {
-        WOLFSSL_MSG("base16 decode failed");
-        return WOLFSSL_FATAL_ERROR;
-    }
-
-#ifndef NO_MD5
-
-#ifdef WOLFSSL_SMALL_STACK
-    key = (byte*)XMALLOC(AES_256_KEY_SIZE, NULL, DYNAMIC_TYPE_SYMETRIC_KEY);
-    if (key == NULL) {
-        WOLFSSL_MSG("memory failure");
-        return WOLFSSL_FATAL_ERROR;
-    }
-#endif /* WOLFSSL_SMALL_STACK */
-
-    if ((ret = wolfSSL_EVP_BytesToKey(info->name, "MD5", info->iv,
-                              password, passwordSz, 1, key, NULL)) <= 0) {
-        WOLFSSL_MSG("bytes to key failure");
-#ifdef WOLFSSL_SMALL_STACK
-        XFREE(key, NULL, DYNAMIC_TYPE_SYMETRIC_KEY);
-#endif
-        return WOLFSSL_FATAL_ERROR;
-    }
-
-#endif /* NO_MD5 */
-
-#ifndef NO_DES3
-    if (XSTRNCMP(info->name, EVP_DES_CBC, EVP_DES_SIZE) == 0)
-        ret = wc_Des_CbcDecryptWithKey(der->buffer, der->buffer, der->length,
-                                       key, info->iv);
-    else if (XSTRNCMP(info->name, EVP_DES_EDE3_CBC, EVP_DES_EDE3_SIZE) == 0)
-        ret = wc_Des3_CbcDecryptWithKey(der->buffer, der->buffer, der->length,
-                                        key, info->iv);
-#endif /* NO_DES3 */
-#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(HAVE_AES_DECRYPT)
-    if (XSTRNCMP(info->name, EVP_AES_128_CBC, EVP_AES_SIZE) == 0)
-        ret = wc_AesCbcDecryptWithKey(der->buffer, der->buffer, der->length,
-                                      key, AES_128_KEY_SIZE, info->iv);
-    else if (XSTRNCMP(info->name, EVP_AES_192_CBC, EVP_AES_SIZE) == 0)
-        ret = wc_AesCbcDecryptWithKey(der->buffer, der->buffer, der->length,
-                                      key, AES_192_KEY_SIZE, info->iv);
-    else if (XSTRNCMP(info->name, EVP_AES_256_CBC, EVP_AES_SIZE) == 0)
-        ret = wc_AesCbcDecryptWithKey(der->buffer, der->buffer, der->length,
-                                      key, AES_256_KEY_SIZE, info->iv);
-#endif /* !NO_AES && HAVE_AES_CBC && HAVE_AES_DECRYPT */
-
-#ifdef WOLFSSL_SMALL_STACK
-    XFREE(key, NULL, DYNAMIC_TYPE_SYMETRIC_KEY);
-#endif
-
-    if (ret == MP_OKAY)
-        return WOLFSSL_SUCCESS;
-    else if (ret == WOLFSSL_BAD_FILE)
-        return WOLFSSL_BAD_FILE;
-
-    return WOLFSSL_FATAL_ERROR;
-}
-#endif /* defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) */
-
-
-#if defined(WOLFSSL_KEY_GEN) && defined(OPENSSL_EXTRA)
-static int wolfssl_encrypt_buffer_key(byte* der, word32 derSz, byte* password,
-                                      int passwordSz, EncryptedInfo* info)
-{
-    int ret = WOLFSSL_BAD_FILE;
-
-#ifdef WOLFSSL_SMALL_STACK
-    byte* key      = NULL;
-#else
-    byte  key[AES_256_KEY_SIZE];
-#endif
-
-    (void)derSz;
-    (void)passwordSz;
-    (void)key;
-
-    WOLFSSL_ENTER("wolfssl_encrypt_buffer_key");
-
-    if (der == NULL || password == NULL || info == NULL || info->ivSz == 0) {
-        WOLFSSL_MSG("bad arguments");
-        return WOLFSSL_FATAL_ERROR;
-    }
-
-#ifndef NO_MD5
-
-#ifdef WOLFSSL_SMALL_STACK
-    key = (byte*)XMALLOC(AES_256_KEY_SIZE, NULL, DYNAMIC_TYPE_SYMETRIC_KEY);
-    if (key == NULL) {
-        WOLFSSL_MSG("memory failure");
-        return WOLFSSL_FATAL_ERROR;
-    }
-#endif /* WOLFSSL_SMALL_STACK */
-
-    if ((ret = wolfSSL_EVP_BytesToKey(info->name, "MD5", info->iv,
-                              password, passwordSz, 1, key, NULL)) <= 0) {
-        WOLFSSL_MSG("bytes to key failure");
-#ifdef WOLFSSL_SMALL_STACK
-        XFREE(key, NULL, DYNAMIC_TYPE_SYMETRIC_KEY);
-#endif
-        return WOLFSSL_FATAL_ERROR;
-    }
-
-#endif /* NO_MD5 */
-
-    if (ret > 0) {
-        ret = WOLFSSL_BAD_FILE; /* Reset error return */
-#ifndef NO_DES3
-        if (XSTRNCMP(info->name, EVP_DES_CBC, EVP_DES_SIZE) == 0)
-            ret = wc_Des_CbcEncryptWithKey(der, der, derSz, key, info->iv);
-        else if (XSTRNCMP(info->name, EVP_DES_EDE3_CBC, EVP_DES_EDE3_SIZE) == 0)
-            ret = wc_Des3_CbcEncryptWithKey(der, der, derSz, key, info->iv);
-#endif /* NO_DES3 */
-#ifndef NO_AES
-        if (XSTRNCMP(info->name, EVP_AES_128_CBC, EVP_AES_SIZE) == 0)
-            ret = wc_AesCbcEncryptWithKey(der, der, derSz,
-                                          key, AES_128_KEY_SIZE, info->iv);
-        else if (XSTRNCMP(info->name, EVP_AES_192_CBC, EVP_AES_SIZE) == 0)
-            ret = wc_AesCbcEncryptWithKey(der, der, derSz,
-                                          key, AES_192_KEY_SIZE, info->iv);
-        else if (XSTRNCMP(info->name, EVP_AES_256_CBC, EVP_AES_SIZE) == 0)
-            ret = wc_AesCbcEncryptWithKey(der, der, derSz,
-                                          key, AES_256_KEY_SIZE, info->iv);
-#endif /* NO_AES */
-    }
-
-#ifdef WOLFSSL_SMALL_STACK
-    XFREE(key, NULL, DYNAMIC_TYPE_SYMETRIC_KEY);
-#endif
-
-    if (ret == MP_OKAY)
-        return WOLFSSL_SUCCESS;
-    else if (ret == WOLFSSL_BAD_FILE)
-        return WOLFSSL_BAD_FILE;
-
-    return WOLFSSL_FATAL_ERROR;
-}
-#endif /* defined(WOLFSSL_KEY_GEN) */
-
 
 #ifndef NO_CERTS
-
-/* Remove PEM header/footer, convert to ASN1, store any encrypted data
-   info->consumed tracks of PEM bytes consumed in case multiple parts */
-int PemToDer(const unsigned char* buff, long longSz, int type,
-              DerBuffer** pDer, void* heap, EncryptedInfo* info, int* eccKey)
-{
-    const char* header      = NULL;
-    const char* footer      = NULL;
-    char*       headerEnd;
-    char*       footerEnd;
-    char*       consumedEnd;
-    char*       bufferEnd   = (char*)(buff + longSz);
-    long        neededSz;
-    int         ret         = 0;
-    int         sz          = (int)longSz;
-    int         encrypted_key = 0;
-    DerBuffer*  der;
-
-    WOLFSSL_ENTER("PemToDer");
-
-    switch (type) {
-        case CA_TYPE:       /* same as below */
-        case TRUSTED_PEER_TYPE:
-        case CERT_TYPE:      header=BEGIN_CERT;       footer=END_CERT;
-                             break;
-        case CRL_TYPE:       header=BEGIN_X509_CRL;   footer=END_X509_CRL;
-                             break;
-        case DH_PARAM_TYPE:  header=BEGIN_DH_PARAM;   footer=END_DH_PARAM;
-                             break;
-        case DSA_PARAM_TYPE: header=BEGIN_DSA_PARAM;  footer=END_DSA_PARAM;
-                             break;
-        case CERTREQ_TYPE:   header=BEGIN_CERT_REQ;   footer=END_CERT_REQ;
-                             break;
-        case DSA_TYPE:       header=BEGIN_DSA_PRIV;   footer=END_DSA_PRIV;
-                             break;
-        case ECC_TYPE:       header=BEGIN_EC_PRIV;    footer=END_EC_PRIV;
-                             break;
-        case RSA_TYPE:       header=BEGIN_RSA_PRIV;   footer=END_RSA_PRIV;
-                             break;
-        case ED25519_TYPE:   header=BEGIN_EDDSA_PRIV; footer=END_EDDSA_PRIV;
-                             break;
-        case PUBLICKEY_TYPE: header=BEGIN_PUB_KEY;    footer=END_PUB_KEY;
-                             break;
-        default:             header=BEGIN_RSA_PRIV;   footer=END_RSA_PRIV;
-                             break;
-    }
-
-    /* find header */
-    for (;;) {
-        headerEnd = XSTRNSTR((char*)buff, header, sz);
-
-        if (headerEnd || type != PRIVATEKEY_TYPE) {
-            break;
-        } else if (header == BEGIN_RSA_PRIV) {
-                   header =  BEGIN_PRIV_KEY;       footer = END_PRIV_KEY;
-        } else if (header == BEGIN_PRIV_KEY) {
-                   header =  BEGIN_ENC_PRIV_KEY;   footer = END_ENC_PRIV_KEY;
-        } else if (header == BEGIN_ENC_PRIV_KEY) {
-                   header =  BEGIN_EC_PRIV;        footer = END_EC_PRIV;
-        } else if (header == BEGIN_EC_PRIV) {
-                   header =  BEGIN_DSA_PRIV;       footer = END_DSA_PRIV;
-        } else if (header == BEGIN_DSA_PRIV) {
-                   header =  BEGIN_EDDSA_PRIV;     footer = END_EDDSA_PRIV;
-        } else
-            break;
-    }
-
-    if (!headerEnd) {
-        WOLFSSL_MSG("Couldn't find PEM header");
-        return SSL_NO_PEM_HEADER;
-    }
-
-    headerEnd += XSTRLEN(header);
-
-    if ((headerEnd + 1) >= bufferEnd)
-        return WOLFSSL_BAD_FILE;
-
-    /* eat end of line */
-    if (headerEnd[0] == '\n')
-        headerEnd++;
-    else if (headerEnd[1] == '\n')
-        headerEnd += 2;
-    else {
-        if (info)
-            info->consumed = (long)(headerEnd+2 - (char*)buff);
-        return WOLFSSL_BAD_FILE;
-    }
-
-    if (type == PRIVATEKEY_TYPE) {
-        if (eccKey)
-            *eccKey = header == BEGIN_EC_PRIV;
-    }
-
-#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
-    {
-        /* remove encrypted header if there */
-        char   encHeader[] = "Proc-Type";
-        word32 headerEndSz = (word32)(bufferEnd - headerEnd);
-        char*  line        = XSTRNSTR(headerEnd, encHeader, min(headerEndSz,
-                                                                PEM_LINE_LEN));
-        if (line != NULL) {
-            word32 lineSz;
-            char*  finish;
-            word32 finishSz;
-            char*  start;
-            word32 startSz;
-            char*  newline;
-
-            if (line >= bufferEnd) {
-                return WOLFSSL_BAD_FILE;
-            }
-
-            lineSz = (word32)(bufferEnd - line);
-            start = XSTRNSTR(line, "DES", min(lineSz, PEM_LINE_LEN));
-
-            if (start == NULL) {
-                start = XSTRNSTR(line, "AES", min(lineSz, PEM_LINE_LEN));
-            }
-
-            if (start == NULL) return WOLFSSL_BAD_FILE;
-            if (info == NULL)  return WOLFSSL_BAD_FILE;
-
-            if (start >= bufferEnd) {
-                return WOLFSSL_BAD_FILE;
-            }
-
-            startSz = (word32)(bufferEnd - start);
-            finish = XSTRNSTR(start, ",", min(startSz, PEM_LINE_LEN));
-
-            if ((start != NULL) && (finish != NULL) && (start < finish)) {
-                if (finish >= bufferEnd) {
-                    return WOLFSSL_BAD_FILE;
-                }
-
-                finishSz = (word32)(bufferEnd - finish);
-                newline = XSTRNSTR(finish, "\r", min(finishSz, PEM_LINE_LEN));
-
-                if (NAME_SZ < (finish - start)) /* buffer size of info->name*/
-                    return BUFFER_E;
-                if (XMEMCPY(info->name, start, finish - start) == NULL)
-                    return WOLFSSL_FATAL_ERROR;
-                info->name[finish - start] = 0;
-                if (finishSz < sizeof(info->iv) + 1)
-                    return BUFFER_E;
-                if (XMEMCPY(info->iv, finish + 1, sizeof(info->iv)) == NULL)
-                    return WOLFSSL_FATAL_ERROR;
-
-                if (newline == NULL)
-                    newline = XSTRNSTR(finish, "\n", min(finishSz,
-                                                         PEM_LINE_LEN));
-                if ((newline != NULL) && (newline > finish)) {
-                    info->ivSz = (word32)(newline - (finish + 1));
-                    info->set = 1;
-                }
-                else
-                    return WOLFSSL_BAD_FILE;
-            }
-            else
-                return WOLFSSL_BAD_FILE;
-
-            /* eat blank line */
-            while (*newline == '\r' || *newline == '\n')
-                newline++;
-            headerEnd = newline;
-
-            encrypted_key = 1;
-        }
-    }
-#endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */
-
-    /* find footer */
-    footerEnd = XSTRNSTR((char*)buff, footer, sz);
-    if (!footerEnd) {
-        if (info)
-            info->consumed = longSz; /* No more certs if no footer */
-        return WOLFSSL_BAD_FILE;
-    }
-
-    consumedEnd = footerEnd + XSTRLEN(footer);
-
-    if (consumedEnd < bufferEnd) {  /* handle no end of line on last line */
-        /* eat end of line */
-        if (consumedEnd[0] == '\n')
-            consumedEnd++;
-        else if ((consumedEnd + 1 < bufferEnd) && consumedEnd[1] == '\n')
-            consumedEnd += 2;
-        else {
-            if (info)
-                info->consumed = (long)(consumedEnd+2 - (char*)buff);
-            return WOLFSSL_BAD_FILE;
-        }
-    }
-
-    if (info)
-        info->consumed = (long)(consumedEnd - (char*)buff);
-
-    /* set up der buffer */
-    neededSz = (long)(footerEnd - headerEnd);
-    if (neededSz > sz || neededSz <= 0)
-        return WOLFSSL_BAD_FILE;
-
-    ret = AllocDer(pDer, (word32)neededSz, type, heap);
-    if (ret < 0) {
-        return ret;
-    }
-    der = *pDer;
-
-    if (Base64_Decode((byte*)headerEnd, (word32)neededSz,
-                      der->buffer, &der->length) < 0)
-        return WOLFSSL_BAD_FILE;
-
-    if (header == BEGIN_PRIV_KEY && !encrypted_key) {
-        /* pkcs8 key, convert and adjust length */
-        if ((ret = ToTraditional(der->buffer, der->length)) < 0)
-            return ret;
-
-        der->length = ret;
-        return 0;
-    }
-
-#if (defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)) && !defined(NO_PWDBASED)
-    if (encrypted_key || header == BEGIN_ENC_PRIV_KEY) {
-        int   passwordSz;
-    #ifdef WOLFSSL_SMALL_STACK
-        char* password = NULL;
-    #else
-        char  password[80];
-    #endif
-
-        if (!info || !info->ctx || !info->ctx->passwd_cb)
-            return WOLFSSL_BAD_FILE;  /* no callback error */
-
-    #ifdef WOLFSSL_SMALL_STACK
-        password = (char*)XMALLOC(80, heap, DYNAMIC_TYPE_STRING);
-        if (password == NULL)
-            return MEMORY_E;
-    #endif
-        passwordSz = info->ctx->passwd_cb(password, sizeof(password), 0,
-                                          info->ctx->userdata);
-        /* convert and adjust length */
-        if (header == BEGIN_ENC_PRIV_KEY) {
-            ret = ToTraditionalEnc(der->buffer, der->length,
-                                   password, passwordSz);
-    #ifdef WOLFSSL_SMALL_STACK
-            XFREE(password, NULL, DYNAMIC_TYPE_STRING);
-    #endif
-            if (ret < 0) {
-                return ret;
-            }
-
-            der->length = ret;
-        }
-        /* decrypt the key */
-        else {
-            ret = wolfssl_decrypt_buffer_key(der, (byte*)password,
-                                             passwordSz, info);
-    #ifdef WOLFSSL_SMALL_STACK
-            XFREE(password, heap, DYNAMIC_TYPE_STRING);
-    #endif
-            if (ret != WOLFSSL_SUCCESS) {
-                return ret;
-            }
-        }
-    }
-#endif  /* OPENSSL_EXTRA || HAVE_WEBSERVER || NO_PWDBASED */
-
-    return 0;
-}
-
-
 
 /* process user cert chain to pass during the handshake */
@@ -4722,32 +4403,37 @@
 #endif
 
+    if ((type == CA_TYPE) && (ctx == NULL)) {
+        WOLFSSL_MSG("Need context for CA load");
+        return BAD_FUNC_ARG;
+    }
+
     /* we may have a user cert chain, try to consume */
-    if (type == CERT_TYPE && info->consumed < sz) {
-    #ifdef WOLFSSL_SMALL_STACK
+    if ((type == CERT_TYPE || type == CA_TYPE) && (info->consumed < sz)) {
+#ifdef WOLFSSL_SMALL_STACK
         byte   staticBuffer[1];                 /* force heap usage */
-    #else
+#else
         byte   staticBuffer[FILE_BUFFER_SIZE];  /* tmp chain buffer */
-    #endif
+#endif
         byte*  chainBuffer = staticBuffer;
         int    dynamicBuffer = 0;
-        word32 bufferSz = sizeof(staticBuffer);
+        word32 bufferSz;
         long   consumed = info->consumed;
         word32 idx = 0;
         int    gotOne = 0;
 
-        if ( (sz - consumed) > (int)bufferSz) {
+        /* Calculate max possible size, including max headers */
+        bufferSz = (word32)(sz - consumed) + (CERT_HEADER_SZ * MAX_CHAIN_DEPTH);
+        if (bufferSz > sizeof(staticBuffer)) {
             WOLFSSL_MSG("Growing Tmp Chain Buffer");
-            bufferSz = (word32)(sz - consumed);
-                       /* will shrink to actual size */
+            /* will shrink to actual size */
             chainBuffer = (byte*)XMALLOC(bufferSz, heap, DYNAMIC_TYPE_FILE);
             if (chainBuffer == NULL) {
                 return MEMORY_E;
-            }
+    }
             dynamicBuffer = 1;
-        }
+    }
 
         WOLFSSL_MSG("Processing Cert Chain");
         while (consumed < sz) {
-            int eccKey = 0;
             DerBuffer* part = NULL;
             word32 remain = (word32)(sz - consumed);
@@ -4755,7 +4441,11 @@
 
             if (format == WOLFSSL_FILETYPE_PEM) {
+            #ifdef WOLFSSL_PEM_TO_DER
                 ret = PemToDer(buff + consumed, remain, type, &part,
-                               heap, info, &eccKey);
-            }
+                               heap, info, NULL);
+            #else
+                ret = NOT_COMPILED_IN;
+            #endif
+    }
             else {
                 int length = remain;
@@ -4763,8 +4453,9 @@
                     /* get length of der (read sequence) */
                     word32 inOutIdx = 0;
-                    if (GetSequence(buff + consumed, &inOutIdx, &length, remain) < 0) {
-                        ret = SSL_NO_PEM_HEADER;
+                    if (GetSequence(buff + consumed, &inOutIdx, &length,
+                            remain) < 0) {
+                        ret = ASN_NO_PEM_HEADER;
                     }
-                    length += inOutIdx; /* include leading squence */
+                    length += inOutIdx; /* include leading sequence */
                 }
                 info->consumed = length;
@@ -4781,5 +4472,5 @@
                 cnt++;
 #endif
-                if ((idx + part->length) > bufferSz) {
+                if ((idx + part->length + CERT_HEADER_SZ) > bufferSz) {
                     WOLFSSL_MSG("   Cert Chain bigger than buffer");
                     ret = BUFFER_E;
@@ -4793,12 +4484,21 @@
                     if (used)
                         *used += info->consumed;
+    }
+
+                /* add CA's to certificate manager */
+                if (type == CA_TYPE) {
+                    /* verify CA unless user set to no verify */
+                    ret = AddCA(ctx->cm, &part, WOLFSSL_USER_CA,
+                        !ctx->verifyNone);
+                     gotOne = 0; /* don't exit loop for CA type */
                 }
             }
+
             FreeDer(&part);
 
-            if (ret == SSL_NO_PEM_HEADER && gotOne) {
+            if (ret == ASN_NO_PEM_HEADER && gotOne) {
                 WOLFSSL_MSG("We got one good cert, so stuff at end ok");
                 break;
-            }
+}
 
             if (ret < 0) {
@@ -4818,11 +4518,12 @@
                 if (ssl->buffers.weOwnCertChain) {
                     FreeDer(&ssl->buffers.certChain);
-                }
+    }
                 ret = AllocDer(&ssl->buffers.certChain, idx, type, heap);
                 if (ret == 0) {
-                    XMEMCPY(ssl->buffers.certChain->buffer, chainBuffer, idx);
+                    XMEMCPY(ssl->buffers.certChain->buffer, chainBuffer,
+                            idx);
                     ssl->buffers.weOwnCertChain = 1;
-                }
-#ifdef WOLFSSL_TLS13
+    }
+            #ifdef WOLFSSL_TLS13
                 ssl->buffers.certChainCnt = cnt;
 #endif
@@ -4833,9 +4534,9 @@
                     XMEMCPY(ctx->certChain->buffer, chainBuffer, idx);
                 }
-#ifdef WOLFSSL_TLS13
+            #ifdef WOLFSSL_TLS13
                 ctx->certChainCnt = cnt;
-#endif
-            }
-        }
+            #endif
+            }
+    }
 
         if (dynamicBuffer)
@@ -4860,4 +4561,6 @@
     void*         heap = wolfSSL_CTX_GetHeap(ctx, ssl);
     int           devId = wolfSSL_CTX_GetDevId(ctx, ssl);
+    word32        idx;
+    int           keySz = 0;
 #ifdef WOLFSSL_SMALL_STACK
     EncryptedInfo* info = NULL;
@@ -4867,4 +4570,7 @@
 
     (void)rsaKey;
+    (void)devId;
+    (void)idx;
+    (void)keySz;
 
     if (used)
@@ -4887,12 +4593,20 @@
 
     XMEMSET(info, 0, sizeof(EncryptedInfo));
-    info->set      = 0;
-    info->ctx      = ctx;
-    info->consumed = 0;
+#ifdef WOLFSSL_ENCRYPTED_KEYS
+    if (ctx) {
+        info->passwd_cb       = ctx->passwd_cb;
+        info->passwd_userdata = ctx->passwd_userdata;
+    }
+#endif
 
     if (format == WOLFSSL_FILETYPE_PEM) {
+    #ifdef WOLFSSL_PEM_TO_DER
         ret = PemToDer(buff, sz, type, &der, heap, info, &eccKey);
-    }
-    else {  /* ASN1 (DER) or RAW (NTRU) */
+    #else
+        ret = NOT_COMPILED_IN;
+    #endif
+    }
+    else {
+        /* ASN1 (DER) or RAW (NTRU) */
         int length = (int)sz;
         if (format == WOLFSSL_FILETYPE_ASN1) {
@@ -4901,8 +4615,10 @@
             if (GetSequence(buff, &inOutIdx, &length, (word32)sz) < 0) {
                 ret = ASN_PARSE_E;
-            }
-            length += inOutIdx; /* include leading squence */
-        }
+    }
+            length += inOutIdx; /* include leading sequence */
+    }
+
         info->consumed = length;
+
         if (ret == 0) {
             ret = AllocDer(&der, (word32)length, type, heap);
@@ -4910,73 +4626,73 @@
                 XMEMCPY(der->buffer, buff, length);
             }
-        }
-    }
+            }
+            }
 
     if (used) {
         *used = info->consumed;
-    }
+                }
 
     /* process user chain */
     if (ret >= 0) {
+        /* Chain should have server cert first, then intermediates, then root.
+         * First certificate in chain is processed below after ProcessUserChain
+         *   and is loaded into ssl->buffers.certificate.
+         * Remainder are processed using ProcessUserChain and are loaded into
+         *   ssl->buffers.certChain. */
         if (userChain) {
             ret = ProcessUserChain(ctx, buff, sz, format, type, ssl, used, info);
-        }
-    }
-
-    /* check for error */
-    if (ret < 0) {
-    #ifdef WOLFSSL_SMALL_STACK
-        XFREE(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO);
-    #endif
-        FreeDer(&der);
-        return ret;
-    }
-
-#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+                }
+            }
+
+#ifdef WOLFSSL_ENCRYPTED_KEYS
     /* for WOLFSSL_FILETYPE_PEM, PemToDer manage the decryption if required */
-    if (info->set && (format != WOLFSSL_FILETYPE_PEM)) {
+    if (ret >= 0 && info->set && format != WOLFSSL_FILETYPE_PEM) {
         /* decrypt */
-        int   passwordSz;
+        int   passwordSz = NAME_SZ;
 #ifdef WOLFSSL_SMALL_STACK
         char* password = NULL;
 #else
-        char  password[80];
+        char  password[NAME_SZ];
 #endif
 
     #ifdef WOLFSSL_SMALL_STACK
-        password = (char*)XMALLOC(80, heap, DYNAMIC_TYPE_STRING);
+        password = (char*)XMALLOC(passwordSz, heap, DYNAMIC_TYPE_STRING);
         if (password == NULL)
             ret = MEMORY_E;
         else
     #endif
-        if (!ctx || !ctx->passwd_cb) {
+        if (info->passwd_cb == NULL) {
+            WOLFSSL_MSG("No password callback set");
             ret = NO_PASSWORD;
-        }
+    }
         else {
-            passwordSz = ctx->passwd_cb(password, sizeof(password),
-                                        0, ctx->userdata);
-
-            /* decrypt the key */
-            ret = wolfssl_decrypt_buffer_key(der, (byte*)password,
-                                             passwordSz, info);
-        }
+            ret = info->passwd_cb(password, passwordSz, PEM_PASS_READ,
+                info->passwd_userdata);
+            if (ret >= 0) {
+                passwordSz = ret;
+
+                /* decrypt the key */
+                ret = wc_BufferKeyDecrypt(info, der->buffer, der->length,
+                    (byte*)password, passwordSz, WC_MD5);
+
+                ForceZero(password, passwordSz);
+    }
+    }
 
     #ifdef WOLFSSL_SMALL_STACK
         XFREE(password, heap, DYNAMIC_TYPE_STRING);
     #endif
-
-        if (ret != WOLFSSL_SUCCESS) {
-        #ifdef WOLFSSL_SMALL_STACK
-            XFREE(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO);
-        #endif
-            FreeDer(&der);
-            return ret;
-        }
-    }
-#endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */
-
-#ifdef WOLFSSL_SMALL_STACK
+    }
+#endif /* WOLFSSL_ENCRYPTED_KEYS */
+
+    #ifdef WOLFSSL_SMALL_STACK
     XFREE(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO);
-#endif
+    #endif
+
+    /* check for error */
+            if (ret < 0) {
+        FreeDer(&der);
+                return ret;
+            }
 
     /* Handle DER owner */
@@ -4989,5 +4705,5 @@
         /* verify CA unless user set to no verify */
         return AddCA(ctx->cm, &der, WOLFSSL_USER_CA, !ctx->verifyNone);
-    }
+            }
 #ifdef WOLFSSL_TRUST_PEER_CERT
     else if (type == TRUSTED_PEER_TYPE) {
@@ -5006,18 +4722,18 @@
             if (ssl->buffers.weOwnCert) {
                 FreeDer(&ssl->buffers.certificate);
-                #ifdef KEEP_OUR_CERT
-                    FreeX509(ssl->ourCert);
-                    if (ssl->ourCert) {
-                        XFREE(ssl->ourCert, ssl->heap, DYNAMIC_TYPE_X509);
-                        ssl->ourCert = NULL;
-                    }
-                #endif
+            #ifdef KEEP_OUR_CERT
+                FreeX509(ssl->ourCert);
+                if (ssl->ourCert) {
+                    XFREE(ssl->ourCert, ssl->heap, DYNAMIC_TYPE_X509);
+                    ssl->ourCert = NULL;
+}
+#endif
             }
             ssl->buffers.certificate = der;
-            #ifdef KEEP_OUR_CERT
-                ssl->keepCert = 1; /* hold cert for ssl lifetime */
-            #endif
+        #ifdef KEEP_OUR_CERT
+            ssl->keepCert = 1; /* hold cert for ssl lifetime */
+    #endif
             ssl->buffers.weOwnCert = 1;
-        }
+            }
         else if (ctx) {
             FreeDer(&ctx->certificate); /* Make sure previous is free'd */
@@ -5027,11 +4743,11 @@
                     FreeX509(ctx->ourCert);
                     XFREE(ctx->ourCert, ctx->heap, DYNAMIC_TYPE_X509);
-                }
+        }
                 ctx->ourCert = NULL;
             }
         #endif
             ctx->certificate = der;
-        }
-    }
+                    }
+                }
     else if (type == PRIVATEKEY_TYPE) {
         if (ssl) {
@@ -5039,17 +4755,17 @@
             if (ssl->buffers.weOwnKey) {
                 FreeDer(&ssl->buffers.key);
-            }
+                    }
             ssl->buffers.key = der;
             ssl->buffers.weOwnKey = 1;
-        }
+                }
         else if (ctx) {
             FreeDer(&ctx->privateKey);
             ctx->privateKey = der;
-        }
-    }
-    else {
+            }
+                }
+                else {
         FreeDer(&der);
         return WOLFSSL_BAD_CERTTYPE;
-    }
+            }
 
     if (type == PRIVATEKEY_TYPE && format != WOLFSSL_FILETYPE_RAW) {
@@ -5057,5 +4773,4 @@
         if (!eccKey && !ed25519Key) {
             /* make sure RSA key can be used */
-            word32 idx = 0;
         #ifdef WOLFSSL_SMALL_STACK
             RsaKey* key = NULL;
@@ -5072,37 +4787,36 @@
             ret = wc_InitRsaKey_ex(key, heap, devId);
             if (ret == 0) {
+                idx = 0;
                 if (wc_RsaPrivateKeyDecode(der->buffer, &idx, key, der->length)
                     != 0) {
                 #ifdef HAVE_ECC
                     /* could have DER ECC (or pkcs8 ecc), no easy way to tell */
-                    eccKey = 1;  /* so try it out */
+                    eccKey = 1;  /* try it next */
+                #elif defined(HAVE_ED25519)
+                    ed25519Key = 1; /* try it next */
                 #else
                     WOLFSSL_MSG("RSA decode failed and ECC not enabled to try");
                     ret = WOLFSSL_BAD_FILE;
                 #endif
-                } else {
+            }
+                else {
                     /* check that the size of the RSA key is enough */
-                    int rsaSz = wc_RsaEncryptSize((RsaKey*)key);
-
-                    if (ssl) {
-                        if (rsaSz < ssl->options.minRsaKeySz) {
-                            ret = RSA_KEY_SIZE_E;
-                            WOLFSSL_MSG("Private Key size too small");
-                        }
+                    int minRsaSz = ssl ? ssl->options.minRsaKeySz :
+                        ctx->minRsaKeySz;
+                    keySz = wc_RsaEncryptSize((RsaKey*)key);
+                    if (keySz < minRsaSz) {
+                        ret = RSA_KEY_SIZE_E;
+                        WOLFSSL_MSG("Private Key size too small");
+        }
+
+            if (ssl) {
                         ssl->buffers.keyType = rsa_sa_algo;
-                    #ifdef WC_RSA_PSS
-                        ssl->buffers.keySz = rsaSz;
-                    #endif
-                    }
+                        ssl->buffers.keySz = keySz;
+                }
                     else if(ctx) {
-                        if (rsaSz < ctx->minRsaKeySz) {
-                            ret = RSA_KEY_SIZE_E;
-                            WOLFSSL_MSG("Private Key size too small");
-                        }
                         ctx->privateKeyType = rsa_sa_algo;
-                    #ifdef WC_RSA_PSS
-                        ctx->privateKeySz = rsaSz;
-                    #endif
-                    }
+                        ctx->privateKeySz = keySz;
+                }
+
                     rsaKey = 1;
                     (void)rsaKey;  /* for no ecc builds */
@@ -5111,9 +4825,9 @@
                         ssl->options.haveStaticECC = 0;
                         resetSuites = 1;
-                    }
-                }
+            }
+        }
 
                 wc_FreeRsaKey(key);
-            }
+    }
 
         #ifdef WOLFSSL_SMALL_STACK
@@ -5122,32 +4836,34 @@
 
             if (ret != 0)
-                return ret;
-        }
+    return ret;
+}
     #endif
     #ifdef HAVE_ECC
         if (!rsaKey && !ed25519Key) {
             /* make sure ECC key can be used */
-            word32  idx = 0;
-            ecc_key key;
-
-            if (wc_ecc_init_ex(&key, heap, devId) == 0) {
-                if (wc_EccPrivateKeyDecode(der->buffer, &idx, &key,
+#ifdef WOLFSSL_SMALL_STACK
+            ecc_key* key = NULL;
+#else
+            ecc_key  key[1];
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+            key = (ecc_key*)XMALLOC(sizeof(ecc_key), heap, DYNAMIC_TYPE_ECC);
+            if (key == NULL)
+        return MEMORY_E;
+#endif
+
+            if (wc_ecc_init_ex(key, heap, devId) == 0) {
+                idx = 0;
+                if (wc_EccPrivateKeyDecode(der->buffer, &idx, key,
                                                             der->length) == 0) {
-
                     /* check for minimum ECC key size and then free */
-                    if (ssl) {
-                        if (wc_ecc_size(&key) < ssl->options.minEccKeySz) {
-                            wc_ecc_free(&key);
-                            WOLFSSL_MSG("ECC private key too small");
-                            return ECC_KEY_SIZE_E;
-                        }
-                    }
-                    else if (ctx) {
-                        if (wc_ecc_size(&key) < ctx->minEccKeySz) {
-                            wc_ecc_free(&key);
-                            WOLFSSL_MSG("ECC private key too small");
-                            return ECC_KEY_SIZE_E;
-                        }
-                    }
+                    int minKeySz = ssl ? ssl->options.minEccKeySz :
+                                                            ctx->minEccKeySz;
+                    keySz = wc_ecc_size(key);
+                    if (keySz < minKeySz) {
+                        WOLFSSL_MSG("ECC private key too small");
+                        ret = ECC_KEY_SIZE_E;
+            }
 
                     eccKey = 1;
@@ -5155,68 +4871,93 @@
                         ssl->options.haveStaticECC = 1;
                         ssl->buffers.keyType = ecc_dsa_sa_algo;
-                    }
+                        ssl->buffers.keySz = keySz;
+        }
                     else if (ctx) {
                         ctx->haveStaticECC = 1;
                         ctx->privateKeyType = ecc_dsa_sa_algo;
+                        ctx->privateKeySz = keySz;
+    }
+
+                    if (ssl && ssl->options.side == WOLFSSL_SERVER_END) {
+                        resetSuites = 1;
+    }
+        }
+                else
+                    eccKey = 0;
+
+                wc_ecc_free(key);
+    }
+
+    #ifdef WOLFSSL_SMALL_STACK
+            XFREE(key, heap, DYNAMIC_TYPE_ECC);
+    #endif
+
+            if (ret != 0)
+            return ret;
+        }
+    #endif /* HAVE_ECC */
+    #ifdef HAVE_ED25519
+        if (!rsaKey && !eccKey) {
+            /* make sure Ed25519 key can be used */
+        #ifdef WOLFSSL_SMALL_STACK
+            ed25519_key* key = NULL;
+        #else
+            ed25519_key  key[1];
+        #endif
+
+        #ifdef WOLFSSL_SMALL_STACK
+            key = (ed25519_key*)XMALLOC(sizeof(ed25519_key), heap,
+                                                          DYNAMIC_TYPE_ED25519);
+            if (key == NULL)
+                return MEMORY_E;
+        #endif
+
+            ret = wc_ed25519_init(key);
+            if (ret == 0) {
+                idx = 0;
+                if (wc_Ed25519PrivateKeyDecode(der->buffer, &idx, key,
+                                                            der->length) != 0) {
+                    ret = WOLFSSL_BAD_FILE;
+        }
+
+                if (ret == 0) {
+                    /* check for minimum key size and then free */
+                    int minKeySz = ssl ? ssl->options.minEccKeySz :
+                                                               ctx->minEccKeySz;
+                    keySz = ED25519_KEY_SIZE;
+                    if (keySz < minKeySz) {
+                        WOLFSSL_MSG("ED25519 private key too small");
+                        ret = ECC_KEY_SIZE_E;
+                        }
                     }
-
+                if (ret == 0) {
+                    if (ssl) {
+                        ssl->buffers.keyType = ed25519_sa_algo;
+                        ssl->buffers.keySz = keySz;
+                    }
+                    else if (ctx) {
+                        ctx->privateKeyType = ed25519_sa_algo;
+                        ctx->privateKeySz = keySz;
+                    }
+
+                    ed25519Key = 1;
                     if (ssl && ssl->options.side == WOLFSSL_SERVER_END) {
                         resetSuites = 1;
                     }
                 }
-                else
-                    eccKey = 0;
-
-                wc_ecc_free(&key);
-            }
-        }
-    #endif /* HAVE_ECC */
-    #ifdef HAVE_ED25519
-        if (!rsaKey && !eccKey) {
-            /* make sure Ed25519 key can be used */
-            word32      idx = 0;
-            ed25519_key key;
-
-            ret = wc_ed25519_init(&key);
-            if (ret != 0) {
+
+                wc_ed25519_free(key);
+        }
+
+        #ifdef WOLFSSL_SMALL_STACK
+            XFREE(key, heap, DYNAMIC_TYPE_ED25519);
+        #endif
+            if (ret != 0)
                 return ret;
             }
-
-            if (wc_Ed25519PrivateKeyDecode(der->buffer, &idx, &key,
-                                                            der->length) != 0) {
-                wc_ed25519_free(&key);
-                return WOLFSSL_BAD_FILE;
-            }
-
-            /* check for minimum key size and then free */
-            if (ssl) {
-                if (ED25519_KEY_SIZE < ssl->options.minEccKeySz) {
-                    wc_ed25519_free(&key);
-                    WOLFSSL_MSG("ED25519 private key too small");
-                    return ECC_KEY_SIZE_E;
-                }
-                ssl->buffers.keyType = ed25519_sa_algo;
-            }
-            else if (ctx) {
-                if (ED25519_KEY_SIZE < ctx->minEccKeySz) {
-                    wc_ed25519_free(&key);
-                    WOLFSSL_MSG("ED25519 private key too small");
-                    return ECC_KEY_SIZE_E;
-                }
-                ctx->privateKeyType = ed25519_sa_algo;
-            }
-
-            wc_ed25519_free(&key);
-            ed25519Key = 1;
-
-            if (ssl && ssl->options.side == WOLFSSL_SERVER_END) {
-                resetSuites = 1;
-            }
-        }
-    #endif
-
+    #else
         if (!rsaKey && !eccKey && !ed25519Key)
             return WOLFSSL_BAD_FILE;
-
+    #endif
         (void)ed25519Key;
         (void)devId;
@@ -5227,4 +4968,7 @@
     #else
         DecodedCert  cert[1];
+    #endif
+    #ifdef HAVE_PK_CALLBACKS
+        int keyType = 0;
     #endif
 
@@ -5279,5 +5023,5 @@
         }
 
-    #ifdef HAVE_ECC
+    #if defined(HAVE_ECC) || defined(HAVE_ED25519)
         if (ssl) {
             ssl->pkCurveOID = cert->pkCurveOID;
@@ -5316,7 +5060,17 @@
         #ifndef NO_RSA
             case RSAk:
+            #ifdef HAVE_PK_CALLBACKS
+                keyType = rsa_sa_algo;
+            #endif
+                /* Determine RSA key size by parsing public key */
+                idx = 0;
+                ret = wc_RsaPublicKeyDecode_ex(cert->publicKey, &idx,
+                    cert->pubKeySize, NULL, (word32*)&keySz, NULL, NULL);
+                if (ret < 0)
+                    break;
+
                 if (ssl && !ssl->options.verifyNone) {
                     if (ssl->options.minRsaKeySz < 0 ||
-                          cert->pubKeySize < (word16)ssl->options.minRsaKeySz) {
+                          keySz < (int)ssl->options.minRsaKeySz) {
                         ret = RSA_KEY_SIZE_E;
                         WOLFSSL_MSG("Certificate RSA key size too small");
@@ -5325,5 +5079,5 @@
                 else if (ctx && !ctx->verifyNone) {
                     if (ctx->minRsaKeySz < 0 ||
-                                  cert->pubKeySize < (word16)ctx->minRsaKeySz) {
+                                  keySz < (int)ctx->minRsaKeySz) {
                         ret = RSA_KEY_SIZE_E;
                         WOLFSSL_MSG("Certificate RSA key size too small");
@@ -5334,7 +5088,14 @@
         #ifdef HAVE_ECC
             case ECDSAk:
+            #ifdef HAVE_PK_CALLBACKS
+                keyType = ecc_dsa_sa_algo;
+            #endif
+                /* Determine ECC key size based on curve */
+                keySz = wc_ecc_get_curve_size_from_id(
+                    wc_ecc_get_oid(cert->pkCurveOID, NULL, NULL));
+
                 if (ssl && !ssl->options.verifyNone) {
                     if (ssl->options.minEccKeySz < 0 ||
-                          cert->pubKeySize < (word16)ssl->options.minEccKeySz) {
+                          keySz < (int)ssl->options.minEccKeySz) {
                         ret = ECC_KEY_SIZE_E;
                         WOLFSSL_MSG("Certificate ECC key size error");
@@ -5343,5 +5104,5 @@
                 else if (ctx && !ctx->verifyNone) {
                     if (ctx->minEccKeySz < 0 ||
-                                  cert->pubKeySize < (word16)ctx->minEccKeySz) {
+                                  keySz < (int)ctx->minEccKeySz) {
                         ret = ECC_KEY_SIZE_E;
                         WOLFSSL_MSG("Certificate ECC key size error");
@@ -5352,7 +5113,12 @@
         #ifdef HAVE_ED25519
             case ED25519k:
+            #ifdef HAVE_PK_CALLBACKS
+                keyType = ed25519_sa_algo;
+            #endif
+                /* ED25519 is fixed key size */
+                keySz = ED25519_KEY_SIZE;
                 if (ssl && !ssl->options.verifyNone) {
                     if (ssl->options.minEccKeySz < 0 ||
-                          ED25519_KEY_SIZE < (word16)ssl->options.minEccKeySz) {
+                          keySz < (int)ssl->options.minEccKeySz) {
                         ret = ECC_KEY_SIZE_E;
                         WOLFSSL_MSG("Certificate Ed key size error");
@@ -5361,5 +5127,5 @@
                 else if (ctx && !ctx->verifyNone) {
                     if (ctx->minEccKeySz < 0 ||
-                                  ED25519_KEY_SIZE < (word16)ctx->minEccKeySz) {
+                                  keySz < (int)ctx->minEccKeySz) {
                         ret = ECC_KEY_SIZE_E;
                         WOLFSSL_MSG("Certificate ECC key size error");
@@ -5374,4 +5140,15 @@
         }
 
+    #ifdef HAVE_PK_CALLBACKS
+        if (ssl && ssl->buffers.keyType == 0) {
+            ssl->buffers.keyType = keyType;
+            ssl->buffers.keySz = keySz;
+        }
+        else if (ctx && ctx->privateKeyType == 0) {
+            ctx->privateKeyType = keyType;
+            ctx->privateKeySz = keySz;
+        }
+    #endif
+
         FreeDecodedCert(cert);
     #ifdef WOLFSSL_SMALL_STACK
@@ -5396,7 +5173,10 @@
             haveRSA = 1;
         #endif
+        #ifndef NO_CERTS
+            keySz = ssl->buffers.keySz;
+        #endif
 
         /* let's reset suites */
-        InitSuites(ssl->suites, ssl->version, ssl->buffers.keySz, haveRSA,
+        InitSuites(ssl->suites, ssl->version, keySz, haveRSA,
                    havePSK, ssl->options.haveDH, ssl->options.haveNTRU,
                    ssl->options.haveECDSAsig, ssl->options.haveECC,
@@ -5432,5 +5212,5 @@
             if (PemToDer(buff + used, sz - used, CRL_TYPE, &der, NULL, &info,
                          NULL) == 0) {
-                WOLFSSL_MSG("   Proccessed a CRL");
+                WOLFSSL_MSG("   Processed a CRL");
                 wolfSSL_CertManagerLoadCRLBuffer(ctx->cm, der->buffer,
                                                 der->length, WOLFSSL_FILETYPE_ASN1);
@@ -5442,16 +5222,17 @@
 #endif
 #endif
-        if (ret < 0)
-        {
+        if (ret < 0) {
             if(consumed > 0) { /* Made progress in file */
                 WOLFSSL_ERROR(ret);
                 WOLFSSL_MSG("CA Parse failed, with progress in file.");
                 WOLFSSL_MSG("Search for other certs in file");
-            } else {
+            }
+            else {
                 WOLFSSL_MSG("CA Parse failed, no progress in file.");
                 WOLFSSL_MSG("Do not continue search for other certs in file");
                 break;
             }
-        } else {
+        }
+        else {
             WOLFSSL_MSG("   Processed a CA");
             gotOne = 1;
@@ -5460,6 +5241,5 @@
     }
 
-    if(gotOne)
-    {
+    if (gotOne) {
         WOLFSSL_MSG("Processed at least one valid CA. Other stuff OK");
         return WOLFSSL_SUCCESS;
@@ -5469,17 +5249,33 @@
 
 
-static INLINE WOLFSSL_METHOD* cm_pick_method(void)
+static WC_INLINE WOLFSSL_METHOD* cm_pick_method(void)
 {
     #ifndef NO_WOLFSSL_CLIENT
-        #if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS)
+        #if !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_SSLV3)
             return wolfSSLv3_client_method();
+        #elif !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_TLSV10)
+            return wolfTLSv1_client_method();
+        #elif !defined(NO_OLD_TLS)
+            return wolfTLSv1_1_client_method();
+        #elif !defined(WOLFSSL_NO_TLS12)
+            return wolfTLSv1_2_client_method();
+        #elif defined(WOLFSSL_TLS13)
+            return wolfTLSv1_3_client_method();
         #else
-            return wolfTLSv1_2_client_method();
+            return NULL;
         #endif
     #elif !defined(NO_WOLFSSL_SERVER)
-        #if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS)
+        #if !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_SSLV3)
             return wolfSSLv3_server_method();
+        #elif !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_TLSV10)
+            return wolfTLSv1_server_method();
+        #elif !defined(NO_OLD_TLS)
+            return wolfTLSv1_1_server_method();
+        #elif !defined(WOLFSSL_NO_TLS12)
+            return wolfTLSv1_2_server_method();
+        #elif defined(WOLFSSL_TLS13)
+            return wolfTLSv1_3_server_method();
         #else
-            return wolfTLSv1_2_server_method();
+            return NULL;
         #endif
     #else
@@ -5641,41 +5437,21 @@
 
     if (format == WOLFSSL_FILETYPE_PEM) {
-        int eccKey = 0; /* not used */
-    #ifdef WOLFSSL_SMALL_STACK
-        EncryptedInfo* info = NULL;
-    #else
-        EncryptedInfo  info[1];
-    #endif
-
-    #ifdef WOLFSSL_SMALL_STACK
-        info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), cm->heap,
-                                       DYNAMIC_TYPE_ENCRYPTEDINFO);
-        if (info == NULL) {
-            XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT);
-            return MEMORY_E;
-        }
-    #endif
-
-        info->set      = 0;
-        info->ctx      = NULL;
-        info->consumed = 0;
-
-        ret = PemToDer(buff, sz, CERT_TYPE, &der, cm->heap, info, &eccKey);
+#ifdef WOLFSSL_PEM_TO_DER
+        ret = PemToDer(buff, sz, CERT_TYPE, &der, cm->heap, NULL, NULL);
         if (ret != 0) {
             FreeDer(&der);
         #ifdef WOLFSSL_SMALL_STACK
             XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT);
-            XFREE(info, cm->heap, DYNAMIC_TYPE_ENCRYPTEDINFO);
         #endif
             return ret;
         }
         InitDecodedCert(cert, der->buffer, der->length, cm->heap);
-
-    #ifdef WOLFSSL_SMALL_STACK
-        XFREE(info, cm->heap, DYNAMIC_TYPE_ENCRYPTEDINFO);
+#else
+        ret = NOT_COMPILED_IN;
     #endif
     }
-    else
+    else {
         InitDecodedCert(cert, (byte*)buff, (word32)sz, cm->heap);
+    }
 
     if (ret == 0)
@@ -5767,4 +5543,5 @@
 #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \
  || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
+    #ifndef NO_WOLFSSL_SERVER
     if (cm->ocsp_stapling == NULL) {
         cm->ocsp_stapling = (WOLFSSL_OCSP*)XMALLOC(sizeof(WOLFSSL_OCSP),
@@ -5780,5 +5557,4 @@
         }
     }
-    cm->ocspStaplingEnabled = 1;
 
     #ifndef WOLFSSL_USER_IO
@@ -5787,4 +5563,6 @@
         cm->ocspIOCtx = cm->heap;
     #endif /* WOLFSSL_USER_IO */
+    #endif /* NO_WOLFSSL_SERVER */
+    cm->ocspStaplingEnabled = 1;
 #else
     ret = NOT_COMPILED_IN;
@@ -5811,8 +5589,15 @@
     return ret;
 }
-
-
+#if defined(SESSION_CERTS)
+WOLF_STACK_OF(WOLFSSL_X509)* wolfSSL_get_peer_cert_chain(const WOLFSSL* ssl)
+{
+    WOLFSSL_ENTER("wolfSSL_get_peer_cert_chain");
+    if ((ssl == NULL) || (ssl->session.chain.count == 0))
+        return NULL;
+    else
+        return (WOLF_STACK_OF(WOLFSSL_X509)* )&ssl->session.chain;
+}
+#endif
 #ifdef HAVE_OCSP
-
 
 /* check CRL if enabled, WOLFSSL_SUCCESS  */
@@ -6049,5 +5834,8 @@
     file = XFOPEN(fname, "rb");
     if (file == XBADFILE) return WOLFSSL_BAD_FILE;
-    XFSEEK(file, 0, XSEEK_END);
+    if (XFSEEK(file, 0, XSEEK_END) != 0) {
+        XFCLOSE(file);
+        return WOLFSSL_BAD_FILE;
+    }
     sz = XFTELL(file);
     XREWIND(file);
@@ -6089,15 +5877,16 @@
 }
 
-
 /* loads file then loads each file in path, no c_rehash */
-int wolfSSL_CTX_load_verify_locations(WOLFSSL_CTX* ctx, const char* file,
-                                     const char* path)
+int wolfSSL_CTX_load_verify_locations_ex(WOLFSSL_CTX* ctx, const char* file,
+                                     const char* path, word32 flags)
 {
     int ret = WOLFSSL_SUCCESS;
 #ifndef NO_WOLFSSL_DIR
     int fileRet;
-#endif
-
-    WOLFSSL_ENTER("wolfSSL_CTX_load_verify_locations");
+    int successCount = 0;
+    int failCount = 0;
+#endif
+
+    WOLFSSL_MSG("wolfSSL_CTX_load_verify_locations_ex");
 
     if (ctx == NULL || (file == NULL && path == NULL) )
@@ -6123,8 +5912,28 @@
         fileRet = wc_ReadDirFirst(readCtx, path, &name);
         while (fileRet == 0 && name) {
+            WOLFSSL_MSG(name); /* log file name */
             ret = ProcessFile(ctx, name, WOLFSSL_FILETYPE_PEM, CA_TYPE,
                                                           NULL, 0, NULL);
-            if (ret != WOLFSSL_SUCCESS)
-                break;
+            if (ret != WOLFSSL_SUCCESS) {
+                /* handle flags for ignoring errors, skipping expired certs or
+                   by PEM certificate header error */
+                if ( (flags & WOLFSSL_LOAD_FLAG_IGNORE_ERR) ||
+                    ((flags & WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY) &&
+                       (ret == ASN_BEFORE_DATE_E || ret == ASN_AFTER_DATE_E)) ||
+                    ((flags & WOLFSSL_LOAD_FLAG_PEM_CA_ONLY) &&
+                       (ret == ASN_NO_PEM_HEADER))) {
+                    /* Do not fail here if a certificate fails to load,
+                       continue to next file */
+                    ret = WOLFSSL_SUCCESS;
+                }
+                else {
+                    WOLFSSL_ERROR(ret);
+                    WOLFSSL_MSG("Load CA file failed, continuing");
+                    failCount++;
+                }
+            }
+            else {
+                successCount++;
+            }
             fileRet = wc_ReadDirNext(readCtx, path, &name);
         }
@@ -6132,6 +5941,15 @@
 
         /* pass directory read failure to response code */
-        if (ret == WOLFSSL_SUCCESS && fileRet != -1) {
+        if (fileRet != WC_READDIR_NOFILE) {
             ret = fileRet;
+        }
+        /* report failure if no files were loaded or there were failures */
+        else if (successCount == 0 || failCount > 0) {
+            /* use existing error code if exists */
+            if (ret == WOLFSSL_SUCCESS)
+                ret = WOLFSSL_FAILURE;
+        }
+        else {
+            ret = WOLFSSL_SUCCESS;
         }
 
@@ -6141,8 +5959,19 @@
 #else
         ret = NOT_COMPILED_IN;
+        (void)flags;
 #endif
     }
 
     return ret;
+}
+
+#ifndef WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS
+#define WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS WOLFSSL_LOAD_FLAG_NONE
+#endif
+int wolfSSL_CTX_load_verify_locations(WOLFSSL_CTX* ctx, const char* file,
+                                     const char* path)
+{
+    return wolfSSL_CTX_load_verify_locations_ex(ctx, file, path,
+        WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS);
 }
 
@@ -6185,5 +6014,8 @@
 
     if (file == XBADFILE) return WOLFSSL_BAD_FILE;
-    XFSEEK(file, 0, XSEEK_END);
+    if(XFSEEK(file, 0, XSEEK_END) != 0) {
+        XFCLOSE(file);
+        return WOLFSSL_BAD_FILE;
+    }
     sz = XFTELL(file);
     XREWIND(file);
@@ -6252,14 +6084,63 @@
 
 
-
-
-int wolfSSL_CTX_check_private_key(WOLFSSL_CTX* ctx)
-{
-    /* TODO: check private against public for RSA match */
-    (void)ctx;
-    WOLFSSL_ENTER("SSL_CTX_check_private_key");
-    return WOLFSSL_SUCCESS;
-}
-
+/* Check private against public in certificate for match
+ *
+ * ctx  WOLFSSL_CTX structure to check private key in
+ *
+ * Returns SSL_SUCCESS on good private key and SSL_FAILURE if miss matched. */
+int wolfSSL_CTX_check_private_key(const WOLFSSL_CTX* ctx)
+{
+#ifdef WOLFSSL_SMALL_STACK
+    DecodedCert* der = NULL;
+#else
+    DecodedCert  der[1];
+#endif
+    word32 size;
+    byte*  buff;
+    int    ret;
+
+    WOLFSSL_ENTER("wolfSSL_CTX_check_private_key");
+
+    if (ctx == NULL) {
+        return WOLFSSL_FAILURE;
+    }
+
+#ifndef NO_CERTS
+#ifdef WOLFSSL_SMALL_STACK
+    der = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_DCERT);
+    if (der == NULL)
+        return MEMORY_E;
+#endif
+
+    size = ctx->certificate->length;
+    buff = ctx->certificate->buffer;
+    InitDecodedCert(der, buff, size, ctx->heap);
+    if (ParseCertRelative(der, CERT_TYPE, NO_VERIFY, NULL) != 0) {
+        FreeDecodedCert(der);
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(der, NULL, DYNAMIC_TYPE_DCERT);
+    #endif
+        return WOLFSSL_FAILURE;
+}
+
+    size = ctx->privateKey->length;
+    buff = ctx->privateKey->buffer;
+    ret  = wc_CheckPrivateKey(buff, size, der);
+    FreeDecodedCert(der);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(der, NULL, DYNAMIC_TYPE_DCERT);
+#endif
+
+    if (ret == 1) {
+        return WOLFSSL_SUCCESS;
+    }
+    else {
+        return WOLFSSL_FAILURE;
+    }
+#else
+    WOLFSSL_MSG("NO_CERTS is defined, can not check private key");
+    return WOLFSSL_FAILURE;
+#endif
+}
 
 #ifdef HAVE_CRL
@@ -6473,196 +6354,4 @@
 
 
-#ifdef WOLFSSL_CERT_GEN
-
-/* load pem cert from file into der buffer, return der size or error */
-int wolfSSL_PemCertToDer(const char* fileName, unsigned char* derBuf, int derSz)
-{
-#ifdef WOLFSSL_SMALL_STACK
-    EncryptedInfo* info = NULL;
-    byte   staticBuffer[1]; /* force XMALLOC */
-#else
-    EncryptedInfo info[1];
-    byte   staticBuffer[FILE_BUFFER_SIZE];
-#endif
-    byte*  fileBuf = staticBuffer;
-    int    dynamic = 0;
-    int    ret     = 0;
-    int    ecc     = 0;
-    long   sz      = 0;
-    XFILE  file    = XFOPEN(fileName, "rb");
-    DerBuffer* converted = NULL;
-
-    WOLFSSL_ENTER("wolfSSL_PemCertToDer");
-
-    if (file == XBADFILE) {
-        ret = WOLFSSL_BAD_FILE;
-    }
-    else {
-        XFSEEK(file, 0, XSEEK_END);
-        sz = XFTELL(file);
-        XREWIND(file);
-
-        if (sz <= 0) {
-            ret = WOLFSSL_BAD_FILE;
-        }
-        else if (sz > (long)sizeof(staticBuffer)) {
-        #ifdef WOLFSSL_STATIC_MEMORY
-            WOLFSSL_MSG("File was larger then static buffer");
-            return MEMORY_E;
-        #endif
-            fileBuf = (byte*)XMALLOC(sz, 0, DYNAMIC_TYPE_FILE);
-            if (fileBuf == NULL)
-                ret = MEMORY_E;
-            else
-                dynamic = 1;
-        }
-
-        if (ret == 0) {
-            if ( (ret = (int)XFREAD(fileBuf, 1, sz, file)) != sz) {
-                ret = WOLFSSL_BAD_FILE;
-            }
-            else {
-            #ifdef WOLFSSL_SMALL_STACK
-                info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), NULL,
-                                               DYNAMIC_TYPE_ENCRYPTEDINFO);
-                if (info == NULL)
-                    ret = MEMORY_E;
-                else
-            #endif
-                {
-                    ret = PemToDer(fileBuf, sz, CA_TYPE, &converted,
-                                   0, info, &ecc);
-                #ifdef WOLFSSL_SMALL_STACK
-                    XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO);
-                #endif
-                }
-            }
-
-            if (ret == 0) {
-                if (converted->length < (word32)derSz) {
-                    XMEMCPY(derBuf, converted->buffer, converted->length);
-                    ret = converted->length;
-                }
-                else
-                    ret = BUFFER_E;
-            }
-
-            FreeDer(&converted);
-        }
-
-        XFCLOSE(file);
-        if (dynamic)
-            XFREE(fileBuf, 0, DYNAMIC_TYPE_FILE);
-    }
-
-    return ret;
-}
-
-#endif /* WOLFSSL_CERT_GEN */
-
-#ifdef WOLFSSL_CERT_EXT
-#ifndef NO_FILESYSTEM
-/* load pem public key from file into der buffer, return der size or error */
-int wolfSSL_PemPubKeyToDer(const char* fileName,
-                           unsigned char* derBuf, int derSz)
-{
-#ifdef WOLFSSL_SMALL_STACK
-    byte   staticBuffer[1]; /* force XMALLOC */
-#else
-    byte   staticBuffer[FILE_BUFFER_SIZE];
-#endif
-    byte*  fileBuf = staticBuffer;
-    int    dynamic = 0;
-    int    ret     = 0;
-    long   sz      = 0;
-    XFILE  file    = XFOPEN(fileName, "rb");
-    DerBuffer* converted = NULL;
-
-    WOLFSSL_ENTER("wolfSSL_PemPubKeyToDer");
-
-    if (file == XBADFILE) {
-        ret = WOLFSSL_BAD_FILE;
-    }
-    else {
-        XFSEEK(file, 0, XSEEK_END);
-        sz = XFTELL(file);
-        XREWIND(file);
-
-        if (sz <= 0) {
-            ret = WOLFSSL_BAD_FILE;
-        }
-        else if (sz > (long)sizeof(staticBuffer)) {
-        #ifdef WOLFSSL_STATIC_MEMORY
-            WOLFSSL_MSG("File was larger then static buffer");
-            return MEMORY_E;
-        #endif
-            fileBuf = (byte*)XMALLOC(sz, 0, DYNAMIC_TYPE_FILE);
-            if (fileBuf == NULL)
-                ret = MEMORY_E;
-            else
-                dynamic = 1;
-        }
-        if (ret == 0) {
-            if ( (ret = (int)XFREAD(fileBuf, 1, sz, file)) != sz)
-                ret = WOLFSSL_BAD_FILE;
-            else
-                ret = PemToDer(fileBuf, sz, PUBLICKEY_TYPE, &converted,
-                               0, NULL, NULL);
-
-            if (ret == 0) {
-                if (converted->length < (word32)derSz) {
-                    XMEMCPY(derBuf, converted->buffer, converted->length);
-                    ret = converted->length;
-                }
-                else
-                    ret = BUFFER_E;
-            }
-
-            FreeDer(&converted);
-        }
-
-        XFCLOSE(file);
-        if (dynamic)
-            XFREE(fileBuf, 0, DYNAMIC_TYPE_FILE);
-    }
-
-    return ret;
-}
-#endif /* NO_FILESYSTEM */
-
-/* Return bytes written to buff or < 0 for error */
-int wolfSSL_PubKeyPemToDer(const unsigned char* pem, int pemSz,
-                           unsigned char* buff, int buffSz)
-{
-    int ret;
-    DerBuffer* der = NULL;
-
-    WOLFSSL_ENTER("wolfSSL_PubKeyPemToDer");
-
-    if (pem == NULL || buff == NULL || buffSz <= 0) {
-        WOLFSSL_MSG("Bad pem der args");
-        return BAD_FUNC_ARG;
-    }
-
-    ret = PemToDer(pem, pemSz, PUBLICKEY_TYPE, &der, NULL, NULL, NULL);
-    if (ret < 0) {
-        WOLFSSL_MSG("Bad Pem To Der");
-    }
-    else {
-        if (der->length <= (word32)buffSz) {
-            XMEMCPY(buff, der->buffer, der->length);
-            ret = der->length;
-        }
-        else {
-            WOLFSSL_MSG("Bad der length");
-            ret = BAD_FUNC_ARG;
-        }
-    }
-
-    FreeDer(&der);
-    return ret;
-}
-
-#endif /* WOLFSSL_CERT_EXT */
 
 int wolfSSL_CTX_use_certificate_file(WOLFSSL_CTX* ctx, const char* file,
@@ -6674,10 +6363,10 @@
 
     return WOLFSSL_FAILURE;
-}
+    }
 
 
 int wolfSSL_CTX_use_PrivateKey_file(WOLFSSL_CTX* ctx, const char* file,
                                     int format)
-{
+                {
     WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_file");
     if (ProcessFile(ctx, file, format, PRIVATEKEY_TYPE, NULL, 0, NULL)
@@ -6686,4 +6375,22 @@
 
     return WOLFSSL_FAILURE;
+            }
+
+
+/* Sets the max chain depth when verifying a certificate chain. Default depth
+ * is set to MAX_CHAIN_DEPTH.
+ *
+ * ctx   WOLFSSL_CTX structure to set depth in
+ * depth max depth
+ */
+void wolfSSL_CTX_set_verify_depth(WOLFSSL_CTX *ctx, int depth) {
+    WOLFSSL_ENTER("wolfSSL_CTX_set_verify_depth");
+
+    if (ctx == NULL || depth < 0 || depth > MAX_CHAIN_DEPTH) {
+        WOLFSSL_MSG("Bad depth argument, too large or less than 0");
+        return;
+    }
+
+    ctx->verifyDepth = (byte)depth;
 }
 
@@ -6700,5 +6407,5 @@
     return ssl->options.verifyDepth;
 #endif
-}
+    }
 
 
@@ -6708,11 +6415,11 @@
     if(ctx == NULL) {
         return BAD_FUNC_ARG;
-    }
+        }
 #ifndef OPENSSL_EXTRA
     return MAX_CHAIN_DEPTH;
 #else
     return ctx->verifyDepth;
-#endif
-}
+        #endif
+        }
 
 
@@ -6722,4 +6429,17 @@
    WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_file");
    if (ProcessFile(ctx, file, WOLFSSL_FILETYPE_PEM,CERT_TYPE,NULL,1, NULL)
+                    == WOLFSSL_SUCCESS)
+        return WOLFSSL_SUCCESS;
+
+    return WOLFSSL_FAILURE;
+}
+
+
+int wolfSSL_CTX_use_certificate_chain_file_format(WOLFSSL_CTX* ctx,
+                                                  const char* file, int format)
+{
+   /* process up to MAX_CHAIN_DEPTH plus subject cert */
+   WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_file_format");
+   if (ProcessFile(ctx, file, format, CERT_TYPE, NULL, 1, NULL)
                    == WOLFSSL_SUCCESS)
        return WOLFSSL_SUCCESS;
@@ -6751,5 +6471,8 @@
     file = XFOPEN(fname, "rb");
     if (file == XBADFILE) return WOLFSSL_BAD_FILE;
-    XFSEEK(file, 0, XSEEK_END);
+    if(XFSEEK(file, 0, XSEEK_END) != 0) {
+        XFCLOSE(file);
+        return WOLFSSL_BAD_FILE;
+    }
     sz = XFTELL(file);
     XREWIND(file);
@@ -6803,47 +6526,435 @@
 #endif /* NO_DH */
 
+#endif /* NO_FILESYSTEM */
+
+
+#if defined(OPENSSL_EXTRA) || !defined(NO_PWDBASED) && \
+    (defined(OPENSSL_EXTRA_X509_SMALL) || defined(HAVE_WEBSERVER))
+
+static int wolfSSL_EVP_get_hashinfo(const WOLFSSL_EVP_MD* evp,
+    int* pHash, int* pHashSz)
+{
+    enum wc_HashType hash = WC_HASH_TYPE_NONE;
+    int hashSz;
+
+    if (XSTRLEN(evp) < 3) {
+        /* do not try comparing strings if size is too small */
+        return WOLFSSL_FAILURE;
+    }
+
+    if (XSTRNCMP("SHA", evp, 3) == 0) {
+        if (XSTRLEN(evp) > 3) {
+        #ifndef NO_SHA256
+            if (XSTRNCMP("SHA256", evp, 6) == 0) {
+                hash = WC_HASH_TYPE_SHA256;
+            }
+            else
+        #endif
+        #ifdef WOLFSSL_SHA384
+            if (XSTRNCMP("SHA384", evp, 6) == 0) {
+                hash = WC_HASH_TYPE_SHA384;
+            }
+            else
+        #endif
+        #ifdef WOLFSSL_SHA512
+            if (XSTRNCMP("SHA512", evp, 6) == 0) {
+                hash = WC_HASH_TYPE_SHA512;
+            }
+            else
+        #endif
+            {
+                WOLFSSL_MSG("Unknown SHA hash");
+    }
+    }
+    else {
+            hash = WC_HASH_TYPE_SHA;
+        }
+    }
+#ifdef WOLFSSL_MD2
+    else if (XSTRNCMP("MD2", evp, 3) == 0) {
+        hash = WC_HASH_TYPE_MD2;
+    }
+#endif
+#ifndef NO_MD4
+    else if (XSTRNCMP("MD4", evp, 3) == 0) {
+        hash = WC_HASH_TYPE_MD4;
+    }
+#endif
+#ifndef NO_MD5
+    else if (XSTRNCMP("MD5", evp, 3) == 0) {
+        hash = WC_HASH_TYPE_MD5;
+    }
+#endif
+
+    if (pHash)
+        *pHash = hash;
+
+    hashSz = wc_HashGetDigestSize(hash);
+    if (pHashSz)
+        *pHashSz = hashSz;
+
+    if (hashSz < 0) {
+        return WOLFSSL_FAILURE;
+    }
+
+    return WOLFSSL_SUCCESS;
+}
+
+#endif
+
 
 #ifdef OPENSSL_EXTRA
 /* put SSL type in extra for now, not very common */
 
-WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey(int type, WOLFSSL_EVP_PKEY** out,
-        const unsigned char **in, long inSz)
-{
-    WOLFSSL_EVP_PKEY* local;
-
-    WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey");
+/* Converts a DER format key read from "bio" to a PKCS8 structure.
+ *
+ * bio  input bio to read DER from
+ * pkey If not NULL then this pointer will be overwritten with a new PKCS8
+ *      structure.
+ *
+ * returns a WOLFSSL_PKCS8_PRIV_KEY_INFO pointer on success and NULL in fail
+ *         case.
+ */
+WOLFSSL_PKCS8_PRIV_KEY_INFO* wolfSSL_d2i_PKCS8_PKEY_bio(WOLFSSL_BIO* bio,
+        WOLFSSL_PKCS8_PRIV_KEY_INFO** pkey)
+{
+    WOLFSSL_PKCS8_PRIV_KEY_INFO* pkcs8 = NULL;
+#ifdef WOLFSSL_PEM_TO_DER
+    unsigned char* mem;
+    int memSz;
+    int keySz;
+    word32 algId;
+
+    WOLFSSL_MSG("wolfSSL_d2i_PKCS8_PKEY_bio()");
+
+    if (bio == NULL) {
+        return NULL;
+}
+
+    if ((memSz = wolfSSL_BIO_get_mem_data(bio, &mem)) < 0) {
+        return NULL;
+    }
+
+    if ((keySz = wc_KeyPemToDer(mem, memSz, mem, memSz, NULL)) < 0) {
+        WOLFSSL_MSG("Not PEM format");
+        keySz = memSz;
+        if ((keySz = ToTraditional_ex((byte*)mem, (word32)keySz, &algId)) < 0) {
+            return NULL;
+        }
+}
+
+    pkcs8 = wolfSSL_PKEY_new();
+    if (pkcs8 == NULL) {
+        return NULL;
+    }
+
+    pkcs8->pkey.ptr = (char*)XMALLOC(keySz, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
+    if (pkcs8->pkey.ptr == NULL) {
+        wolfSSL_EVP_PKEY_free(pkcs8);
+        return NULL;
+    }
+    XMEMCPY(pkcs8->pkey.ptr, mem, keySz);
+    pkcs8->pkey_sz = keySz;
+
+    if (pkey != NULL) {
+        *pkey = pkcs8;
+    }
+#else
+    (void)bio;
+    (void)pkey;
+#endif /* WOLFSSL_PEM_TO_DER */
+
+    return pkcs8;
+}
+
+
+/* expecting DER format public key
+ *
+ * bio  input bio to read DER from
+ * out  If not NULL then this pointer will be overwritten with a new
+ * WOLFSSL_EVP_PKEY pointer
+ *
+ * returns a WOLFSSL_EVP_PKEY pointer on success and NULL in fail case.
+ */
+WOLFSSL_EVP_PKEY* wolfSSL_d2i_PUBKEY_bio(WOLFSSL_BIO* bio,
+                                         WOLFSSL_EVP_PKEY** out)
+{
+    unsigned char* mem;
+    long memSz;
+    WOLFSSL_EVP_PKEY* pkey = NULL;
+
+    WOLFSSL_ENTER("wolfSSL_d2i_PUBKEY_bio()");
+
+    if (bio == NULL) {
+        return NULL;
+    }
+    (void)out;
+
+    memSz = wolfSSL_BIO_pending(bio);
+    if (memSz <= 0) {
+        return NULL;
+    }
+
+    mem = (unsigned char*)XMALLOC(memSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (mem == NULL) {
+        return NULL;
+    }
+
+    if (wolfSSL_BIO_read(bio, mem, (int)memSz) == memSz) {
+        pkey = wolfSSL_d2i_PUBKEY(NULL, &mem, memSz);
+        if (out != NULL && pkey != NULL) {
+            *out = pkey;
+                }
+            }
+
+    XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    return pkey;
+            }
+
+
+
+/* Converts a DER encoded public key to a WOLFSSL_EVP_PKEY structure.
+ *
+ * out  pointer to new WOLFSSL_EVP_PKEY structure. Can be NULL
+ * in   DER buffer to convert
+ * inSz size of in buffer
+ *
+ * returns a pointer to a new WOLFSSL_EVP_PKEY structure on success and NULL
+ *         on fail
+ */
+WOLFSSL_EVP_PKEY* wolfSSL_d2i_PUBKEY(WOLFSSL_EVP_PKEY** out, unsigned char** in,
+        long inSz)
+            {
+    WOLFSSL_EVP_PKEY* pkey = NULL;
+    const unsigned char* mem;
+    long memSz = inSz;
+
+    WOLFSSL_ENTER("wolfSSL_d2i_PUBKEY");
 
     if (in == NULL || inSz < 0) {
         WOLFSSL_MSG("Bad argument");
         return NULL;
-    }
-
+                        }
+    mem = *in;
+
+    #if !defined(NO_RSA)
+    {
+        RsaKey rsa;
+        word32 keyIdx = 0;
+
+        /* test if RSA key */
+        if (wc_InitRsaKey(&rsa, NULL) == 0 &&
+            wc_RsaPublicKeyDecode(mem, &keyIdx, &rsa, (word32)memSz) == 0) {
+            wc_FreeRsaKey(&rsa);
+            pkey = wolfSSL_PKEY_new();
+            if (pkey != NULL) {
+                pkey->pkey_sz = keyIdx;
+                pkey->pkey.ptr = (char*)XMALLOC(memSz, NULL,
+                        DYNAMIC_TYPE_PUBLIC_KEY);
+                if (pkey->pkey.ptr == NULL) {
+                    wolfSSL_EVP_PKEY_free(pkey);
+                    return NULL;
+                        }
+                XMEMCPY(pkey->pkey.ptr, mem, keyIdx);
+                pkey->type = EVP_PKEY_RSA;
+                if (out != NULL) {
+                    *out = pkey;
+                    }
+
+                pkey->ownRsa = 1;
+                pkey->rsa = wolfSSL_RSA_new();
+                if (pkey->rsa == NULL) {
+                    wolfSSL_EVP_PKEY_free(pkey);
+                    return NULL;
+                        }
+
+                if (wolfSSL_RSA_LoadDer_ex(pkey->rsa,
+                            (const unsigned char*)pkey->pkey.ptr,
+                            pkey->pkey_sz, WOLFSSL_RSA_LOAD_PUBLIC) != 1) {
+                    wolfSSL_EVP_PKEY_free(pkey);
+                    return NULL;
+                    }
+
+                return pkey;
+                }
+                }
+        wc_FreeRsaKey(&rsa);
+            }
+    #endif /* NO_RSA */
+
+    #ifdef HAVE_ECC
+    {
+        word32  keyIdx = 0;
+        ecc_key ecc;
+
+        if (wc_ecc_init(&ecc) == 0 &&
+            wc_EccPublicKeyDecode(mem, &keyIdx, &ecc, (word32)memSz) == 0) {
+            wc_ecc_free(&ecc);
+            pkey = wolfSSL_PKEY_new();
+            if (pkey != NULL) {
+                pkey->pkey_sz = keyIdx;
+                pkey->pkey.ptr = (char*)XMALLOC(keyIdx, NULL,
+                        DYNAMIC_TYPE_PUBLIC_KEY);
+                if (pkey->pkey.ptr == NULL) {
+                    wolfSSL_EVP_PKEY_free(pkey);
+                    return NULL;
+            }
+                XMEMCPY(pkey->pkey.ptr, mem, keyIdx);
+                pkey->type = EVP_PKEY_EC;
+                if (out != NULL) {
+                    *out = pkey;
+            }
+
+                pkey->ownEcc = 1;
+                pkey->ecc = wolfSSL_EC_KEY_new();
+                if (pkey->ecc == NULL) {
+                    wolfSSL_EVP_PKEY_free(pkey);
+                    return NULL;
+            }
+
+                if (wolfSSL_EC_KEY_LoadDer_ex(pkey->ecc,
+                            (const unsigned char*)pkey->pkey.ptr,
+                            pkey->pkey_sz, WOLFSSL_EC_KEY_LOAD_PUBLIC) != 1) {
+                    wolfSSL_EVP_PKEY_free(pkey);
+                    return NULL;
+            }
+
+                return pkey;
+                }
+            }
+        wc_ecc_free(&ecc);
+            }
+    #endif /* HAVE_ECC */
+
+    return pkey;
+
+            }
+
+
+/* Reads in a DER format key. If PKCS8 headers are found they are stripped off.
+ *
+ * type  type of key
+ * out   newly created WOLFSSL_EVP_PKEY structure
+ * in    pointer to input key DER
+ * inSz  size of in buffer
+ *
+ * On success a non null pointer is returned and the pointer in is advanced the
+ * same number of bytes read.
+ */
+WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey(int type, WOLFSSL_EVP_PKEY** out,
+        const unsigned char **in, long inSz)
+            {
+    WOLFSSL_EVP_PKEY* local;
+    word32 idx = 0;
+    int    ret;
+    word32 algId;
+
+    WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey");
+
+    if (in == NULL || inSz < 0) {
+        WOLFSSL_MSG("Bad argument");
+        return NULL;
+                    }
+
+    /* Check if input buffer has PKCS8 header. In the case that it does not
+     * have a PKCS8 header then do not error out. */
+    if ((ret = ToTraditionalInline_ex((const byte*)(*in), &idx, (word32)inSz,
+                                                                 &algId)) > 0) {
+        WOLFSSL_MSG("Found and removed PKCS8 header");
+                        }
+    else {
+        if (ret != ASN_PARSE_E) {
+            WOLFSSL_MSG("Unexpected error with trying to remove PKCS8 header");
+            return NULL;
+                    }
+                }
+
+    if (out != NULL && *out != NULL) {
+        wolfSSL_EVP_PKEY_free(*out);
+        *out = NULL;
+                }
     local = wolfSSL_PKEY_new();
     if (local == NULL) {
         return NULL;
-    }
+            }
+
+    /* sanity check on idx before use */
+    if ((int)idx > inSz) {
+        WOLFSSL_MSG("Issue with index pointer");
+        wolfSSL_EVP_PKEY_free(local);
+        local = NULL;
+        return NULL;
+                    }
 
     local->type     = type;
-    local->pkey_sz  = (int)inSz;
-    local->pkey.ptr = (char*)XMALLOC(inSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
+    local->pkey_sz  = (int)inSz - idx;
+    local->pkey.ptr = (char*)XMALLOC(inSz - idx, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
     if (local->pkey.ptr == NULL) {
         wolfSSL_EVP_PKEY_free(local);
         local = NULL;
-    }
-    else {
-        XMEMCPY(local->pkey.ptr, *in, inSz);
-    }
-
-    if (out != NULL) {
-        *out = local;
-    }
+        return NULL;
+                }
+                else {
+        XMEMCPY(local->pkey.ptr, *in + idx, inSz - idx);
+                }
+
+    switch (type) {
+#ifndef NO_RSA
+        case EVP_PKEY_RSA:
+            local->ownRsa = 1;
+            local->rsa = wolfSSL_RSA_new();
+            if (local->rsa == NULL) {
+                wolfSSL_EVP_PKEY_free(local);
+                return NULL;
+            }
+            if (wolfSSL_RSA_LoadDer_ex(local->rsa,
+                      (const unsigned char*)local->pkey.ptr, local->pkey_sz,
+                      WOLFSSL_RSA_LOAD_PRIVATE) != SSL_SUCCESS) {
+                wolfSSL_EVP_PKEY_free(local);
+                return NULL;
+            }
+            break;
+#endif /* NO_RSA */
+#ifdef HAVE_ECC
+        case EVP_PKEY_EC:
+            local->ownEcc = 1;
+            local->ecc = wolfSSL_EC_KEY_new();
+            if (local->ecc == NULL) {
+                wolfSSL_EVP_PKEY_free(local);
+                return NULL;
+            }
+            if (wolfSSL_EC_KEY_LoadDer(local->ecc,
+                      (const unsigned char*)local->pkey.ptr, local->pkey_sz)
+                      != SSL_SUCCESS) {
+                wolfSSL_EVP_PKEY_free(local);
+                return NULL;
+            }
+            break;
+#endif /* HAVE_ECC */
+
+        default:
+            WOLFSSL_MSG("Unsupported key type");
+            wolfSSL_EVP_PKEY_free(local);
+            return NULL;
+                    }
+
+    /* advance pointer with success */
+    if (local != NULL) {
+        if ((idx + local->pkey_sz) <= (word32)inSz) {
+            *in = *in + idx + local->pkey_sz;
+                    }
+
+        if (out != NULL) {
+            *out = local;
+                }
+            }
 
     return local;
-}
-
-
+            }
+
+#ifndef NO_WOLFSSL_STUB
 long wolfSSL_ctrl(WOLFSSL* ssl, int cmd, long opt, void* pt)
 {
-    WOLFSSL_STUB("wolfSSL_ctrl");
+    WOLFSSL_STUB("SSL_ctrl");
     (void)ssl;
     (void)cmd;
@@ -6852,9 +6963,10 @@
     return WOLFSSL_FAILURE;
 }
-
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 long wolfSSL_CTX_ctrl(WOLFSSL_CTX* ctx, int cmd, long opt, void* pt)
 {
-    WOLFSSL_STUB("wolfSSL_CTX_ctrl");
+    WOLFSSL_STUB("SSL_CTX_ctrl");
     (void)ctx;
     (void)cmd;
@@ -6863,6 +6975,8 @@
     return WOLFSSL_FAILURE;
 }
+#endif
 
 #ifndef NO_CERTS
+
 int wolfSSL_check_private_key(const WOLFSSL* ssl)
 {
@@ -6879,4 +6993,12 @@
     buff = ssl->buffers.certificate->buffer;
     InitDecodedCert(&der, buff, size, ssl->heap);
+#ifdef HAVE_PK_CALLBACKS
+    ret = InitSigPkCb((WOLFSSL*)ssl, &der.sigCtx);
+    if (ret != 0) {
+        FreeDecodedCert(&der);
+        return ret;
+    }
+#endif
+
     if (ParseCertRelative(&der, CERT_TYPE, NO_VERIFY, NULL) != 0) {
         FreeDecodedCert(&der);
@@ -6920,5 +7042,5 @@
     if (c != NULL) {
         *c = -1; /* default to not found */
-    }
+            }
 
     sk = (WOLF_STACK_OF(WOLFSSL_ASN1_OBJECT)*)XMALLOC(
@@ -6926,5 +7048,5 @@
     if (sk == NULL) {
         return NULL;
-    }
+            }
     XMEMSET(sk, 0, sizeof(WOLF_STACK_OF(WOLFSSL_ASN1_OBJECT)));
 
@@ -6933,17 +7055,24 @@
             if (x509->basicConstSet) {
                 obj = wolfSSL_ASN1_OBJECT_new();
+                if (obj == NULL) {
+                    WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct");
+                    wolfSSL_sk_ASN1_OBJECT_free(sk);
+                    return NULL;
+            }
                 if (c != NULL) {
                     *c = x509->basicConstCrit;
-                }
+            }
                 obj->type = BASIC_CA_OID;
-            }
-            else {
+                obj->grp  = oidCertExtType;
+                obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
+        }
+        else {
                 WOLFSSL_MSG("No Basic Constraint set");
-            }
+    }
             break;
 
         case ALT_NAMES_OID:
             {
-                DNS_entry* dns;
+                DNS_entry* dns = NULL;
 
                 if (x509->subjAltNameSet && x509->altNames != NULL) {
@@ -6952,15 +7081,27 @@
                         if (x509->altNames->next != NULL) {
                             *c = -2; /* more then one found */
-                        }
-                        else {
+    }
+    else {
                             *c = x509->subjAltNameCrit;
-                        }
-                    }
+    }
+}
 
                     dns = x509->altNames;
                     while (dns != NULL) {
                         obj = wolfSSL_ASN1_OBJECT_new();
-                        obj->type = ALT_NAMES_OID;
+                        if (obj == NULL) {
+                            WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct");
+                            wolfSSL_sk_ASN1_OBJECT_free(sk);
+                            return NULL;
+    }
+                        obj->type = dns->type;
+                        obj->grp  = oidCertExtType;
                         obj->obj  = (byte*)dns->name;
+                        obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
+                        obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA ;
+
+                        /* set app derefrenced pointers */
+                        obj->d.ia5_internal.data   = dns->name;
+                        obj->d.ia5_internal.length = (int)XSTRLEN(dns->name);
                         dns = dns->next;
                         /* last dns in list add at end of function */
@@ -6972,12 +7113,12 @@
                             wolfSSL_sk_ASN1_OBJECT_free(sk);
                             sk = NULL;
-                            }
-                        }
-                    }
-                }
+}
+    }
+}
+    }
                 else {
                     WOLFSSL_MSG("No Alt Names set");
-                }
-            }
+}
+    }
             break;
 
@@ -6986,13 +7127,21 @@
                 if (c != NULL) {
                     *c = x509->CRLdistCrit;
-                }
+}
                 obj = wolfSSL_ASN1_OBJECT_new();
+                if (obj == NULL) {
+                    WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct");
+                    wolfSSL_sk_ASN1_OBJECT_free(sk);
+                    return NULL;
+    }
                 obj->type  = CRL_DIST_OID;
+                obj->grp   = oidCertExtType;
                 obj->obj   = x509->CRLInfo;
                 obj->objSz = x509->CRLInfoSz;
-            }
+                obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
+                obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA ;
+}
             else {
                 WOLFSSL_MSG("No CRL dist set");
-            }
+    }
             break;
 
@@ -7003,7 +7152,15 @@
                 }
                 obj = wolfSSL_ASN1_OBJECT_new();
+                if (obj == NULL) {
+                    WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct");
+                    wolfSSL_sk_ASN1_OBJECT_free(sk);
+                    return NULL;
+                }
                 obj->type  = AUTH_INFO_OID;
+                obj->grp   = oidCertExtType;
                 obj->obj   = x509->authInfo;
                 obj->objSz = x509->authInfoSz;
+                obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
+                obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA;
             }
             else {
@@ -7018,7 +7175,15 @@
                 }
                 obj = wolfSSL_ASN1_OBJECT_new();
+                if (obj == NULL) {
+                    WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct");
+                    wolfSSL_sk_ASN1_OBJECT_free(sk);
+                    return NULL;
+                }
                 obj->type  = AUTH_KEY_OID;
+                obj->grp   = oidCertExtType;
                 obj->obj   = x509->authKeyId;
                 obj->objSz = x509->authKeyIdSz;
+                obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
+                obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA;
             }
             else {
@@ -7033,7 +7198,15 @@
                 }
                 obj = wolfSSL_ASN1_OBJECT_new();
+                if (obj == NULL) {
+                    WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct");
+                    wolfSSL_sk_ASN1_OBJECT_free(sk);
+                    return NULL;
+                }
                 obj->type  = SUBJ_KEY_OID;
+                obj->grp   = oidCertExtType;
                 obj->obj   = x509->subjKeyId;
                 obj->objSz = x509->subjKeyIdSz;
+                obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
+                obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA;
             }
             else {
@@ -7044,5 +7217,5 @@
         case CERT_POLICY_OID:
             #ifdef WOLFSSL_CERT_EXT
-            {
+{
                 int i;
 
@@ -7055,11 +7228,19 @@
                             *c = 0;
                         }
-                    }
+}
 
                     for (i = 0; i < x509->certPoliciesNb - 1; i++) {
                         obj = wolfSSL_ASN1_OBJECT_new();
+                        if (obj == NULL) {
+                            WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct");
+                            wolfSSL_sk_ASN1_OBJECT_free(sk);
+                            return NULL;
+                        }
                         obj->type  = CERT_POLICY_OID;
+                        obj->grp   = oidCertExtType;
                         obj->obj   = (byte*)(x509->certPolicies[i]);
                         obj->objSz = MAX_CERTPOL_SZ;
+                        obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
+                        obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA;
                         if (wolfSSL_sk_ASN1_OBJECT_push(sk, obj)
                                                                != WOLFSSL_SUCCESS) {
@@ -7071,7 +7252,15 @@
                     }
                     obj = wolfSSL_ASN1_OBJECT_new();
+                    if (obj == NULL) {
+                        WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct");
+                        wolfSSL_sk_ASN1_OBJECT_free(sk);
+                        return NULL;
+                    }
                     obj->type  = CERT_POLICY_OID;
+                    obj->grp   = oidCertExtType;
                     obj->obj   = (byte*)(x509->certPolicies[i]);
                     obj->objSz = MAX_CERTPOL_SZ;
+                    obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
+                    obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA;
                 }
                 else {
@@ -7086,5 +7275,12 @@
                     }
                     obj = wolfSSL_ASN1_OBJECT_new();
+                    if (obj == NULL) {
+                        WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct");
+                        wolfSSL_sk_ASN1_OBJECT_free(sk);
+                        return NULL;
+                    }
                     obj->type  = CERT_POLICY_OID;
+                    obj->grp   = oidCertExtType;
+                    obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
                 }
                 else {
@@ -7103,7 +7299,15 @@
                 }
                 obj = wolfSSL_ASN1_OBJECT_new();
+                if (obj == NULL) {
+                    WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct");
+                    wolfSSL_sk_ASN1_OBJECT_free(sk);
+                    return NULL;
+                }
                 obj->type  = KEY_USAGE_OID;
+                obj->grp   = oidCertExtType;
                 obj->obj   = (byte*)&(x509->keyUsage);
                 obj->objSz = sizeof(word16);
+                obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
+                obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA;
             }
             else {
@@ -7127,11 +7331,19 @@
                 }
                 obj = wolfSSL_ASN1_OBJECT_new();
+                if (obj == NULL) {
+                    WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct");
+                    wolfSSL_sk_ASN1_OBJECT_free(sk);
+                    return NULL;
+                }
                 obj->type  = EXT_KEY_USAGE_OID;
+                obj->grp   = oidCertExtType;
                 obj->obj   = x509->extKeyUsageSrc;
                 obj->objSz = x509->extKeyUsageSz;
+                obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
+                obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA;
             }
             else {
                 WOLFSSL_MSG("No Extended Key Usage set");
-            }
+}
             break;
 
@@ -7166,5 +7378,5 @@
         default:
             WOLFSSL_MSG("Unsupported/Unknown extension OID");
-    }
+}
 
     if (obj != NULL) {
@@ -7192,55 +7404,21 @@
                               WOLFSSL_ENGINE* eng)
 {
-    enum wc_HashType hash = WC_HASH_TYPE_NONE;
-    int  hashSz;
-
-    if (XSTRLEN(evp) < 3) {
-        /* do not try comparing strings if size is too small */
+    int err;
+    int hashType = WC_HASH_TYPE_NONE;
+    int hashSz;
+
+    (void)eng;
+
+    err = wolfSSL_EVP_get_hashinfo(evp, &hashType, &hashSz);
+    if (err != WOLFSSL_SUCCESS)
+        return err;
+
+    *outSz = hashSz;
+
+    if (wc_Hash((enum wc_HashType)hashType, in, inSz, out, *outSz) != 0) {
         return WOLFSSL_FAILURE;
-    }
-
-    if (XSTRNCMP("SHA", evp, 3) == 0) {
-        if (XSTRLEN(evp) > 3) {
-            if (XSTRNCMP("SHA256", evp, 6) == 0) {
-                hash = WC_HASH_TYPE_SHA256;
-            }
-            else if (XSTRNCMP("SHA384", evp, 6) == 0) {
-                hash = WC_HASH_TYPE_SHA384;
-            }
-            else if (XSTRNCMP("SHA512", evp, 6) == 0) {
-                hash = WC_HASH_TYPE_SHA512;
-            }
-            else {
-                WOLFSSL_MSG("Unknown SHA hash");
-            }
-        }
-        else {
-            hash = WC_HASH_TYPE_SHA;
-        }
-    }
-    else if (XSTRNCMP("MD2", evp, 3) == 0) {
-        hash = WC_HASH_TYPE_MD2;
-    }
-    else if (XSTRNCMP("MD4", evp, 3) == 0) {
-        hash = WC_HASH_TYPE_MD4;
-    }
-    else if (XSTRNCMP("MD5", evp, 3) == 0) {
-        hash = WC_HASH_TYPE_MD5;
-    }
-
-    hashSz = wc_HashGetDigestSize(hash);
-    if (hashSz < 0) {
-        WOLFSSL_LEAVE("wolfSSL_EVP_Digest", hashSz);
-        return WOLFSSL_FAILURE;
-    }
-    *outSz = hashSz;
-
-    (void)eng;
-    if (wc_Hash(hash, in, inSz, out, *outSz) == 0) {
-        return WOLFSSL_SUCCESS;
-    }
-    else {
-        return WOLFSSL_FAILURE;
-    }
+}
+
+    return WOLFSSL_SUCCESS;
 }
 
@@ -7297,20 +7475,4 @@
 #endif
 
-int wolfSSL_use_certificate_ASN1(WOLFSSL* ssl, unsigned char* der, int derSz)
-{
-    long idx;
-
-    WOLFSSL_ENTER("wolfSSL_use_certificate_ASN1");
-    if (der != NULL && ssl != NULL) {
-        if (ProcessBuffer(NULL, der, derSz, WOLFSSL_FILETYPE_ASN1, CERT_TYPE, ssl,
-                                                        &idx, 0) == WOLFSSL_SUCCESS)
-            return WOLFSSL_SUCCESS;
-    }
-
-    (void)idx;
-    return WOLFSSL_FAILURE;
-}
-
-
 int wolfSSL_use_certificate(WOLFSSL* ssl, WOLFSSL_X509* x509)
 {
@@ -7320,6 +7482,7 @@
     if (x509 != NULL && ssl != NULL && x509->derCert != NULL) {
         if (ProcessBuffer(NULL, x509->derCert->buffer, x509->derCert->length,
-                     WOLFSSL_FILETYPE_ASN1, CERT_TYPE, ssl, &idx, 0) == WOLFSSL_SUCCESS)
+           WOLFSSL_FILETYPE_ASN1, CERT_TYPE, ssl, &idx, 0) == WOLFSSL_SUCCESS) {
             return WOLFSSL_SUCCESS;
+        }
     }
 
@@ -7327,6 +7490,27 @@
     return WOLFSSL_FAILURE;
 }
+
 #endif /* NO_CERTS */
 
+#endif /* OPENSSL_EXTRA */
+
+#ifndef NO_CERTS
+int wolfSSL_use_certificate_ASN1(WOLFSSL* ssl, unsigned char* der, int derSz)
+{
+    long idx;
+
+    WOLFSSL_ENTER("wolfSSL_use_certificate_ASN1");
+    if (der != NULL && ssl != NULL) {
+        if (ProcessBuffer(NULL, der, derSz, WOLFSSL_FILETYPE_ASN1, CERT_TYPE,
+                                            ssl, &idx, 0) == WOLFSSL_SUCCESS) {
+            return WOLFSSL_SUCCESS;
+        }
+    }
+
+    (void)idx;
+    return WOLFSSL_FAILURE;
+}
+
+#ifndef NO_FILESYSTEM
 
 int wolfSSL_use_certificate_file(WOLFSSL* ssl, const char* file, int format)
@@ -7363,4 +7547,18 @@
 }
 
+int wolfSSL_use_certificate_chain_file_format(WOLFSSL* ssl, const char* file,
+                                              int format)
+{
+   /* process up to MAX_CHAIN_DEPTH plus subject cert */
+   WOLFSSL_ENTER("wolfSSL_use_certificate_chain_file_format");
+   if (ProcessFile(ssl->ctx, file, format, CERT_TYPE, ssl, 1,
+                   NULL) == WOLFSSL_SUCCESS)
+       return WOLFSSL_SUCCESS;
+
+   return WOLFSSL_FAILURE;
+}
+
+#endif /* !NO_FILESYSTEM */
+#endif /* !NO_CERTS */
 
 #ifdef HAVE_ECC
@@ -7369,5 +7567,22 @@
 int wolfSSL_CTX_SetTmpEC_DHE_Sz(WOLFSSL_CTX* ctx, word16 sz)
 {
-    if (ctx == NULL || sz < ECC_MINSIZE || sz > ECC_MAXSIZE)
+    if (ctx == NULL)
+        return BAD_FUNC_ARG;
+
+    if (sz == 0) {
+        /* applies only to ECDSA */
+        if (ctx->privateKeyType != ecc_dsa_sa_algo)
+            return WOLFSSL_SUCCESS;
+
+        if (ctx->privateKeySz == 0) {
+            WOLFSSL_MSG("Must set private key/cert first");
+            return BAD_FUNC_ARG;
+        }
+
+        sz = (word16)ctx->privateKeySz;
+    }
+
+    /* check size */
+    if (sz < ECC_MINSIZE || sz > ECC_MAXSIZE)
         return BAD_FUNC_ARG;
 
@@ -7392,6 +7607,7 @@
 
 
-
-
+#ifdef OPENSSL_EXTRA
+
+#ifndef NO_FILESYSTEM
 int wolfSSL_CTX_use_RSAPrivateKey_file(WOLFSSL_CTX* ctx,const char* file,
                                    int format)
@@ -7409,4 +7625,5 @@
     return wolfSSL_use_PrivateKey_file(ssl, file, format);
 }
+#endif /* NO_FILESYSTEM */
 
 
@@ -7453,4 +7670,5 @@
 #endif /* OPENSSL_EXTRA */
 
+#ifndef NO_FILESYSTEM
 #ifdef HAVE_NTRU
 
@@ -7479,4 +7697,7 @@
 {
     WOLFSSL_ENTER("wolfSSL_CTX_set_verify");
+    if (ctx == NULL)
+        return;
+
     if (mode & WOLFSSL_VERIFY_PEER) {
         ctx->verifyPeer = 1;
@@ -7504,4 +7725,7 @@
 {
     WOLFSSL_ENTER("wolfSSL_set_verify");
+    if (ssl == NULL)
+        return;
+
     if (mode & WOLFSSL_VERIFY_PEER) {
         ssl->options.verifyPeer = 1;
@@ -8036,5 +8260,5 @@
 
 /* Return memory needed to persist this signer, have lock */
-static INLINE int GetSignerMemory(Signer* signer)
+static WC_INLINE int GetSignerMemory(Signer* signer)
 {
     int sz = sizeof(signer->pubKeySize) + sizeof(signer->keyOID)
@@ -8054,5 +8278,5 @@
 
 /* Return memory needed to persist this row, have lock */
-static INLINE int GetCertCacheRowMemory(Signer* row)
+static WC_INLINE int GetCertCacheRowMemory(Signer* row)
 {
     int sz = 0;
@@ -8068,5 +8292,5 @@
 
 /* get the size of persist cert cache, have lock */
-static INLINE int GetCertCacheMemSize(WOLFSSL_CERT_MANAGER* cm)
+static WC_INLINE int GetCertCacheMemSize(WOLFSSL_CERT_MANAGER* cm)
 {
     int sz;
@@ -8083,5 +8307,5 @@
 
 /* Store cert cache header columns with number of items per list, have lock */
-static INLINE void SetCertHeaderColumns(WOLFSSL_CERT_MANAGER* cm, int* columns)
+static WC_INLINE void SetCertHeaderColumns(WOLFSSL_CERT_MANAGER* cm, int* columns)
 {
     int     i;
@@ -8103,5 +8327,5 @@
 /* Restore whole cert row from memory, have lock, return bytes consumed,
    < 0 on error, have lock */
-static INLINE int RestoreCertRow(WOLFSSL_CERT_MANAGER* cm, byte* current,
+static WC_INLINE int RestoreCertRow(WOLFSSL_CERT_MANAGER* cm, byte* current,
                                  int row, int listSz, const byte* end)
 {
@@ -8115,4 +8339,5 @@
     while (listSz) {
         Signer* signer;
+        byte*   publicKey;
         byte*   start = current + idx;  /* for end checks on this signer */
         int     minSz = sizeof(signer->pubKeySize) + sizeof(signer->keyOID) +
@@ -8144,12 +8369,13 @@
             return BUFFER_E;
         }
-        signer->publicKey = (byte*)XMALLOC(signer->pubKeySize, cm->heap,
+        publicKey = (byte*)XMALLOC(signer->pubKeySize, cm->heap,
                                            DYNAMIC_TYPE_KEY);
-        if (signer->publicKey == NULL) {
+        if (publicKey == NULL) {
             FreeSigner(signer, cm->heap);
             return MEMORY_E;
         }
 
-        XMEMCPY(signer->publicKey, current + idx, signer->pubKeySize);
+        XMEMCPY(publicKey, current + idx, signer->pubKeySize);
+        signer->publicKey = publicKey;
         idx += signer->pubKeySize;
 
@@ -8195,5 +8421,5 @@
 
 /* Store whole cert row into memory, have lock, return bytes added */
-static INLINE int StoreCertRow(WOLFSSL_CERT_MANAGER* cm, byte* current, int row)
+static WC_INLINE int StoreCertRow(WOLFSSL_CERT_MANAGER* cm, byte* current, int row)
 {
     int     added  = 0;
@@ -8232,5 +8458,5 @@
 
 /* Persist cert cache to memory, have lock */
-static INLINE int DoMemSaveCertCache(WOLFSSL_CERT_MANAGER* cm,
+static WC_INLINE int DoMemSaveCertCache(WOLFSSL_CERT_MANAGER* cm,
                                      void* mem, int sz)
 {
@@ -8331,5 +8557,8 @@
     }
 
-    XFSEEK(file, 0, XSEEK_END);
+    if(XFSEEK(file, 0, XSEEK_END) != 0) {
+        XFCLOSE(file);
+        return WOLFSSL_BAD_FILE;
+    }
     memSz = (int)XFTELL(file);
     XREWIND(file);
@@ -8464,4 +8693,7 @@
     WOLFSSL_ENTER("wolfSSL_CTX_set_cipher_list");
 
+    if (ctx == NULL)
+        return WOLFSSL_FAILURE;
+
     /* alloc/init on demand only */
     if (ctx->suites == NULL) {
@@ -8486,12 +8718,56 @@
 
 
+int wolfSSL_dtls_get_using_nonblock(WOLFSSL* ssl)
+{
+    int useNb = 0;
+
+    if (ssl == NULL)
+        return WOLFSSL_FAILURE;
+
+    WOLFSSL_ENTER("wolfSSL_dtls_get_using_nonblock");
+    if (ssl->options.dtls) {
+#ifdef WOLFSSL_DTLS
+        useNb = ssl->options.dtlsUseNonblock;
+#endif
+    }
+    else {
+        WOLFSSL_MSG("wolfSSL_dtls_get_using_nonblock() is "
+                    "DEPRECATED for non-DTLS use.");
+    }
+    return useNb;
+}
+
+
 #ifndef WOLFSSL_LEANPSK
+
+void wolfSSL_dtls_set_using_nonblock(WOLFSSL* ssl, int nonblock)
+{
+    (void)nonblock;
+
+    WOLFSSL_ENTER("wolfSSL_dtls_set_using_nonblock");
+
+    if (ssl == NULL)
+        return;
+
+    if (ssl->options.dtls) {
 #ifdef WOLFSSL_DTLS
+        ssl->options.dtlsUseNonblock = (nonblock != 0);
+#endif
+    }
+    else {
+        WOLFSSL_MSG("wolfSSL_dtls_set_using_nonblock() is "
+                    "DEPRECATED for non-DTLS use.");
+    }
+}
+
+
+#ifdef WOLFSSL_DTLS
 
 int wolfSSL_dtls_get_current_timeout(WOLFSSL* ssl)
 {
-    (void)ssl;
-
-    return ssl->dtls_timeout;
+    int timeout = 0;
+    if (ssl)
+        timeout = ssl->dtls_timeout;
+    return timeout;
 }
 
@@ -8535,4 +8811,7 @@
 {
     int result = WOLFSSL_SUCCESS;
+
+    if (ssl == NULL)
+        return WOLFSSL_FATAL_ERROR;
 
     if (!ssl->options.handShakeDone &&
@@ -8608,12 +8887,19 @@
 #endif /* WOLFSSL_DTLS && !NO_WOLFSSL_SERVER */
 
-#ifdef OPENSSL_EXTRA
-    WOLFSSL_METHOD* wolfSSLv23_method(void) {
-        WOLFSSL_METHOD* m;
-        WOLFSSL_ENTER("wolfSSLv23_method");
-#ifndef NO_WOLFSSL_CLIENT
-        m = wolfSSLv23_client_method();
-#else
-        m = wolfSSLv23_server_method();
+
+/* EITHER SIDE METHODS */
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
+    WOLFSSL_METHOD* wolfSSLv23_method(void)
+    {
+        return wolfSSLv23_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfSSLv23_method_ex(void* heap)
+    {
+        WOLFSSL_METHOD* m = NULL;
+        WOLFSSL_ENTER("SSLv23_method");
+    #if !defined(NO_WOLFSSL_CLIENT)
+        m = wolfSSLv23_client_method_ex(heap);
+    #elif !defined(NO_WOLFSSL_SERVER)
+        m = wolfSSLv23_server_method_ex(heap);
 #endif
         if (m != NULL) {
@@ -8623,35 +8909,22 @@
         return m;
     }
-#endif /* OPENSSL_EXTRA */
+#endif /* OPENSSL_EXTRA || WOLFSSL_EITHER_SIDE */
 
 /* client only parts */
 #ifndef NO_WOLFSSL_CLIENT
 
-    #if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS)
+    #ifdef OPENSSL_EXTRA
+    WOLFSSL_METHOD* wolfSSLv2_client_method(void)
+    {
+        WOLFSSL_STUB("wolfSSLv2_client_method");
+        return NULL;
+    }
+    #endif
+
+    #ifdef WOLFSSL_ALLOW_SSLV3
     WOLFSSL_METHOD* wolfSSLv3_client_method(void)
-    {
-        WOLFSSL_ENTER("SSLv3_client_method");
+        {
         return wolfSSLv3_client_method_ex(NULL);
-    }
-    #endif
-
-    #ifdef WOLFSSL_DTLS
-
-        #ifndef NO_OLD_TLS
-        WOLFSSL_METHOD* wolfDTLSv1_client_method(void)
-        {
-            WOLFSSL_ENTER("DTLSv1_client_method");
-            return wolfDTLSv1_client_method_ex(NULL);
-        }
-        #endif  /* NO_OLD_TLS */
-
-        WOLFSSL_METHOD* wolfDTLSv1_2_client_method(void)
-        {
-            WOLFSSL_ENTER("DTLSv1_2_client_method");
-            return wolfDTLSv1_2_client_method_ex(NULL);
-        }
-    #endif
-
-    #if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS)
+        }
     WOLFSSL_METHOD* wolfSSLv3_client_method_ex(void* heap)
     {
@@ -8659,4 +8932,5 @@
                               (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
                                                      heap, DYNAMIC_TYPE_METHOD);
+        (void)heap;
         WOLFSSL_ENTER("SSLv3_client_method_ex");
         if (method)
@@ -8664,37 +8938,45 @@
         return method;
     }
-    #endif
-
-    #ifdef WOLFSSL_DTLS
-
-        #ifndef NO_OLD_TLS
-        WOLFSSL_METHOD* wolfDTLSv1_client_method_ex(void* heap)
+    #endif /* WOLFSSL_ALLOW_SSLV3 */
+
+
+    WOLFSSL_METHOD* wolfSSLv23_client_method(void)
+        {
+        return wolfSSLv23_client_method_ex(NULL);
+        }
+    WOLFSSL_METHOD* wolfSSLv23_client_method_ex(void* heap)
         {
             WOLFSSL_METHOD* method =
                               (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
                                                      heap, DYNAMIC_TYPE_METHOD);
-            WOLFSSL_ENTER("DTLSv1_client_method_ex");
-            if (method)
-                InitSSL_Method(method, MakeDTLSv1());
+            (void)heap;
+        WOLFSSL_ENTER("SSLv23_client_method_ex");
+        if (method) {
+    #if !defined(NO_SHA256) || defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512)
+        #if defined(WOLFSSL_TLS13)
+            InitSSL_Method(method, MakeTLSv1_3());
+        #elif !defined(WOLFSSL_NO_TLS12)
+            InitSSL_Method(method, MakeTLSv1_2());
+        #elif !defined(NO_OLD_TLS)
+            InitSSL_Method(method, MakeTLSv1_1());
+        #endif
+    #else
+        #ifndef NO_OLD_TLS
+            InitSSL_Method(method, MakeTLSv1_1());
+        #endif
+    #endif
+    #if !defined(NO_OLD_TLS) || defined(WOLFSSL_TLS13)
+            method->downgrade = 1;
+    #endif
+        }
             return method;
         }
-        #endif  /* NO_OLD_TLS */
-
-        WOLFSSL_METHOD* wolfDTLSv1_2_client_method_ex(void* heap)
-        {
-            WOLFSSL_METHOD* method =
-                              (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
-                                                     heap, DYNAMIC_TYPE_METHOD);
-            WOLFSSL_ENTER("DTLSv1_2_client_method_ex");
-            if (method)
-                InitSSL_Method(method, MakeDTLSv1_2());
-            (void)heap;
-            return method;
-        }
-    #endif
-
+
+
+    #if defined(WOLFSSL_DTLS) || !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS) || \
+        defined(WOLFSSL_ALLOW_SSLV3)
     /* If SCTP is not enabled returns the state of the dtls option.
      * If SCTP is enabled returns dtls && !sctp. */
-    static INLINE int IsDtlsNotSctpMode(WOLFSSL* ssl)
+    static WC_INLINE int IsDtlsNotSctpMode(WOLFSSL* ssl)
     {
         int result = ssl->options.dtls;
@@ -8708,4 +8990,5 @@
         return result;
     }
+    #endif /* WOLFSSL_DTLS || !WOLFSSL_NO_TLS12 || !NO_OLD_TLS */
 
 
@@ -8713,5 +8996,7 @@
     int wolfSSL_connect(WOLFSSL* ssl)
     {
+    #if !(defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && defined(WOLFSSL_TLS13))
         int neededState;
+    #endif
 
         WOLFSSL_ENTER("SSL_connect()");
@@ -8724,13 +9009,34 @@
             return BAD_FUNC_ARG;
 
-        if (ssl->options.side != WOLFSSL_CLIENT_END) {
-            WOLFSSL_ERROR(ssl->error = SIDE_ERROR);
+    #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
+        if (ssl->options.side == WOLFSSL_NEITHER_END) {
+            ssl->error = InitSSL_Side(ssl, WOLFSSL_CLIENT_END);
+            if (ssl->error != WOLFSSL_SUCCESS) {
+                WOLFSSL_ERROR(ssl->error);
             return WOLFSSL_FATAL_ERROR;
         }
-
+            ssl->error = 0; /* expected to be zero here */
+        }
+
+    #ifdef OPENSSL_EXTRA
+        if (ssl->CBIS != NULL) {
+            ssl->CBIS(ssl, SSL_ST_CONNECT, SSL_SUCCESS);
+            ssl->cbmode = SSL_CB_WRITE;
+        }
+    #endif
+    #endif /* OPENSSL_EXTRA || WOLFSSL_EITHER_SIDE */
+
+    #if defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && defined(WOLFSSL_TLS13)
+        return wolfSSL_connect_TLSv13(ssl);
+    #else
         #ifdef WOLFSSL_TLS13
             if (ssl->options.tls1_3)
                 return wolfSSL_connect_TLSv13(ssl);
         #endif
+
+        if (ssl->options.side != WOLFSSL_CLIENT_END) {
+            WOLFSSL_ERROR(ssl->error = SIDE_ERROR);
+            return WOLFSSL_FATAL_ERROR;
+        }
 
         #ifdef WOLFSSL_DTLS
@@ -8763,9 +9069,4 @@
         }
 
-#ifdef WOLFSSL_TLS13
-        if (ssl->options.tls1_3)
-            return wolfSSL_connect_TLSv13(ssl);
-#endif
-
         switch (ssl->options.connectState) {
 
@@ -8792,4 +9093,8 @@
             /* get response */
             while (ssl->options.serverState < neededState) {
+                #ifdef WOLFSSL_TLS13
+                    if (ssl->options.tls1_3)
+                        return wolfSSL_connect_TLSv13(ssl);
+                #endif
                 if ( (ssl->error = ProcessReply(ssl)) < 0) {
                     WOLFSSL_ERROR(ssl->error);
@@ -8850,9 +9155,10 @@
                         }
                         /* if resumption failed, reset needed state */
-                        else if (neededState == SERVER_FINISHED_COMPLETE)
+                        if (neededState == SERVER_FINISHED_COMPLETE) {
                             if (!ssl->options.resuming)
                                 neededState = SERVER_HELLODONE_COMPLETE;
                     }
                 }
+                }
             #endif
 
@@ -8862,9 +9168,9 @@
 
         case FIRST_REPLY_DONE :
+            #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH)
             #ifdef WOLFSSL_TLS13
                 if (ssl->options.tls1_3)
                     return wolfSSL_connect_TLSv13(ssl);
             #endif
-            #ifndef NO_CERTS
                 if (ssl->options.sendVerify) {
                     if ( (ssl->error = SendCertificate(ssl)) != 0) {
@@ -8898,5 +9204,5 @@
 
         case FIRST_REPLY_SECOND :
-            #ifndef NO_CERTS
+            #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH)
                 if (ssl->options.sendVerify) {
                     if ( (ssl->error = SendCertificateVerify(ssl)) != 0) {
@@ -8906,5 +9212,5 @@
                     WOLFSSL_MSG("sent: certificate verify");
                 }
-            #endif
+            #endif /* !NO_CERTS && !WOLFSSL_NO_CLIENT_AUTH */
             ssl->options.connectState = FIRST_REPLY_THIRD;
             WOLFSSL_MSG("connect state: FIRST_REPLY_THIRD");
@@ -8973,4 +9279,5 @@
             return WOLFSSL_FATAL_ERROR; /* unknown connect state */
         }
+    #endif /* !WOLFSSL_NO_TLS12 */
     }
 
@@ -8981,31 +9288,17 @@
 #ifndef NO_WOLFSSL_SERVER
 
-    #if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS)
+    #ifdef OPENSSL_EXTRA
+    WOLFSSL_METHOD* wolfSSLv2_server_method(void)
+    {
+        WOLFSSL_STUB("wolfSSLv2_server_method");
+        return 0;
+    }
+    #endif
+
+    #ifdef WOLFSSL_ALLOW_SSLV3
     WOLFSSL_METHOD* wolfSSLv3_server_method(void)
-    {
-        WOLFSSL_ENTER("SSLv3_server_method");
+        {
         return wolfSSLv3_server_method_ex(NULL);
-    }
-    #endif
-
-
-    #ifdef WOLFSSL_DTLS
-
-        #ifndef NO_OLD_TLS
-        WOLFSSL_METHOD* wolfDTLSv1_server_method(void)
-        {
-            WOLFSSL_ENTER("DTLSv1_server_method");
-            return wolfDTLSv1_server_method_ex(NULL);
-        }
-        #endif /* NO_OLD_TLS */
-
-        WOLFSSL_METHOD* wolfDTLSv1_2_server_method(void)
-        {
-            WOLFSSL_ENTER("DTLSv1_2_server_method");
-            return wolfDTLSv1_2_server_method_ex(NULL);
-        }
-    #endif
-
-    #if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS)
+        }
     WOLFSSL_METHOD* wolfSSLv3_server_method_ex(void* heap)
     {
@@ -9013,4 +9306,5 @@
                               (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
                                                      heap, DYNAMIC_TYPE_METHOD);
+        (void)heap;
         WOLFSSL_ENTER("SSLv3_server_method_ex");
         if (method) {
@@ -9020,46 +9314,68 @@
         return method;
     }
-    #endif
-
-
-    #ifdef WOLFSSL_DTLS
-
-        #ifndef NO_OLD_TLS
-        WOLFSSL_METHOD* wolfDTLSv1_server_method_ex(void* heap)
+    #endif /* WOLFSSL_ALLOW_SSLV3 */
+
+    WOLFSSL_METHOD* wolfSSLv23_server_method(void)
+        {
+        return wolfSSLv23_server_method_ex(NULL);
+        }
+
+    WOLFSSL_METHOD* wolfSSLv23_server_method_ex(void* heap)
         {
             WOLFSSL_METHOD* method =
                               (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
                                                      heap, DYNAMIC_TYPE_METHOD);
-            WOLFSSL_ENTER("DTLSv1_server_method_ex");
+        (void)heap;
+        WOLFSSL_ENTER("SSLv23_server_method_ex");
             if (method) {
-                InitSSL_Method(method, MakeDTLSv1());
+    #if !defined(NO_SHA256) || defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512)
+        #ifdef WOLFSSL_TLS13
+            InitSSL_Method(method, MakeTLSv1_3());
+        #elif !defined(WOLFSSL_NO_TLS12)
+            InitSSL_Method(method, MakeTLSv1_2());
+        #elif !defined(NO_OLD_TLS)
+            InitSSL_Method(method, MakeTLSv1_1());
+        #endif
+    #else
+        #ifndef NO_OLD_TLS
+            InitSSL_Method(method, MakeTLSv1_1());
+        #else
+            #error Must have SHA256, SHA384 or SHA512 enabled for TLS 1.2
+        #endif
+    #endif
+    #if !defined(NO_OLD_TLS) || defined(WOLFSSL_TLS13)
+            method->downgrade = 1;
+    #endif
                 method->side = WOLFSSL_SERVER_END;
             }
             return method;
         }
-        #endif /* NO_OLD_TLS */
-
-        WOLFSSL_METHOD* wolfDTLSv1_2_server_method_ex(void* heap)
-        {
-            WOLFSSL_METHOD* method =
-                              (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
-                                                     heap, DYNAMIC_TYPE_METHOD);
-            WOLFSSL_ENTER("DTLSv1_2_server_method_ex");
-            if (method) {
-                InitSSL_Method(method, MakeDTLSv1_2());
-                method->side = WOLFSSL_SERVER_END;
-            }
-            (void)heap;
-            return method;
-        }
-    #endif
 
 
     int wolfSSL_accept(WOLFSSL* ssl)
     {
+#if !(defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && defined(WOLFSSL_TLS13))
         word16 havePSK = 0;
         word16 haveAnon = 0;
         word16 haveMcast = 0;
-
+#endif
+
+        if (ssl == NULL)
+            return WOLFSSL_FATAL_ERROR;
+
+    #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
+        if (ssl->options.side == WOLFSSL_NEITHER_END) {
+            ssl->error = InitSSL_Side(ssl, WOLFSSL_SERVER_END);
+            if (ssl->error != WOLFSSL_SUCCESS) {
+                WOLFSSL_ERROR(ssl->error);
+                return WOLFSSL_FATAL_ERROR;
+            }
+            ssl->error = 0; /* expected to be zero here */
+        }
+    #endif /* OPENSSL_EXTRA || WOLFSSL_EITHER_SIDE */
+
+#if defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && defined(WOLFSSL_TLS13)
+        return wolfSSL_accept_TLSv13(ssl);
+#else
 #ifdef WOLFSSL_TLS13
         if (ssl->options.tls1_3)
@@ -9094,14 +9410,26 @@
         #ifndef NO_CERTS
             /* in case used set_accept_state after init */
-            if (!havePSK && !haveAnon && !haveMcast &&
-                (!ssl->buffers.certificate ||
-                 !ssl->buffers.certificate->buffer ||
-                 !ssl->buffers.key ||
-                 !ssl->buffers.key->buffer)) {
-                WOLFSSL_MSG("accept error: don't have server cert and key");
-                ssl->error = NO_PRIVATE_KEY;
-                WOLFSSL_ERROR(ssl->error);
+        /* allow no private key if using PK callbacks and CB is set */
+        if (!havePSK && !haveAnon && !haveMcast) {
+            if (!ssl->buffers.certificate ||
+                !ssl->buffers.certificate->buffer) {
+
+                WOLFSSL_MSG("accept error: server cert required");
+                WOLFSSL_ERROR(ssl->error = NO_PRIVATE_KEY);
                 return WOLFSSL_FATAL_ERROR;
             }
+
+        #ifdef HAVE_PK_CALLBACKS
+            if (wolfSSL_CTX_IsPrivatePkSet(ssl->ctx)) {
+                WOLFSSL_MSG("Using PK for server private key");
+            }
+            else
+        #endif
+            if (!ssl->buffers.key || !ssl->buffers.key->buffer) {
+                WOLFSSL_MSG("accept error: server key required");
+                WOLFSSL_ERROR(ssl->error = NO_PRIVATE_KEY);
+                return WOLFSSL_FATAL_ERROR;
+            }
+        }
         #endif
 
@@ -9150,20 +9478,6 @@
 
         case ACCEPT_CLIENT_HELLO_DONE :
-            if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) {
-                if ((ssl->error = SendTls13HelloRetryRequest(ssl)) != 0) {
-                    WOLFSSL_ERROR(ssl->error);
-                    return WOLFSSL_FATAL_ERROR;
-                }
-            }
-            ssl->options.acceptState = ACCEPT_HELLO_RETRY_REQUEST_DONE;
-            WOLFSSL_MSG("accept state ACCEPT_HELLO_RETRY_REQUEST_DONE");
-            FALL_THROUGH;
-
-        case ACCEPT_HELLO_RETRY_REQUEST_DONE :
-            if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) {
-                if ( (ssl->error = ProcessReply(ssl)) < 0) {
-                    WOLFSSL_ERROR(ssl->error);
-                    return WOLFSSL_FATAL_ERROR;
-                }
+            if (ssl->options.tls1_3) {
+                return wolfSSL_accept_TLSv13(ssl);
             }
 #endif
@@ -9173,9 +9487,4 @@
 
         case ACCEPT_FIRST_REPLY_DONE :
-        #ifdef WOLFSSL_TLS13
-            if (ssl->options.tls1_3) {
-                return wolfSSL_accept_TLSv13(ssl);
-            }
-        #endif
             if ( (ssl->error = SendServerHello(ssl)) != 0) {
                 WOLFSSL_ERROR(ssl->error);
@@ -9351,4 +9660,5 @@
             return WOLFSSL_FATAL_ERROR;
         }
+#endif /* !WOLFSSL_NO_TLS12 */
     }
 
@@ -9418,7 +9728,7 @@
 
 /* some session IDs aren't random after all, let's make them random */
-static INLINE word32 HashSession(const byte* sessionID, word32 len, int* error)
-{
-    byte digest[MAX_DIGEST_SIZE];
+static WC_INLINE word32 HashSession(const byte* sessionID, word32 len, int* error)
+{
+    byte digest[WC_MAX_DIGEST_SIZE];
 
 #ifndef NO_MD5
@@ -9562,5 +9872,5 @@
  * restoreSessionCerts  Restoring session certificates is required.
  */
-static INLINE void RestoreSession(WOLFSSL* ssl, WOLFSSL_SESSION* session,
+static WC_INLINE void RestoreSession(WOLFSSL* ssl, WOLFSSL_SESSION* session,
         byte* masterSecret, byte restoreSessionCerts)
 {
@@ -9605,5 +9915,5 @@
 #endif
 
-    if (ssl->arrays)
+    if (!ssl->options.tls1_3 && ssl->arrays != NULL)
         id = ssl->arrays->sessionID;
     else
@@ -9727,4 +10037,8 @@
     copyInto->ticketSeen     = copyFrom->ticketSeen;
     copyInto->ticketAdd      = copyFrom->ticketAdd;
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    XMEMCPY(&copyInto->ticketNonce, &copyFrom->ticketNonce,
+                                                           sizeof(TicketNonce));
+#endif
 #ifdef WOLFSSL_EARLY_DATA
     copyInto->maxEarlyDataSz = copyFrom->maxEarlyDataSz;
@@ -9790,4 +10104,15 @@
     if (ssl->options.sessionCacheOff)
         return WOLFSSL_FAILURE;
+
+#ifdef OPENSSL_EXTRA
+    /* check for application context id */
+    if (ssl->sessionCtxSz > 0) {
+        if (XMEMCMP(ssl->sessionCtx, session->sessionCtx, ssl->sessionCtxSz)) {
+            /* context id did not match! */
+            WOLFSSL_MSG("Session context did not match");
+            return SSL_FAILURE;
+        }
+    }
+#endif /* OPENSSL_EXTRA */
 
     if (LowResTimer() < (session->bornOn + session->timeout)) {
@@ -9867,6 +10192,15 @@
         /* Use the session object in the cache for external cache if required.
          */
+#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)
+        if (ssl->options.tls1_3) {
+            row = HashSession(ssl->session.sessionID, ID_LEN, &error) %
+                    SESSION_ROWS;
+        }
+        else
+#endif
+        {
         row = HashSession(ssl->arrays->sessionID, ID_LEN, &error) %
                 SESSION_ROWS;
+        }
         if (error != 0) {
             WOLFSSL_MSG("Hash session failed");
@@ -9896,6 +10230,23 @@
         XMEMCPY(session->masterSecret, ssl->session.masterSecret, SECRET_LEN);
     session->haveEMS = ssl->options.haveEMS;
+#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)
+    if (ssl->options.tls1_3) {
+        XMEMCPY(session->sessionID, ssl->session.sessionID, ID_LEN);
+        session->sessionIDSz = ID_LEN;
+    }
+    else
+#endif
+    {
     XMEMCPY(session->sessionID, ssl->arrays->sessionID, ID_LEN);
     session->sessionIDSz = ssl->arrays->sessionIDSz;
+    }
+
+#ifdef OPENSSL_EXTRA
+    /* If using compatibilty layer then check for and copy over session context
+     * id. */
+    if (ssl->sessionCtxSz > 0 && ssl->sessionCtxSz < ID_LEN) {
+        XMEMCPY(session->sessionCtx, ssl->sessionCtx, ssl->sessionCtxSz);
+    }
+#endif
 
     session->timeout = ssl->timeout;
@@ -9926,5 +10277,5 @@
 
     if (error == 0) {
-        session->ticketLen = ticLen;
+        session->ticketLen = (word16)ticLen;
         XMEMCPY(session->ticket, ssl->session.ticket, ticLen);
     } else { /* cleanup, reset state */
@@ -9954,9 +10305,17 @@
     }
 #endif /* SESSION_CERTS || (WOLFSSL_TLS13 & HAVE_SESSION_TICKET) */
+#if defined(WOLFSSL_TLS13)
+    if (error == 0) {
+        session->namedGroup     = ssl->session.namedGroup;
+    }
+#endif
 #if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)
     if (error == 0) {
-        session->namedGroup     = ssl->session.namedGroup;
         session->ticketSeen     = ssl->session.ticketSeen;
         session->ticketAdd      = ssl->session.ticketAdd;
+#ifndef WOLFSSL_TLS13_DRAFT_18
+        XMEMCPY(&session->ticketNonce, &ssl->session.ticketNonce,
+                                                           sizeof(TicketNonce));
+#endif
     #ifdef WOLFSSL_EARLY_DATA
         session->maxEarlyDataSz = ssl->session.maxEarlyDataSz;
@@ -10285,11 +10644,12 @@
         XFREE(ssl->buffers.domainName.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN);
 
-    ssl->buffers.domainName.length = (word32)XSTRLEN(dn) + 1;
+    ssl->buffers.domainName.length = (word32)XSTRLEN(dn);
     ssl->buffers.domainName.buffer = (byte*) XMALLOC(
-                ssl->buffers.domainName.length, ssl->heap, DYNAMIC_TYPE_DOMAIN);
+            ssl->buffers.domainName.length + 1, ssl->heap, DYNAMIC_TYPE_DOMAIN);
 
     if (ssl->buffers.domainName.buffer) {
-        XSTRNCPY((char*)ssl->buffers.domainName.buffer, dn,
-                ssl->buffers.domainName.length);
+        unsigned char* domainName = ssl->buffers.domainName.buffer;
+        XMEMCPY(domainName, dn, ssl->buffers.domainName.length);
+        domainName[ssl->buffers.domainName.length] = '\0';
         return WOLFSSL_SUCCESS;
     }
@@ -10552,4 +10912,8 @@
     {
         WOLFSSL_ENTER("SSL_CTX_set_psk_client_callback");
+
+        if (ctx == NULL)
+            return;
+
         ctx->havePSK = 1;
         ctx->client_psk_cb = cb;
@@ -10563,4 +10927,8 @@
 
         WOLFSSL_ENTER("SSL_set_psk_client_callback");
+
+        if (ssl == NULL)
+            return;
+
         ssl->options.havePSK = 1;
         ssl->options.client_psk_cb = cb;
@@ -10583,4 +10951,6 @@
     {
         WOLFSSL_ENTER("SSL_CTX_set_psk_server_callback");
+        if (ctx == NULL)
+            return;
         ctx->havePSK = 1;
         ctx->server_psk_cb = cb;
@@ -10594,4 +10964,7 @@
 
         WOLFSSL_ENTER("SSL_set_psk_server_callback");
+        if (ssl == NULL)
+            return;
+
         ssl->options.havePSK = 1;
         ssl->options.server_psk_cb = cb;
@@ -10636,5 +11009,5 @@
         WOLFSSL_ENTER("SSL_CTX_use_psk_identity_hint");
         if (hint == 0)
-            ctx->server_hint[0] = 0;
+            ctx->server_hint[0] = '\0';
         else {
             XSTRNCPY(ctx->server_hint, hint, sizeof(ctx->server_hint));
@@ -10656,6 +11029,6 @@
         else {
             XSTRNCPY(ssl->arrays->server_hint, hint,
-                                            sizeof(ssl->arrays->server_hint));
-            ssl->arrays->server_hint[MAX_PSK_ID_LEN] = '\0'; /* null term */
+                                            sizeof(ssl->arrays->server_hint)-1);
+            ssl->arrays->server_hint[sizeof(ssl->arrays->server_hint)-1] = '\0';
         }
         return WOLFSSL_SUCCESS;
@@ -10695,4 +11068,16 @@
         else
             return ProcessBuffer(ctx, in, sz, format, CA_TYPE, NULL,NULL,0);
+    }
+
+
+    int wolfSSL_CTX_load_verify_chain_buffer_format(WOLFSSL_CTX* ctx,
+                                       const unsigned char* in,
+                                       long sz, int format)
+    {
+        WOLFSSL_ENTER("wolfSSL_CTX_load_verify_chain_buffer_format");
+        if (format == WOLFSSL_FILETYPE_PEM)
+            return ProcessChainBuffer(ctx, in, sz, format, CA_TYPE, NULL);
+        else
+            return ProcessBuffer(ctx, in, sz, format, CA_TYPE, NULL,NULL,1);
     }
 
@@ -10795,4 +11180,5 @@
         else {
             if (format == WOLFSSL_FILETYPE_PEM) {
+#ifdef WOLFSSL_PEM_TO_DER
                 FreeDer(&der);
                 ret = PemToDer(buf, sz, DH_PARAM_TYPE, &der, ctx->heap,
@@ -10805,5 +11191,8 @@
                 }
     #endif
-#endif
+    #endif /* WOLFSSL_WPAS */
+#else
+                ret = NOT_COMPILED_IN;
+#endif /* WOLFSSL_PEM_TO_DER */
             }
 
@@ -10946,6 +11335,5 @@
 
 
-#if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS)
-
+#ifdef OPENSSL_EXTRA
 
     int wolfSSL_add_all_algorithms(void)
@@ -10958,4 +11346,13 @@
     }
 
+    int wolfSSL_OpenSSL_add_all_algorithms_noconf(void)
+    {
+        WOLFSSL_ENTER("wolfSSL_OpenSSL_add_all_algorithms_noconf");
+
+        if  (wolfSSL_add_all_algorithms() == WOLFSSL_FATAL_ERROR)
+            return WOLFSSL_FATAL_ERROR;
+
+        return  WOLFSSL_SUCCESS;
+    }
 
    /* returns previous set cache size which stays constant */
@@ -10973,5 +11370,7 @@
     }
 
-
+#endif
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA)
     void wolfSSL_CTX_set_quiet_shutdown(WOLFSSL_CTX* ctx, int mode)
     {
@@ -10988,26 +11387,68 @@
             ssl->options.quietShutdown = 1;
     }
-
-
+#endif
+
+#ifdef OPENSSL_EXTRA
     void wolfSSL_set_bio(WOLFSSL* ssl, WOLFSSL_BIO* rd, WOLFSSL_BIO* wr)
     {
-        WOLFSSL_ENTER("SSL_set_bio");
+        WOLFSSL_ENTER("wolfSSL_set_bio");
+
+        if (ssl == NULL) {
+            WOLFSSL_MSG("Bad argument, ssl was NULL");
+            return;
+        }
+
+        /* if WOLFSSL_BIO is socket type then set WOLFSSL socket to use */
+        if (rd != NULL && rd->type == WOLFSSL_BIO_SOCKET) {
         wolfSSL_set_rfd(ssl, rd->fd);
+        }
+        if (wr != NULL && wr->type == WOLFSSL_BIO_SOCKET) {
         wolfSSL_set_wfd(ssl, wr->fd);
+        }
+
+        /* free any existing WOLFSSL_BIOs in use */
+        if (ssl->biord != NULL) {
+            if (ssl->biord != ssl->biowr) {
+                if (ssl->biowr != NULL) {
+                    wolfSSL_BIO_free(ssl->biowr);
+                    ssl->biowr = NULL;
+                }
+            }
+            wolfSSL_BIO_free(ssl->biord);
+            ssl->biord = NULL;
+        }
+
 
         ssl->biord = rd;
         ssl->biowr = wr;
-    }
-
-
+
+        /* set SSL to use BIO callbacks instead */
+        if (((ssl->cbioFlag & WOLFSSL_CBIO_RECV) == 0) &&
+            (rd != NULL && rd->type != WOLFSSL_BIO_SOCKET)) {
+            ssl->CBIORecv = BioReceive;
+        }
+        if (((ssl->cbioFlag & WOLFSSL_CBIO_SEND) == 0) &&
+            (wr != NULL && wr->type != WOLFSSL_BIO_SOCKET)) {
+            ssl->CBIOSend = BioSend;
+        }
+    }
+#endif
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA) || defined(HAVE_WEBSERVER)
     void wolfSSL_CTX_set_client_CA_list(WOLFSSL_CTX* ctx,
                                        WOLF_STACK_OF(WOLFSSL_X509_NAME)* names)
     {
         WOLFSSL_ENTER("wolfSSL_SSL_CTX_set_client_CA_list");
-
+    #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA)
         if (ctx != NULL)
             ctx->ca_names = names;
-    }
-
+    #else
+        (void)ctx;
+        (void)names;
+    #endif
+    }
+#endif
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA)
     WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_SSL_CTX_get_client_CA_list(
             const WOLFSSL_CTX *s)
@@ -11020,7 +11461,15 @@
         return s->ca_names;
     }
-
+#endif
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+    #if !defined(NO_RSA) && !defined(NO_CERTS)
     WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_load_client_CA_file(const char* fname)
     {
+        /* The webserver build is using this to load a CA into the server
+         * for client authentication as an option. Have this return NULL in
+         * that case. If OPENSSL_EXTRA is enabled, go ahead and include
+         * the function. */
+    #ifdef OPENSSL_EXTRA
         WOLFSSL_STACK *list = NULL;
         WOLFSSL_STACK *node;
@@ -11069,14 +11518,219 @@
         wolfSSL_BIO_free(bio);
         return list;
-    }
-
-
+    #else
+        (void)fname;
+        return NULL;
+    #endif
+    }
+    #endif
+#endif
+
+#ifdef OPENSSL_EXTRA
+    #if !defined(NO_RSA) && !defined(NO_CERTS)
+    int wolfSSL_CTX_add_client_CA(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509)
+    {
+        WOLFSSL_STACK *node = NULL;
+        WOLFSSL_X509_NAME *subjectName = NULL;
+
+        WOLFSSL_ENTER("wolfSSL_CTX_add_client_CA");
+
+        if (ctx == NULL || x509 == NULL){
+            WOLFSSL_MSG("Bad argument");
+            return SSL_FAILURE;
+        }
+
+        subjectName = wolfSSL_X509_get_subject_name(x509);
+        if (subjectName == NULL){
+            WOLFSSL_MSG("invalid x509 data");
+            return SSL_FAILURE;
+        }
+
+        /* Alloc stack struct */
+        node = (WOLF_STACK_OF(WOLFSSL_X509_NAME)*)XMALLOC(
+                                           sizeof(WOLF_STACK_OF(WOLFSSL_X509_NAME)),
+                                           NULL, DYNAMIC_TYPE_OPENSSL);
+        if (node == NULL){
+            WOLFSSL_MSG("memory allocation error");
+            return SSL_FAILURE;
+        }
+        XMEMSET(node, 0, sizeof(WOLF_STACK_OF(WOLFSSL_X509_NAME)));
+
+        /* Alloc and copy WOLFSSL_X509_NAME */
+        node->data.name = (WOLFSSL_X509_NAME*)XMALLOC(
+                                              sizeof(WOLFSSL_X509_NAME),
+                                              NULL, DYNAMIC_TYPE_OPENSSL);
+        if (node->data.name == NULL) {
+            XFREE(node, NULL, DYNAMIC_TYPE_OPENSSL);
+            WOLFSSL_MSG("memory allocation error");
+            return SSL_FAILURE;
+    }
+        XMEMCPY(node->data.name, subjectName, sizeof(WOLFSSL_X509_NAME));
+        XMEMSET(subjectName, 0, sizeof(WOLFSSL_X509_NAME));
+
+        /* push new node onto head of stack */
+        node->num = (ctx->ca_names == NULL) ? 1 : ctx->ca_names->num + 1;
+        node->next = ctx->ca_names;
+        ctx->ca_names = node;
+        return SSL_SUCCESS;
+    }
+    #endif
+
+    #ifndef NO_WOLFSSL_STUB
     int wolfSSL_CTX_set_default_verify_paths(WOLFSSL_CTX* ctx)
     {
         /* TODO:, not needed in goahead */
         (void)ctx;
-        return WOLFSSL_NOT_IMPLEMENTED;
-    }
-
+        WOLFSSL_STUB("SSL_CTX_set_default_verify_paths");
+        return SSL_NOT_IMPLEMENTED;
+    }
+    #endif
+
+    #if defined(WOLFCRYPT_HAVE_SRP) && !defined(NO_SHA256) \
+        && !defined(WC_NO_RNG)
+    static const byte srp_N[] = {
+        0xEE, 0xAF, 0x0A, 0xB9, 0xAD, 0xB3, 0x8D, 0xD6, 0x9C, 0x33, 0xF8,
+        0x0A, 0xFA, 0x8F, 0xC5, 0xE8, 0x60, 0x72, 0x61, 0x87, 0x75, 0xFF,
+        0x3C, 0x0B, 0x9E, 0xA2, 0x31, 0x4C, 0x9C, 0x25, 0x65, 0x76, 0xD6,
+        0x74, 0xDF, 0x74, 0x96, 0xEA, 0x81, 0xD3, 0x38, 0x3B, 0x48, 0x13,
+        0xD6, 0x92, 0xC6, 0xE0, 0xE0, 0xD5, 0xD8, 0xE2, 0x50, 0xB9, 0x8B,
+        0xE4, 0x8E, 0x49, 0x5C, 0x1D, 0x60, 0x89, 0xDA, 0xD1, 0x5D, 0xC7,
+        0xD7, 0xB4, 0x61, 0x54, 0xD6, 0xB6, 0xCE, 0x8E, 0xF4, 0xAD, 0x69,
+        0xB1, 0x5D, 0x49, 0x82, 0x55, 0x9B, 0x29, 0x7B, 0xCF, 0x18, 0x85,
+        0xC5, 0x29, 0xF5, 0x66, 0x66, 0x0E, 0x57, 0xEC, 0x68, 0xED, 0xBC,
+        0x3C, 0x05, 0x72, 0x6C, 0xC0, 0x2F, 0xD4, 0xCB, 0xF4, 0x97, 0x6E,
+        0xAA, 0x9A, 0xFD, 0x51, 0x38, 0xFE, 0x83, 0x76, 0x43, 0x5B, 0x9F,
+        0xC6, 0x1D, 0x2F, 0xC0, 0xEB, 0x06, 0xE3
+    };
+    static const byte srp_g[] = {
+        0x02
+    };
+
+    int wolfSSL_CTX_set_srp_username(WOLFSSL_CTX* ctx, char* username)
+    {
+        int r = 0;
+        SrpSide srp_side = SRP_CLIENT_SIDE;
+        WC_RNG rng;
+        byte salt[SRP_SALT_SIZE];
+
+        WOLFSSL_ENTER("wolfSSL_CTX_set_srp_username");
+        if (ctx == NULL || ctx->srp == NULL || username==NULL)
+            return SSL_FAILURE;
+
+        if (ctx->method->side == WOLFSSL_SERVER_END){
+            srp_side = SRP_SERVER_SIDE;
+        } else if (ctx->method->side == WOLFSSL_CLIENT_END){
+            srp_side = SRP_CLIENT_SIDE;
+        } else {
+            WOLFSSL_MSG("Init CTX failed");
+            return SSL_FAILURE;
+        }
+
+        if (wc_SrpInit(ctx->srp, SRP_TYPE_SHA256, srp_side) < 0){
+            WOLFSSL_MSG("Init CTX failed");
+            XFREE(ctx->srp, ctx->heap, DYNAMIC_TYPE_SRP);
+            wolfSSL_CTX_free(ctx);
+            return SSL_FAILURE;
+        }
+        r = wc_SrpSetUsername(ctx->srp, (const byte*)username,
+                              (word32)XSTRLEN(username));
+        if (r < 0) {
+            WOLFSSL_MSG("fail to set srp username.");
+            return SSL_FAILURE;
+        }
+
+        /* if wolfSSL_CTX_set_srp_password has already been called, */
+        /* execute wc_SrpSetPassword here */
+        if (ctx->srp_password != NULL){
+            if (wc_InitRng(&rng) < 0){
+                WOLFSSL_MSG("wc_InitRng failed");
+                return SSL_FAILURE;
+            }
+            XMEMSET(salt, 0, sizeof(salt)/sizeof(salt[0]));
+            if (wc_RNG_GenerateBlock(&rng, salt,
+                                     sizeof(salt)/sizeof(salt[0])) <  0){
+                WOLFSSL_MSG("wc_RNG_GenerateBlock failed");
+                wc_FreeRng(&rng);
+                return SSL_FAILURE;
+            }
+            if (wc_SrpSetParams(ctx->srp, srp_N, sizeof(srp_N)/sizeof(srp_N[0]),
+                                srp_g, sizeof(srp_g)/sizeof(srp_g[0]),
+                                salt, sizeof(salt)/sizeof(salt[0])) < 0){
+                WOLFSSL_MSG("wc_SrpSetParam failed");
+                wc_FreeRng(&rng);
+                return SSL_FAILURE;
+            }
+            r = wc_SrpSetPassword(ctx->srp,
+                     (const byte*)ctx->srp_password,
+                     (word32)XSTRLEN((char *)ctx->srp_password));
+            if (r < 0) {
+                WOLFSSL_MSG("fail to set srp password.");
+                return SSL_FAILURE;
+            }
+            wc_FreeRng(&rng);
+            XFREE(ctx->srp_password, ctx->heap, DYNAMIC_TYPE_SRP);
+            ctx->srp_password = NULL;
+        }
+
+        return SSL_SUCCESS;
+    }
+
+    int wolfSSL_CTX_set_srp_password(WOLFSSL_CTX* ctx, char* password)
+    {
+        int r;
+        WC_RNG rng;
+        byte salt[SRP_SALT_SIZE];
+
+        WOLFSSL_ENTER("wolfSSL_CTX_set_srp_password");
+        if (ctx == NULL || ctx->srp == NULL || password == NULL)
+            return SSL_FAILURE;
+
+        if (ctx->srp->user != NULL){
+            if (wc_InitRng(&rng) < 0){
+                WOLFSSL_MSG("wc_InitRng failed");
+                return SSL_FAILURE;
+            }
+            XMEMSET(salt, 0, sizeof(salt)/sizeof(salt[0]));
+            if (wc_RNG_GenerateBlock(&rng, salt,
+                                     sizeof(salt)/sizeof(salt[0])) <  0){
+                WOLFSSL_MSG("wc_RNG_GenerateBlock failed");
+                wc_FreeRng(&rng);
+                return SSL_FAILURE;
+            }
+            if (wc_SrpSetParams(ctx->srp, srp_N, sizeof(srp_N)/sizeof(srp_N[0]),
+                                srp_g, sizeof(srp_g)/sizeof(srp_g[0]),
+                                salt, sizeof(salt)/sizeof(salt[0])) < 0){
+                WOLFSSL_MSG("wc_SrpSetParam failed");
+                wc_FreeRng(&rng);
+                return SSL_FAILURE;
+            }
+            r = wc_SrpSetPassword(ctx->srp, (const byte*)password,
+                                  (word32)XSTRLEN(password));
+            if (r < 0) {
+                WOLFSSL_MSG("wc_SrpSetPassword failed.");
+                wc_FreeRng(&rng);
+                return SSL_FAILURE;
+            }
+            if (ctx->srp_password != NULL){
+                XFREE(ctx->srp_password,NULL,
+                      DYNAMIC_TYPE_SRP);
+                ctx->srp_password = NULL;
+    }
+            wc_FreeRng(&rng);
+        } else {
+            /* save password for wolfSSL_set_srp_username */
+            if (ctx->srp_password != NULL)
+                XFREE(ctx->srp_password,ctx->heap, DYNAMIC_TYPE_SRP);
+
+            ctx->srp_password = (byte*)XMALLOC(XSTRLEN(password) + 1, ctx->heap,
+                                               DYNAMIC_TYPE_SRP);
+            if (ctx->srp_password == NULL){
+                WOLFSSL_MSG("memory allocation error");
+                return SSL_FAILURE;
+            }
+            XMEMCPY(ctx->srp_password, password, XSTRLEN(password) + 1);
+        }
+        return SSL_SUCCESS;
+    }
+    #endif /* WOLFCRYPT_HAVE_SRP && !NO_SHA256 && !WC_NO_RNG */
 
     /* keyblock size in bytes or -1 */
@@ -11110,11 +11764,10 @@
     }
 
-
+#endif /* OPENSSL_EXTRA */
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA)
     void wolfSSL_set_accept_state(WOLFSSL* ssl)
     {
-        word16 haveRSA = 1;
-        word16 havePSK = 0;
-
-        WOLFSSL_ENTER("SSL_set_accept_state");
+        WOLFSSL_ENTER("wolfSSL_set_accept_state");
         if (ssl->options.side == WOLFSSL_CLIENT_END) {
     #ifdef HAVE_ECC
@@ -11142,19 +11795,11 @@
     #endif
         }
-        ssl->options.side = WOLFSSL_SERVER_END;
-        /* reset suites in case user switched */
-
-        #ifdef NO_RSA
-            haveRSA = 0;
-        #endif
-        #ifndef NO_PSK
-            havePSK = ssl->options.havePSK;
-        #endif
-        InitSuites(ssl->suites, ssl->version, ssl->buffers.keySz, haveRSA,
-                   havePSK, ssl->options.haveDH, ssl->options.haveNTRU,
-                   ssl->options.haveECDSAsig, ssl->options.haveECC,
-                   ssl->options.haveStaticECC, ssl->options.side);
-    }
-#endif
+
+        if (InitSSL_Side(ssl, WOLFSSL_SERVER_END) != WOLFSSL_SUCCESS) {
+            WOLFSSL_MSG("Error initializing server side");
+    }
+    }
+
+#endif /* OPENSSL_EXTRA || WOLFSSL_EXTRA */
 
     /* return true if connection established */
@@ -11170,5 +11815,6 @@
     }
 
-#if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS)
+#ifdef OPENSSL_EXTRA
+
     void wolfSSL_CTX_set_tmp_rsa_callback(WOLFSSL_CTX* ctx,
                                       WOLFSSL_RSA*(*f)(WOLFSSL*, int, int))
@@ -11195,19 +11841,40 @@
     long wolfSSL_CTX_get_options(WOLFSSL_CTX* ctx)
     {
-        (void)ctx;
         WOLFSSL_ENTER("wolfSSL_CTX_get_options");
         WOLFSSL_MSG("wolfSSL options are set through API calls and macros");
-
-        return 0;
-    }
-
-
+        if(ctx == NULL)
+            return BAD_FUNC_ARG;
+        return ctx->mask;
+    }
+
+#endif
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+
+    static long wolf_set_options(long old_op, long op);
     long wolfSSL_CTX_set_options(WOLFSSL_CTX* ctx, long opt)
     {
         WOLFSSL_ENTER("SSL_CTX_set_options");
-        ctx->mask |= opt;
-        return opt;
-    }
-
+
+        if (ctx == NULL)
+            return BAD_FUNC_ARG;
+
+        ctx->mask = wolf_set_options(ctx->mask, opt);
+
+        return ctx->mask;
+    }
+
+#endif
+
+#ifdef OPENSSL_EXTRA
+
+    long wolfSSL_CTX_clear_options(WOLFSSL_CTX* ctx, long opt)
+    {
+        WOLFSSL_ENTER("SSL_CTX_clear_options");
+        if(ctx == NULL)
+            return BAD_FUNC_ARG;
+        ctx->mask &= ~opt;
+        return ctx->mask;
+    }
 
     int wolfSSL_set_rfd(WOLFSSL* ssl, int rfd)
@@ -11233,17 +11900,7 @@
 
 
-    WOLFSSL_RSA* wolfSSL_RSA_generate_key(int len, unsigned long bits,
-                                          void(*f)(int, int, void*), void* data)
-    {
-        /* no tmp key needed, actual generation not supported */
-        WOLFSSL_ENTER("RSA_generate_key");
-        (void)len;
-        (void)bits;
-        (void)f;
-        (void)data;
-        return NULL;
-    }
-
-
+
+
+#ifndef NO_CERTS
     WOLFSSL_X509_STORE* wolfSSL_CTX_get_cert_store(WOLFSSL_CTX* ctx)
     {
@@ -11252,9 +11909,8 @@
         }
 
-        return &(ctx->x509_store);
-    }
-
-
-#ifndef NO_CERTS
+        return &ctx->x509_store;
+    }
+
+
     void wolfSSL_CTX_set_cert_store(WOLFSSL_CTX* ctx, WOLFSSL_X509_STORE* str)
     {
@@ -11269,4 +11925,6 @@
         ctx->cm               = str->cm;
         ctx->x509_store.cache = str->cache;
+        ctx->x509_store_pt    = str; /* take ownership of store and free it
+                                        with CTX free */
     }
 
@@ -11298,6 +11956,14 @@
         return WOLFSSL_FATAL_ERROR;
     }
-#endif
-
+
+    void wolfSSL_X509_STORE_CTX_set_verify_cb(WOLFSSL_X509_STORE_CTX *ctx,
+                                  WOLFSSL_X509_STORE_CTX_verify_cb verify_cb)
+    {
+        WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_set_verify_cb");
+        if(ctx == NULL)
+            return;
+        ctx->verify_cb = verify_cb;
+    }
+#endif /* !NO_CERTS */
 
     WOLFSSL_BIO_METHOD* wolfSSL_BIO_f_buffer(void)
@@ -11306,18 +11972,19 @@
 
         WOLFSSL_ENTER("BIO_f_buffer");
-        meth.type = BIO_BUFFER;
+        meth.type = WOLFSSL_BIO_BUFFER;
 
         return &meth;
     }
 
-
+    #ifndef NO_WOLFSSL_STUB
     long wolfSSL_BIO_set_write_buffer_size(WOLFSSL_BIO* bio, long size)
     {
         /* wolfSSL has internal buffer, compatibility only */
         WOLFSSL_ENTER("BIO_set_write_buffer_size");
+        WOLFSSL_STUB("BIO_set_write_buffer_size");
         (void)bio;
         return size;
     }
-
+    #endif
 
     WOLFSSL_BIO_METHOD* wolfSSL_BIO_s_bio(void)
@@ -11326,5 +11993,5 @@
 
         WOLFSSL_ENTER("wolfSSL_BIO_f_bio");
-        bio_meth.type = BIO_BIO;
+        bio_meth.type = WOLFSSL_BIO_BIO;
 
         return &bio_meth;
@@ -11338,5 +12005,5 @@
 
         WOLFSSL_ENTER("wolfSSL_BIO_f_file");
-        file_meth.type = BIO_FILE;
+        file_meth.type = WOLFSSL_BIO_FILE;
 
         return &file_meth;
@@ -11350,5 +12017,5 @@
 
         WOLFSSL_ENTER("BIO_f_ssl");
-        meth.type = BIO_SSL;
+        meth.type = WOLFSSL_BIO_SSL;
 
         return &meth;
@@ -11361,5 +12028,5 @@
 
         WOLFSSL_ENTER("BIO_s_socket");
-        meth.type = BIO_SOCKET;
+        meth.type = WOLFSSL_BIO_SOCKET;
 
         return &meth;
@@ -11369,14 +12036,11 @@
     WOLFSSL_BIO* wolfSSL_BIO_new_socket(int sfd, int closeF)
     {
-        WOLFSSL_BIO* bio = (WOLFSSL_BIO*) XMALLOC(sizeof(WOLFSSL_BIO), 0,
-                                                DYNAMIC_TYPE_OPENSSL);
+        WOLFSSL_BIO* bio = wolfSSL_BIO_new(wolfSSL_BIO_s_socket());
 
         WOLFSSL_ENTER("BIO_new_socket");
         if (bio) {
-            XMEMSET(bio, 0, sizeof(WOLFSSL_BIO));
-            bio->type  = BIO_SOCKET;
+            bio->type  = WOLFSSL_BIO_SOCKET;
             bio->close = (byte)closeF;
             bio->fd    = sfd;
-            bio->mem   = NULL;
         }
         return bio;
@@ -11425,12 +12089,20 @@
         WOLFSSL_BIO* bio = (WOLFSSL_BIO*) XMALLOC(sizeof(WOLFSSL_BIO), 0,
                                                 DYNAMIC_TYPE_OPENSSL);
-        WOLFSSL_ENTER("BIO_new");
+        WOLFSSL_ENTER("wolfSSL_BIO_new");
         if (bio) {
             XMEMSET(bio, 0, sizeof(WOLFSSL_BIO));
             bio->type   = method->type;
-            bio->ssl    = NULL;
-            bio->mem    = NULL;
-            bio->prev   = NULL;
-            bio->next   = NULL;
+            bio->close  = BIO_CLOSE; /* default to close things */
+            if (method->type != WOLFSSL_BIO_FILE &&
+                    method->type != WOLFSSL_BIO_SOCKET) {
+                bio->mem_buf =(WOLFSSL_BUF_MEM*)XMALLOC(sizeof(WOLFSSL_BUF_MEM),
+                                                       0, DYNAMIC_TYPE_OPENSSL);
+                if (bio->mem_buf == NULL) {
+                    WOLFSSL_MSG("Memory error");
+                    wolfSSL_BIO_free(bio);
+                    return NULL;
+                }
+                bio->mem_buf->data = (char*)bio->mem;
+            }
         }
         return bio;
@@ -11454,17 +12126,24 @@
     {
         WOLFSSL_BIO* bio = NULL;
-        if (buf == NULL)
+
+        if (buf == NULL || len < 0) {
             return bio;
+        }
 
         bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem());
-        if (bio == NULL)
+        if (bio == NULL) {
             return bio;
-
-        bio->memLen = len;
+        }
+
+        bio->memLen = bio->wrSz = len;
         bio->mem    = (byte*)XMALLOC(len, 0, DYNAMIC_TYPE_OPENSSL);
         if (bio->mem == NULL) {
-            XFREE(bio, 0, DYNAMIC_TYPE_OPENSSL);
+            wolfSSL_BIO_free(bio);
             return NULL;
         }
+        if (bio->mem_buf != NULL) {
+            bio->mem_buf->data = (char*)bio->mem;
+            bio->mem_buf->length = bio->memLen;
+        }
 
         XMEMCPY(bio->mem, buf, len);
@@ -11473,14 +12152,8 @@
     }
 
-
-#ifdef USE_WINDOWS_API
-    #define CloseSocket(s) closesocket(s)
-#elif defined(WOLFSSL_MDK_ARM)  || defined(WOLFSSL_KEIL_TCP_NET)
-    #define CloseSocket(s) closesocket(s)
-    extern int closesocket(int);
-#else
-    #define CloseSocket(s) close(s)
-#endif
-
+    /*
+     * Note : If the flag BIO_NOCLOSE is set then freeing memory buffers is up
+     *        to the application.
+     */
     int wolfSSL_BIO_free(WOLFSSL_BIO* bio)
     {
@@ -11501,5 +12174,5 @@
 
         #ifndef NO_FILESYSTEM
-            if (bio->type == BIO_FILE && bio->close == BIO_CLOSE) {
+            if (bio->type == WOLFSSL_BIO_FILE && bio->close == BIO_CLOSE) {
                 if (bio->file) {
                     XFCLOSE(bio->file);
@@ -11508,7 +12181,24 @@
         #endif
 
-            if (bio->mem)
+            if (bio->close != BIO_NOCLOSE) {
+                if (bio->mem != NULL) {
+                    if (bio->mem_buf != NULL) {
+                        if (bio->mem_buf->data != (char*)bio->mem) {
+                            XFREE(bio->mem, bio->heap, DYNAMIC_TYPE_OPENSSL);
+                            bio->mem = NULL;
+                        }
+                    }
+                    else {
                 XFREE(bio->mem, bio->heap, DYNAMIC_TYPE_OPENSSL);
-            XFREE(bio, bio->heap, DYNAMIC_TYPE_OPENSSL);
+                        bio->mem = NULL;
+                    }
+                }
+                if (bio->mem_buf != NULL) {
+                    wolfSSL_BUF_MEM_free(bio->mem_buf);
+                    bio->mem_buf = NULL;
+                }
+            }
+
+            XFREE(bio, 0, DYNAMIC_TYPE_OPENSSL);
         }
         return 0;
@@ -11528,203 +12218,4 @@
 
 
-    static int wolfSSL_BIO_BIO_read(WOLFSSL_BIO* bio, void* buf, int len)
-    {
-        int   sz;
-        char* pt;
-
-        sz = wolfSSL_BIO_nread(bio, &pt, len);
-
-        if (sz > 0) {
-            XMEMCPY(buf, pt, sz);
-        }
-
-        return sz;
-    }
-
-    /* Handles reading from a memory type BIO and advancing the state.
-     *
-     * bio  WOLFSSL_BIO to read from
-     * buf  buffer to put data from bio in
-     * len  amount of data to be read
-     *
-     * returns size read on success
-     */
-    static int wolfSSL_BIO_MEMORY_read(WOLFSSL_BIO* bio, void* buf, int len)
-    {
-        int   sz;
-
-        sz = (int)wolfSSL_BIO_ctrl_pending(bio);
-        if (sz > 0) {
-            byte* pt = NULL;
-            int memSz;
-
-            if (sz > len) {
-                sz = len;
-            }
-            memSz = wolfSSL_BIO_get_mem_data(bio, (void*)&pt);
-            if (memSz >= sz && pt != NULL) {
-                byte* tmp;
-
-                XMEMCPY(buf, pt, sz);
-                if (memSz - sz > 0) {
-                    tmp = (byte*)XMALLOC(memSz-sz, bio->heap,
-                            DYNAMIC_TYPE_OPENSSL);
-                    if (tmp == NULL) {
-                        WOLFSSL_MSG("Memory error");
-                        return WOLFSSL_BIO_ERROR;
-                    }
-                    XMEMCPY(tmp, pt + sz, memSz - sz);
-
-                    /* reset internal bio->mem, tmp gets free'd with
-                     * wolfSSL_BIO_free */
-                    XFREE(bio->mem, bio->heap, DYNAMIC_TYPE_OPENSSL);
-                    bio->mem = tmp;
-                }
-                bio->wrSz  -= sz;
-                bio->memLen = memSz - sz;
-            }
-            else {
-                WOLFSSL_MSG("Issue with getting bio mem pointer");
-                return 0;
-            }
-        }
-        else {
-            return WOLFSSL_BIO_ERROR;
-        }
-
-        return sz;
-    }
-
-
-    int wolfSSL_BIO_read(WOLFSSL_BIO* bio, void* buf, int len)
-    {
-        int  ret;
-        WOLFSSL* ssl = 0;
-        WOLFSSL_BIO* front = bio;
-
-        WOLFSSL_ENTER("wolfSSL_BIO_read");
-
-        if (bio && bio->type == BIO_BIO) {
-            return wolfSSL_BIO_BIO_read(bio, buf, len);
-        }
-
-    #ifndef NO_FILESYSTEM
-        if (bio && bio->type == BIO_FILE) {
-            return (int)XFREAD(buf, 1, len, bio->file);
-        }
-    #endif
-        if (bio && bio->type == BIO_MEMORY) {
-            return wolfSSL_BIO_MEMORY_read(bio, buf, len);
-        }
-
-        /* already got eof, again is error */
-        if (bio && front->eof)
-            return WOLFSSL_FATAL_ERROR;
-
-        while(bio && ((ssl = bio->ssl) == 0) )
-            bio = bio->next;
-
-        if (ssl == 0) return BAD_FUNC_ARG;
-
-        ret = wolfSSL_read(ssl, buf, len);
-        if (ret == 0)
-            front->eof = 1;
-        else if (ret < 0) {
-            int err = wolfSSL_get_error(ssl, 0);
-            if ( !(err == WOLFSSL_ERROR_WANT_READ || err == WOLFSSL_ERROR_WANT_WRITE) )
-                front->eof = 1;
-        }
-        return ret;
-    }
-
-
-    static int wolfSSL_BIO_BIO_write(WOLFSSL_BIO* bio, const void* data,
-            int len)
-    {
-        /* internal function where arguments have already been sanity checked */
-        int   sz;
-        char* buf;
-
-        sz = wolfSSL_BIO_nwrite(bio, &buf, len);
-
-        /* test space for write */
-        if (sz <= 0) {
-            WOLFSSL_MSG("No room left to write");
-            return sz;
-        }
-
-        XMEMCPY(buf, data, sz);
-
-        return sz;
-    }
-
-
-    int wolfSSL_BIO_write(WOLFSSL_BIO* bio, const void* data, int len)
-    {
-        int  ret;
-        WOLFSSL* ssl = 0;
-        WOLFSSL_BIO* front = bio;
-        byte* p;
-
-        WOLFSSL_ENTER("wolfSSL_BIO_write");
-
-        if (bio && bio->type == BIO_BIO) {
-            return wolfSSL_BIO_BIO_write(bio, data, len);
-        }
-
-    #ifndef NO_FILESYSTEM
-        if (bio && bio->type == BIO_FILE) {
-            return (int)XFWRITE(data, 1, len, bio->file);
-        }
-    #endif
-
-        if (bio && bio->type == BIO_MEMORY) {
-            /* Make buffer big enough to hold new data. */
-            if (bio->mem == NULL) {
-                bio->mem = (byte*)XMALLOC(len, bio->heap, DYNAMIC_TYPE_OPENSSL);
-                if (bio->mem == NULL)
-                    return -1;
-                p = bio->mem;
-            }
-            else {
-                p = (byte*)XMALLOC(len + bio->memLen, bio->heap,
-                                   DYNAMIC_TYPE_OPENSSL);
-                if (p == NULL)
-                    return -1;
-                XMEMCPY(p, bio->mem, bio->memLen);
-                XFREE(bio->mem, bio->heap, DYNAMIC_TYPE_OPENSSL);
-                bio->mem = p;
-                p += bio->memLen;
-            }
-
-            /* Put data on the end of the buffer. */
-            XMEMCPY(p, data, len);
-            bio->memLen += len;
-
-            return len;
-        }
-
-        /* already got eof, again is error */
-        if (bio && front->eof)
-            return WOLFSSL_FATAL_ERROR;
-
-        while(bio && ((ssl = bio->ssl) == 0) )
-            bio = bio->next;
-
-        if (ssl == 0) return BAD_FUNC_ARG;
-
-        ret = wolfSSL_write(ssl, data, len);
-        if (ret == 0)
-            front->eof = 1;
-        else if (ret < 0) {
-            int err = wolfSSL_get_error(ssl, 0);
-            if ( !(err == WOLFSSL_ERROR_WANT_READ || err == WOLFSSL_ERROR_WANT_WRITE) )
-                front->eof = 1;
-        }
-
-        return ret;
-    }
-
-
     WOLFSSL_BIO* wolfSSL_BIO_push(WOLFSSL_BIO* top, WOLFSSL_BIO* append)
     {
@@ -11734,5 +12225,5 @@
 
         return top;
-    }
+        }
 
 
@@ -11744,10 +12235,7 @@
         return 1;
     }
-
-
-#endif /* OPENSSL_EXTRA || GOAHEAD_WS */
-
-
-#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+#endif /* OPENSSL_EXTRA */
+
+#ifdef WOLFSSL_ENCRYPTED_KEYS
 
     void wolfSSL_CTX_set_default_passwd_cb_userdata(WOLFSSL_CTX* ctx,
@@ -11755,6 +12243,7 @@
     {
         WOLFSSL_ENTER("SSL_CTX_set_default_passwd_cb_userdata");
-        ctx->userdata = userdata;
-    }
+        if (ctx)
+            ctx->passwd_userdata = userdata;
+            }
 
 
@@ -11762,22 +12251,108 @@
     {
         WOLFSSL_ENTER("SSL_CTX_set_default_passwd_cb");
-        if (ctx != NULL) {
+        if (ctx)
             ctx->passwd_cb = cb;
-        }
-    }
-
+            }
+
+    pem_password_cb* wolfSSL_CTX_get_default_passwd_cb(WOLFSSL_CTX *ctx)
+    {
+        if (ctx == NULL || ctx->passwd_cb == NULL) {
+            return NULL;
+            }
+
+        return ctx->passwd_cb;
+        }
+
+
+    void* wolfSSL_CTX_get_default_passwd_cb_userdata(WOLFSSL_CTX *ctx)
+    {
+        if (ctx == NULL) {
+            return NULL;
+        }
+
+        return ctx->passwd_userdata;
+    }
+
+#if !defined(NO_PWDBASED) && (defined(OPENSSL_EXTRA) || \
+        defined(OPENSSL_EXTRA_X509_SMALL) || defined(HAVE_WEBSERVER))
+
+    int wolfSSL_EVP_BytesToKey(const WOLFSSL_EVP_CIPHER* type,
+                       const WOLFSSL_EVP_MD* md, const byte* salt,
+                       const byte* data, int sz, int count, byte* key, byte* iv)
+    {
+        int  ret;
+        int hashType = WC_HASH_TYPE_NONE;
+    #ifdef WOLFSSL_SMALL_STACK
+        EncryptedInfo* info = NULL;
+    #else
+        EncryptedInfo  info[1];
+    #endif
+
+    #ifdef WOLFSSL_SMALL_STACK
+        info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), NULL,
+                                       DYNAMIC_TYPE_ENCRYPTEDINFO);
+        if (info == NULL) {
+            WOLFSSL_MSG("malloc failed");
+            return WOLFSSL_FAILURE;
+        }
+    #endif
+
+        XMEMSET(info, 0, sizeof(EncryptedInfo));
+        info->ivSz = EVP_SALT_SIZE;
+
+        ret = wolfSSL_EVP_get_hashinfo(md, &hashType, NULL);
+        if (ret == 0)
+            ret = wc_EncryptedInfoGet(info, type);
+        if (ret == 0)
+            ret = wc_PBKDF1_ex(key, info->keySz, iv, info->ivSz, data, sz, salt,
+                               EVP_SALT_SIZE, count, hashType, NULL);
+
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO);
+    #endif
+
+        if (ret <= 0)
+            return 0; /* failure - for compatibility */
+
+        return ret;
+    }
+
+#endif /* !NO_PWDBASED && (OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL || HAVE_WEBSERVER) */
+#endif /* WOLFSSL_ENCRYPTED_KEYS */
+
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
     int wolfSSL_num_locks(void)
     {
         return 0;
-    }
+        }
 
     void wolfSSL_set_locking_callback(void (*f)(int, int, const char*, int))
     {
-        (void)f;
-    }
+        WOLFSSL_ENTER("wolfSSL_set_locking_callback");
+
+        if (wc_SetMutexCb(f) != 0) {
+            WOLFSSL_MSG("Error when setting mutex call back");
+        }
+    }
+
+
+    typedef unsigned long (idCb)(void);
+    static idCb* inner_idCb = NULL;
+
+    unsigned long wolfSSL_thread_id(void)
+    {
+        if (inner_idCb != NULL) {
+            return inner_idCb();
+        }
+        else {
+            return 0;
+        }
+        }
+
 
     void wolfSSL_set_id_callback(unsigned long (*f)(void))
     {
-        (void)f;
+        inner_idCb = f;
     }
 
@@ -11786,5 +12361,5 @@
         WOLFSSL_ENTER("wolfSSL_ERR_get_error");
 
-#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
         {
             unsigned long ret = wolfSSL_ERR_peek_error_line_data(NULL, NULL,
@@ -11793,134 +12368,24 @@
             return ret;
         }
+#elif (defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE))
+        {
+            int ret = wc_PullErrorNode(NULL, NULL, NULL);
+
+            if (ret < 0) {
+                if (ret == BAD_STATE_E) return 0; /* no errors in queue */
+                WOLFSSL_MSG("Error with pulling error node!");
+                WOLFSSL_LEAVE("wolfSSL_ERR_get_error", ret);
+                ret = 0 - ret; /* return absolute value of error */
+
+                /* panic and try to clear out nodes */
+                wc_ClearErrorNodes();
+            }
+
+            return (unsigned long)ret;
+        }
 #else
         return (unsigned long)(0 - NOT_COMPILED_IN);
-#endif
-    }
-
-#ifndef NO_MD5
-
-    int wolfSSL_EVP_BytesToKey(const WOLFSSL_EVP_CIPHER* type,
-                       const WOLFSSL_EVP_MD* md, const byte* salt,
-                       const byte* data, int sz, int count, byte* key, byte* iv)
-    {
-        int  keyLen = 0;
-        int  ivLen  = 0;
-        int  j;
-        int  keyLeft;
-        int  ivLeft;
-        int  keyOutput = 0;
-        byte digest[WC_MD5_DIGEST_SIZE];
-    #ifdef WOLFSSL_SMALL_STACK
-        wc_Md5* md5 = NULL;
-    #else
-        wc_Md5  md5[1];
     #endif
-
-    #ifdef WOLFSSL_SMALL_STACK
-        md5 = (wc_Md5*)XMALLOC(sizeof(wc_Md5), NULL, DYNAMIC_TYPE_HASHCTX);
-        if (md5 == NULL)
-            return 0;
-    #endif
-
-        (void)type;
-
-        WOLFSSL_ENTER("wolfSSL_EVP_BytesToKey");
-
-        if (wc_InitMd5(md5) != 0) {
-        #ifdef WOLFSSL_SMALL_STACK
-            XFREE(md5, NULL, DYNAMIC_TYPE_HASHCTX);
-        #endif
-            return 0;
-        }
-
-        /* only support MD5 for now */
-        if (XSTRNCMP(md, "MD5", 3) != 0) {
-        #ifdef WOLFSSL_SMALL_STACK
-            XFREE(md5, NULL, DYNAMIC_TYPE_HASHCTX);
-        #endif
-            return 0;
-        }
-
-        /* only support CBC DES and AES for now */
-        #ifndef NO_DES3
-        if (XSTRNCMP(type, EVP_DES_CBC, EVP_DES_SIZE) == 0) {
-            keyLen = DES_KEY_SIZE;
-            ivLen  = DES_IV_SIZE;
-        }
-        else if (XSTRNCMP(type, EVP_DES_EDE3_CBC, EVP_DES_EDE3_SIZE) == 0) {
-            keyLen = DES3_KEY_SIZE;
-            ivLen  = DES_IV_SIZE;
-        }
-        else
-        #endif /* NO_DES3 */
-        #ifndef NO_AES
-        if (XSTRNCMP(type, EVP_AES_128_CBC, EVP_AES_SIZE) == 0) {
-            keyLen = AES_128_KEY_SIZE;
-            ivLen  = AES_IV_SIZE;
-        }
-        else if (XSTRNCMP(type, EVP_AES_192_CBC, EVP_AES_SIZE) == 0) {
-            keyLen = AES_192_KEY_SIZE;
-            ivLen  = AES_IV_SIZE;
-        }
-        else if (XSTRNCMP(type, EVP_AES_256_CBC, EVP_AES_SIZE) == 0) {
-            keyLen = AES_256_KEY_SIZE;
-            ivLen  = AES_IV_SIZE;
-        }
-        else
-        #endif /* NO_AES */
-        {
-        #ifdef WOLFSSL_SMALL_STACK
-            XFREE(md5, NULL, DYNAMIC_TYPE_HASHCTX);
-        #endif
-            return 0;
-        }
-
-        keyLeft   = keyLen;
-        ivLeft    = ivLen;
-
-        while (keyOutput < (keyLen + ivLen)) {
-            int digestLeft = WC_MD5_DIGEST_SIZE;
-            /* D_(i - 1) */
-            if (keyOutput)                      /* first time D_0 is empty */
-                wc_Md5Update(md5, digest, WC_MD5_DIGEST_SIZE);
-            /* data */
-            wc_Md5Update(md5, data, sz);
-            /* salt */
-            if (salt)
-                wc_Md5Update(md5, salt, EVP_SALT_SIZE);
-            wc_Md5Final(md5, digest);
-            /* count */
-            for (j = 1; j < count; j++) {
-                wc_Md5Update(md5, digest, WC_MD5_DIGEST_SIZE);
-                wc_Md5Final(md5, digest);
-            }
-
-            if (keyLeft) {
-                int store = min(keyLeft, WC_MD5_DIGEST_SIZE);
-                XMEMCPY(&key[keyLen - keyLeft], digest, store);
-
-                keyOutput  += store;
-                keyLeft    -= store;
-                digestLeft -= store;
-            }
-
-            if (ivLeft && digestLeft) {
-                int store = min(ivLeft, digestLeft);
-                if (iv != NULL)
-                    XMEMCPY(&iv[ivLen - ivLeft],
-                            &digest[WC_MD5_DIGEST_SIZE - digestLeft], store);
-                keyOutput += store;
-                ivLeft    -= store;
-            }
-        }
-
-    #ifdef WOLFSSL_SMALL_STACK
-        XFREE(md5, NULL, DYNAMIC_TYPE_HASHCTX);
-    #endif
-
-        return keyOutput == (keyLen + ivLen) ? keyOutput : 0;
-    }
-
-#endif /* NO_MD5 */
+    }
 
 #endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */
@@ -11999,5 +12464,5 @@
     return size;
 }
-#endif /* !defined(NO_WOLFSSL_CLIENT) */
+#endif /* !NO_WOLFSSL_CLIENT */
 
 
@@ -12063,5 +12528,5 @@
         return 0;
     }
-#endif /* NO_MD5 */
+#endif /* !NO_MD5 */
 
 
@@ -12136,5 +12601,5 @@
         return SHA_Final(input, sha);
     }
-#endif /* NO_SHA */
+#endif /* !NO_SHA */
 
     #ifdef WOLFSSL_SHA224
@@ -12349,24 +12814,28 @@
         const char *name;
     } md_tbl[] = {
+    #ifndef NO_MD4
+         {WC_HASH_TYPE_MD4, "MD4"},
+    #endif /* NO_MD4 */
+
     #ifndef NO_MD5
-        {WC_MD5, "MD5"},
+        {WC_HASH_TYPE_MD5, "MD5"},
     #endif /* NO_MD5 */
 
     #ifndef NO_SHA
-        {WC_SHA, "SHA"},
+        {WC_HASH_TYPE_SHA, "SHA"},
     #endif /* NO_SHA */
 
     #ifdef WOLFSSL_SHA224
-        {WC_SHA224, "SHA224"},
+        {WC_HASH_TYPE_SHA224, "SHA224"},
     #endif /* WOLFSSL_SHA224 */
     #ifndef NO_SHA256
-        {WC_SHA256, "SHA256"},
+        {WC_HASH_TYPE_SHA256, "SHA256"},
     #endif
 
     #ifdef WOLFSSL_SHA384
-        {WC_SHA384, "SHA384"},
+        {WC_HASH_TYPE_SHA384, "SHA384"},
     #endif /* WOLFSSL_SHA384 */
     #ifdef WOLFSSL_SHA512
-        {WC_SHA512, "SHA512"},
+        {WC_HASH_TYPE_SHA512, "SHA512"},
     #endif /* WOLFSSL_SHA512 */
         {0, NULL}
@@ -12378,5 +12847,7 @@
         const char *name;
         const char *alias;
-    } alias_tbl[] = {
+    } alias_tbl[] =
+    {
+        {"MD4", "ssl3-md4"},
         {"MD5", "ssl3-md5"},
         {"SHA", "ssl3-sha1"},
@@ -12404,9 +12875,11 @@
 {
     const struct s_ent *ent;
-    for( ent = md_tbl; ent->macType != 0; ent++)
+    WOLFSSL_ENTER("EVP_get_md");
+    for( ent = md_tbl; ent->name != NULL; ent++){
         if(type == ent->macType) {
             return (WOLFSSL_EVP_MD *)ent->name;
         }
-    return 0;
+    }
+    return (WOLFSSL_EVP_MD *)"";
 }
 
@@ -12414,10 +12887,24 @@
 {
     const struct s_ent *ent;
-    for( ent = md_tbl; ent->name != NULL; ent++)
+    WOLFSSL_ENTER("EVP_MD_type");
+    for( ent = md_tbl; ent->name != NULL; ent++){
         if(XSTRNCMP((const char *)md, ent->name, XSTRLEN(ent->name)+1) == 0) {
             return ent->macType;
         }
+    }
     return 0;
 }
+
+
+#ifndef NO_MD4
+
+    /* return a pointer to MD4 EVP type */
+    const WOLFSSL_EVP_MD* wolfSSL_EVP_md4(void)
+    {
+        WOLFSSL_ENTER("wolfSSL_EVP_md4");
+        return EVP_get_digestbyname("MD4");
+    }
+
+#endif /* !NO_MD4 */
 
 
@@ -12426,10 +12913,9 @@
     const WOLFSSL_EVP_MD* wolfSSL_EVP_md5(void)
     {
-        const char* type = EVP_get_digestbyname("MD5");
         WOLFSSL_ENTER("EVP_md5");
-        return type;
-    }
-
-    #endif /* NO_MD5 */
+        return EVP_get_digestbyname("MD5");
+    }
+
+#endif /* !NO_MD5 */
 
 
@@ -12437,7 +12923,6 @@
     const WOLFSSL_EVP_MD* wolfSSL_EVP_sha1(void)
     {
-        const char* type = EVP_get_digestbyname("SHA");
         WOLFSSL_ENTER("EVP_sha1");
-        return type;
+        return EVP_get_digestbyname("SHA");
     }
 #endif /* NO_SHA */
@@ -12447,7 +12932,6 @@
     const WOLFSSL_EVP_MD* wolfSSL_EVP_sha224(void)
     {
-        const char* type = EVP_get_digestbyname("SHA224");
         WOLFSSL_ENTER("EVP_sha224");
-        return type;
+        return EVP_get_digestbyname("SHA224");
     }
 
@@ -12457,7 +12941,6 @@
     const WOLFSSL_EVP_MD* wolfSSL_EVP_sha256(void)
     {
-        const char* type = EVP_get_digestbyname("SHA256");
         WOLFSSL_ENTER("EVP_sha256");
-        return type;
+        return EVP_get_digestbyname("SHA256");
     }
 
@@ -12466,7 +12949,6 @@
     const WOLFSSL_EVP_MD* wolfSSL_EVP_sha384(void)
     {
-        const char* type = EVP_get_digestbyname("SHA384");
         WOLFSSL_ENTER("EVP_sha384");
-        return type;
+        return EVP_get_digestbyname("SHA384");
     }
 
@@ -12477,10 +12959,10 @@
     const WOLFSSL_EVP_MD* wolfSSL_EVP_sha512(void)
     {
-        const char* type = EVP_get_digestbyname("SHA512");
         WOLFSSL_ENTER("EVP_sha512");
-        return type;
+        return EVP_get_digestbyname("SHA512");
     }
 
     #endif /* WOLFSSL_SHA512 */
+
 
     WOLFSSL_EVP_MD_CTX *wolfSSL_EVP_MD_CTX_new(void)
@@ -12505,4 +12987,94 @@
     }
 
+
+    /* returns the type of message digest used by the ctx */
+    int wolfSSL_EVP_MD_CTX_type(const WOLFSSL_EVP_MD_CTX *ctx) {
+        WOLFSSL_ENTER("EVP_MD_CTX_type");
+        return ctx->macType;
+    }
+
+
+    /* returns WOLFSSL_SUCCESS on success */
+    int wolfSSL_EVP_MD_CTX_copy(WOLFSSL_EVP_MD_CTX *out, const WOLFSSL_EVP_MD_CTX *in)
+    {
+        return wolfSSL_EVP_MD_CTX_copy_ex(out, in);
+    }
+
+
+    /* Deep copy of EVP_MD hasher
+     * return WOLFSSL_SUCCESS on success */
+    static int wolfSSL_EVP_MD_Copy_Hasher(WOLFSSL_EVP_MD_CTX* des,
+            const WOLFSSL_EVP_MD_CTX* src)
+    {
+        if (src->macType == (NID_hmac & 0xFF)) {
+            wolfSSL_HmacCopy(&des->hash.hmac, (Hmac*)&src->hash.hmac);
+        }
+        else {
+            switch (src->macType) {
+            #ifndef NO_MD5
+                case WC_HASH_TYPE_MD5:
+                    wc_Md5Copy((wc_Md5*)&src->hash.digest,
+                            (wc_Md5*)&des->hash.digest);
+                    break;
+            #endif /* !NO_MD5 */
+
+            #ifndef NO_SHA
+                case WC_HASH_TYPE_SHA:
+                    wc_ShaCopy((wc_Sha*)&src->hash.digest,
+                            (wc_Sha*)&des->hash.digest);
+                    break;
+            #endif /* !NO_SHA */
+
+            #ifdef WOLFSSL_SHA224
+                case WC_HASH_TYPE_SHA224:
+                    wc_Sha224Copy((wc_Sha224*)&src->hash.digest,
+                            (wc_Sha224*)&des->hash.digest);
+                    break;
+            #endif /* WOLFSSL_SHA224 */
+
+            #ifndef NO_SHA256
+                case WC_HASH_TYPE_SHA256:
+                    wc_Sha256Copy((wc_Sha256*)&src->hash.digest,
+                            (wc_Sha256*)&des->hash.digest);
+                    break;
+            #endif /* !NO_SHA256 */
+
+            #ifdef WOLFSSL_SHA384
+                case WC_HASH_TYPE_SHA384:
+                    wc_Sha384Copy((wc_Sha384*)&src->hash.digest,
+                            (wc_Sha384*)&des->hash.digest);
+                    break;
+            #endif /* WOLFSSL_SHA384 */
+            #ifdef WOLFSSL_SHA512
+                case WC_HASH_TYPE_SHA512:
+                    wc_Sha512Copy((wc_Sha512*)&src->hash.digest,
+                        (wc_Sha512*)&des->hash.digest);
+                    break;
+            #endif /* WOLFSSL_SHA512 */
+
+                default:
+                    return WOLFSSL_FAILURE;
+            }
+        }
+        return WOLFSSL_SUCCESS;
+    }
+
+
+    /* copies structure in to the structure out
+     *
+     * returns WOLFSSL_SUCCESS on success */
+    int wolfSSL_EVP_MD_CTX_copy_ex(WOLFSSL_EVP_MD_CTX *out, const WOLFSSL_EVP_MD_CTX *in)
+    {
+        if ((out == NULL) || (in == NULL)) return WOLFSSL_FAILURE;
+        WOLFSSL_ENTER("EVP_CIPHER_MD_CTX_copy_ex");
+        XMEMCPY(out, in, sizeof(WOLFSSL_EVP_MD_CTX));
+        if (in->pctx != NULL) {
+            out->pctx = wolfSSL_EVP_PKEY_CTX_new(in->pctx->pkey, NULL);
+            if (out->pctx == NULL)
+                return WOLFSSL_FAILURE;
+        }
+        return wolfSSL_EVP_MD_Copy_Hasher(out, (WOLFSSL_EVP_MD_CTX*)in);
+    }
+
     void wolfSSL_EVP_MD_CTX_init(WOLFSSL_EVP_MD_CTX* ctx)
     {
@@ -12513,6 +13085,7 @@
     const WOLFSSL_EVP_MD *wolfSSL_EVP_MD_CTX_md(const WOLFSSL_EVP_MD_CTX *ctx)
     {
-        if (!ctx)
+        if (ctx == NULL)
             return NULL;
+        WOLFSSL_ENTER("EVP_MD_CTX_md");
         return (const WOLFSSL_EVP_MD *)wolfSSL_EVP_get_md(ctx->macType);
     }
@@ -12520,64 +13093,102 @@
     #ifndef NO_AES
 
+    #ifdef HAVE_AES_CBC
+    #ifdef WOLFSSL_AES_128
     const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_aes_128_cbc(void)
     {
         WOLFSSL_ENTER("wolfSSL_EVP_aes_128_cbc");
+        if (EVP_AES_128_CBC == NULL)
+            wolfSSL_EVP_init();
         return EVP_AES_128_CBC;
     }
-
-
+    #endif /* WOLFSSL_AES_128 */
+
+
+    #ifdef WOLFSSL_AES_192
     const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_aes_192_cbc(void)
     {
         WOLFSSL_ENTER("wolfSSL_EVP_aes_192_cbc");
+        if (EVP_AES_192_CBC == NULL)
+            wolfSSL_EVP_init();
         return EVP_AES_192_CBC;
     }
-
-
+    #endif /* WOLFSSL_AES_192 */
+
+
+    #ifdef WOLFSSL_AES_256
     const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_aes_256_cbc(void)
     {
         WOLFSSL_ENTER("wolfSSL_EVP_aes_256_cbc");
+        if (EVP_AES_256_CBC == NULL)
+            wolfSSL_EVP_init();
         return EVP_AES_256_CBC;
     }
-
-
+    #endif /* WOLFSSL_AES_256 */
+    #endif /* HAVE_AES_CBC */
+
+
+    #ifdef WOLFSSL_AES_128
     const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_aes_128_ctr(void)
     {
         WOLFSSL_ENTER("wolfSSL_EVP_aes_128_ctr");
+        if (EVP_AES_128_CTR == NULL)
+            wolfSSL_EVP_init();
         return EVP_AES_128_CTR;
     }
-
-
+    #endif /* WOLFSSL_AES_2128 */
+
+
+    #ifdef WOLFSSL_AES_192
     const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_aes_192_ctr(void)
     {
         WOLFSSL_ENTER("wolfSSL_EVP_aes_192_ctr");
+        if (EVP_AES_192_CTR == NULL)
+            wolfSSL_EVP_init();
         return EVP_AES_192_CTR;
     }
-
-
+    #endif /* WOLFSSL_AES_192 */
+
+
+    #ifdef WOLFSSL_AES_256
     const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_aes_256_ctr(void)
     {
         WOLFSSL_ENTER("wolfSSL_EVP_aes_256_ctr");
+        if (EVP_AES_256_CTR == NULL)
+            wolfSSL_EVP_init();
         return EVP_AES_256_CTR;
     }
-
+    #endif /* WOLFSSL_AES_256 */
+
+    #ifdef WOLFSSL_AES_128
     const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_aes_128_ecb(void)
     {
         WOLFSSL_ENTER("wolfSSL_EVP_aes_128_ecb");
+        if (EVP_AES_128_ECB == NULL)
+            wolfSSL_EVP_init();
         return EVP_AES_128_ECB;
     }
-
-
+    #endif /* WOLFSSL_AES_128 */
+
+
+    #ifdef WOLFSSL_AES_192
     const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_aes_192_ecb(void)
     {
         WOLFSSL_ENTER("wolfSSL_EVP_aes_192_ecb");
+        if (EVP_AES_192_ECB == NULL)
+            wolfSSL_EVP_init();
         return EVP_AES_192_ECB;
     }
-
-
+    #endif /* WOLFSSL_AES_192*/
+
+
+    #ifdef WOLFSSL_AES_256
     const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_aes_256_ecb(void)
     {
         WOLFSSL_ENTER("wolfSSL_EVP_aes_256_ecb");
+        if (EVP_AES_256_ECB == NULL)
+            wolfSSL_EVP_init();
         return EVP_AES_256_ECB;
     }
+    #endif /* WOLFSSL_AES_256 */
     #endif /* NO_AES */
 
@@ -12586,4 +13197,6 @@
     {
         WOLFSSL_ENTER("wolfSSL_EVP_des_cbc");
+        if (EVP_DES_CBC == NULL)
+            wolfSSL_EVP_init();
         return EVP_DES_CBC;
     }
@@ -12592,4 +13205,6 @@
     {
         WOLFSSL_ENTER("wolfSSL_EVP_des_ecb");
+        if (EVP_DES_ECB == NULL)
+            wolfSSL_EVP_init();
         return EVP_DES_ECB;
     }
@@ -12598,4 +13213,6 @@
     {
         WOLFSSL_ENTER("wolfSSL_EVP_des_ede3_cbc");
+        if (EVP_DES_EDE3_CBC == NULL)
+            wolfSSL_EVP_init();
         return EVP_DES_EDE3_CBC;
     }
@@ -12604,4 +13221,6 @@
     {
         WOLFSSL_ENTER("wolfSSL_EVP_des_ede3_ecb");
+        if (EVP_DES_EDE3_ECB == NULL)
+            wolfSSL_EVP_init();
         return EVP_DES_EDE3_ECB;
     }
@@ -12609,4 +13228,5 @@
 #endif /* NO_DES3 */
 
+#ifndef NO_RC4
     const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_rc4(void)
     {
@@ -12615,4 +13235,5 @@
         return type;
     }
+#endif
 
 #ifdef HAVE_IDEA
@@ -12620,4 +13241,6 @@
     {
         WOLFSSL_ENTER("wolfSSL_EVP_idea_cbc");
+        if (EVP_IDEA_CBC == NULL)
+            wolfSSL_EVP_init();
         return EVP_IDEA_CBC;
     }
@@ -12634,4 +13257,51 @@
     {
         WOLFSSL_ENTER("EVP_MD_CTX_cleanup");
+        if (ctx->pctx != NULL)
+            wolfSSL_EVP_PKEY_CTX_free(ctx->pctx);
+
+        if (ctx->macType == (NID_hmac & 0xFF)) {
+            wc_HmacFree(&ctx->hash.hmac);
+        }
+        else {
+            switch (ctx->macType) {
+            #ifndef NO_MD5
+                case WC_HASH_TYPE_MD5:
+                    wc_Md5Free((wc_Md5*)&ctx->hash.digest);
+                    break;
+            #endif /* !NO_MD5 */
+
+            #ifndef NO_SHA
+                case WC_HASH_TYPE_SHA:
+                    wc_ShaFree((wc_Sha*)&ctx->hash.digest);
+                    break;
+            #endif /* !NO_SHA */
+
+            #ifdef WOLFSSL_SHA224
+                case WC_HASH_TYPE_SHA224:
+                    wc_Sha224Free((wc_Sha224*)&ctx->hash.digest);
+                    break;
+            #endif /* WOLFSSL_SHA224 */
+
+            #ifndef NO_SHA256
+                case WC_HASH_TYPE_SHA256:
+                    wc_Sha256Free((wc_Sha256*)&ctx->hash.digest);
+                    break;
+            #endif /* !NO_SHA256 */
+
+            #ifdef WOLFSSL_SHA384
+                case WC_HASH_TYPE_SHA384:
+                    wc_Sha384Free((wc_Sha384*)&ctx->hash.digest);
+                    break;
+            #endif /* WOLFSSL_SHA384 */
+            #ifdef WOLFSSL_SHA512
+                case WC_HASH_TYPE_SHA512:
+                    wc_Sha512Free((wc_Sha512*)&ctx->hash.digest);
+                    break;
+            #endif /* WOLFSSL_SHA512 */
+
+                default:
+                    return WOLFSSL_FAILURE;
+            }
+        }
         ForceZero(ctx, sizeof(*ctx));
         ctx->macType = 0xFF;
@@ -12667,9 +13337,8 @@
     /* return WOLFSSL_SUCCESS on ok, 0 on failure to match API compatibility */
     int  wolfSSL_EVP_CipherInit(WOLFSSL_EVP_CIPHER_CTX* ctx,
-                               const WOLFSSL_EVP_CIPHER* type, byte* key,
-                               byte* iv, int enc)
+                               const WOLFSSL_EVP_CIPHER* type, const byte* key,
+                               const byte* iv, int enc)
     {
-        int ret = -1;  /* failure local, during function 0 means success
-                          because internal functions work that way */
+        int ret = 0;
         (void)key;
         (void)iv;
@@ -12682,19 +13351,25 @@
         }
 
-        if (type == NULL && ctx->cipherType == 0xff) {
+        if (type == NULL && ctx->cipherType == WOLFSSL_EVP_CIPH_TYPE_INIT) {
             WOLFSSL_MSG("no type set");
             return 0;   /* failure */
         }
+        if (ctx->cipherType == WOLFSSL_EVP_CIPH_TYPE_INIT){
         ctx->bufUsed = 0;
         ctx->lastUsed = 0;
         ctx->flags   = 0;
+        }
+
+        XMEMSET(&ctx->cipher, 0, sizeof(ctx->cipher));
 
 #ifndef NO_AES
-        /* printf("cipherType=%d\n", ctx->cipherType); */
+    #ifdef HAVE_AES_CBC
+        #ifdef WOLFSSL_AES_128
         if (ctx->cipherType == AES_128_CBC_TYPE ||
             (type && XSTRNCMP(type, EVP_AES_128_CBC, EVP_AES_SIZE) == 0)) {
             WOLFSSL_MSG("EVP_AES_128_CBC");
             ctx->cipherType = AES_128_CBC_TYPE;
-            ctx->flags      = WOLFSSL_EVP_CIPH_CBC_MODE;
+            ctx->flags     &= ~WOLFSSL_EVP_CIPH_MODE;
+            ctx->flags     |= WOLFSSL_EVP_CIPH_CBC_MODE;
             ctx->keyLen     = 16;
             ctx->block_size = AES_BLOCK_SIZE;
@@ -12713,9 +13388,12 @@
             }
         }
-        else if (ctx->cipherType == AES_192_CBC_TYPE ||
+        #endif /* WOLFSSL_AES_128 */
+        #ifdef WOLFSSL_AES_192
+        if (ctx->cipherType == AES_192_CBC_TYPE ||
                  (type && XSTRNCMP(type, EVP_AES_192_CBC, EVP_AES_SIZE) == 0)) {
             WOLFSSL_MSG("EVP_AES_192_CBC");
             ctx->cipherType = AES_192_CBC_TYPE;
-            ctx->flags      = WOLFSSL_EVP_CIPH_CBC_MODE;
+            ctx->flags     &= ~WOLFSSL_EVP_CIPH_MODE;
+            ctx->flags     |= WOLFSSL_EVP_CIPH_CBC_MODE;
             ctx->keyLen     = 24;
             ctx->block_size = AES_BLOCK_SIZE;
@@ -12734,9 +13412,12 @@
             }
         }
-        else if (ctx->cipherType == AES_256_CBC_TYPE ||
+        #endif /* WOLFSSL_AES_192 */
+        #ifdef WOLFSSL_AES_256
+        if (ctx->cipherType == AES_256_CBC_TYPE ||
                  (type && XSTRNCMP(type, EVP_AES_256_CBC, EVP_AES_SIZE) == 0)) {
             WOLFSSL_MSG("EVP_AES_256_CBC");
             ctx->cipherType = AES_256_CBC_TYPE;
-            ctx->flags      = WOLFSSL_EVP_CIPH_CBC_MODE;
+            ctx->flags     &= ~WOLFSSL_EVP_CIPH_MODE;
+            ctx->flags     |= WOLFSSL_EVP_CIPH_CBC_MODE;
             ctx->keyLen     = 32;
             ctx->block_size = AES_BLOCK_SIZE;
@@ -12746,19 +13427,27 @@
                 ret = wc_AesSetKey(&ctx->cipher.aes, key, ctx->keyLen, iv,
                                 ctx->enc ? AES_ENCRYPTION : AES_DECRYPTION);
-                if (ret != 0)
+                if (ret != 0){
+                    WOLFSSL_MSG("wc_AesSetKey() failed");
                     return ret;
+            }
             }
             if (iv && key == NULL) {
                 ret = wc_AesSetIV(&ctx->cipher.aes, iv);
-                if (ret != 0)
+                if (ret != 0){
+                    WOLFSSL_MSG("wc_AesSetIV() failed");
                     return ret;
             }
         }
+        }
+        #endif /* WOLFSSL_AES_256 */
+    #endif /* HAVE_AES_CBC */
 #ifdef WOLFSSL_AES_COUNTER
-        else if (ctx->cipherType == AES_128_CTR_TYPE ||
+        #ifdef WOLFSSL_AES_128
+        if (ctx->cipherType == AES_128_CTR_TYPE ||
                  (type && XSTRNCMP(type, EVP_AES_128_CTR, EVP_AES_SIZE) == 0)) {
             WOLFSSL_MSG("EVP_AES_128_CTR");
+            ctx->flags     &= ~WOLFSSL_EVP_CIPH_MODE;
             ctx->cipherType = AES_128_CTR_TYPE;
-            ctx->flags      = WOLFSSL_EVP_CIPH_CTR_MODE;
+            ctx->flags     |= WOLFSSL_EVP_CIPH_CTR_MODE;
             ctx->keyLen     = 16;
             ctx->block_size = AES_BLOCK_SIZE;
@@ -12777,9 +13466,12 @@
             }
         }
-        else if (ctx->cipherType == AES_192_CTR_TYPE ||
+        #endif /* WOLFSSL_AES_128 */
+        #ifdef WOLFSSL_AES_192
+        if (ctx->cipherType == AES_192_CTR_TYPE ||
                  (type && XSTRNCMP(type, EVP_AES_192_CTR, EVP_AES_SIZE) == 0)) {
             WOLFSSL_MSG("EVP_AES_192_CTR");
             ctx->cipherType = AES_192_CTR_TYPE;
-            ctx->flags      = WOLFSSL_EVP_CIPH_CTR_MODE;
+            ctx->flags     &= ~WOLFSSL_EVP_CIPH_MODE;
+            ctx->flags     |= WOLFSSL_EVP_CIPH_CTR_MODE;
             ctx->keyLen     = 24;
             ctx->block_size = AES_BLOCK_SIZE;
@@ -12798,9 +13490,12 @@
             }
         }
-        else if (ctx->cipherType == AES_256_CTR_TYPE ||
+        #endif /* WOLFSSL_AES_192 */
+        #ifdef WOLFSSL_AES_256
+        if (ctx->cipherType == AES_256_CTR_TYPE ||
                  (type && XSTRNCMP(type, EVP_AES_256_CTR, EVP_AES_SIZE) == 0)) {
             WOLFSSL_MSG("EVP_AES_256_CTR");
             ctx->cipherType = AES_256_CTR_TYPE;
-            ctx->flags      = WOLFSSL_EVP_CIPH_CTR_MODE;
+            ctx->flags     &= ~WOLFSSL_EVP_CIPH_MODE;
+            ctx->flags     |= WOLFSSL_EVP_CIPH_CTR_MODE;
             ctx->keyLen     = 32;
             ctx->block_size = AES_BLOCK_SIZE;
@@ -12819,10 +13514,13 @@
             }
         }
-#endif /* WOLFSSL_AES_CTR */
-        else if (ctx->cipherType == AES_128_ECB_TYPE ||
+        #endif /* WOLFSSL_AES_256 */
+#endif /* WOLFSSL_AES_COUNTER */
+        #ifdef WOLFSSL_AES_128
+        if (ctx->cipherType == AES_128_ECB_TYPE ||
             (type && XSTRNCMP(type, EVP_AES_128_ECB, EVP_AES_SIZE) == 0)) {
             WOLFSSL_MSG("EVP_AES_128_ECB");
             ctx->cipherType = AES_128_ECB_TYPE;
-            ctx->flags      = WOLFSSL_EVP_CIPH_ECB_MODE;
+            ctx->flags     &= ~WOLFSSL_EVP_CIPH_MODE;
+            ctx->flags     |= WOLFSSL_EVP_CIPH_ECB_MODE;
             ctx->keyLen     = 16;
             ctx->block_size = AES_BLOCK_SIZE;
@@ -12836,9 +13534,12 @@
                 return ret;
         }
-        else if (ctx->cipherType == AES_192_ECB_TYPE ||
+        #endif /* WOLFSSL_AES_128 */
+        #ifdef WOLFSSL_AES_192
+        if (ctx->cipherType == AES_192_ECB_TYPE ||
                  (type && XSTRNCMP(type, EVP_AES_192_ECB, EVP_AES_SIZE) == 0)) {
             WOLFSSL_MSG("EVP_AES_192_ECB");
             ctx->cipherType = AES_192_ECB_TYPE;
-            ctx->flags      = WOLFSSL_EVP_CIPH_ECB_MODE;
+            ctx->flags     &= ~WOLFSSL_EVP_CIPH_MODE;
+            ctx->flags     |= WOLFSSL_EVP_CIPH_ECB_MODE;
             ctx->keyLen     = 24;
             ctx->block_size = AES_BLOCK_SIZE;
@@ -12846,5 +13547,4 @@
                 ctx->enc = enc ? 1 : 0;
             if (key) {
-                if(ctx->enc)
                 ret = wc_AesSetKey(&ctx->cipher.aes, key, ctx->keyLen, NULL,
                       ctx->enc ? AES_ENCRYPTION : AES_DECRYPTION);
@@ -12853,9 +13553,12 @@
                 return ret;
         }
-        else if (ctx->cipherType == AES_256_ECB_TYPE ||
+        #endif /* WOLFSSL_AES_192 */
+        #ifdef WOLFSSL_AES_256
+        if (ctx->cipherType == AES_256_ECB_TYPE ||
                  (type && XSTRNCMP(type, EVP_AES_256_ECB, EVP_AES_SIZE) == 0)) {
             WOLFSSL_MSG("EVP_AES_256_ECB");
             ctx->cipherType = AES_256_ECB_TYPE;
-            ctx->flags      = WOLFSSL_EVP_CIPH_ECB_MODE;
+            ctx->flags     &= ~WOLFSSL_EVP_CIPH_MODE;
+            ctx->flags     |= WOLFSSL_EVP_CIPH_ECB_MODE;
             ctx->keyLen     = 32;
             ctx->block_size = AES_BLOCK_SIZE;
@@ -12869,4 +13572,5 @@
                 return ret;
         }
+        #endif /* WOLFSSL_AES_256 */
 #endif /* NO_AES */
 
@@ -12876,5 +13580,6 @@
             WOLFSSL_MSG("EVP_DES_CBC");
             ctx->cipherType = DES_CBC_TYPE;
-            ctx->flags      = WOLFSSL_EVP_CIPH_CBC_MODE;
+            ctx->flags     &= ~WOLFSSL_EVP_CIPH_MODE;
+            ctx->flags     |= WOLFSSL_EVP_CIPH_CBC_MODE;
             ctx->keyLen     = 8;
             ctx->block_size = DES_BLOCK_SIZE;
@@ -12896,5 +13601,6 @@
             WOLFSSL_MSG("EVP_DES_ECB");
             ctx->cipherType = DES_ECB_TYPE;
-            ctx->flags      = WOLFSSL_EVP_CIPH_ECB_MODE;
+            ctx->flags     &= ~WOLFSSL_EVP_CIPH_MODE;
+            ctx->flags     |= WOLFSSL_EVP_CIPH_ECB_MODE;
             ctx->keyLen     = 8;
             ctx->block_size = DES_BLOCK_SIZE;
@@ -12902,4 +13608,5 @@
                 ctx->enc = enc ? 1 : 0;
             if (key) {
+                WOLFSSL_MSG("Des_SetKey");
                 ret = wc_Des_SetKey(&ctx->cipher.des, key, NULL,
                           ctx->enc ? DES_ENCRYPTION : DES_DECRYPTION);
@@ -12914,5 +13621,6 @@
             WOLFSSL_MSG("EVP_DES_EDE3_CBC");
             ctx->cipherType = DES_EDE3_CBC_TYPE;
-            ctx->flags      = WOLFSSL_EVP_CIPH_CBC_MODE;
+            ctx->flags     &= ~WOLFSSL_EVP_CIPH_MODE;
+            ctx->flags     |= WOLFSSL_EVP_CIPH_CBC_MODE;
             ctx->keyLen     = 24;
             ctx->block_size = DES_BLOCK_SIZE;
@@ -12937,5 +13645,6 @@
             WOLFSSL_MSG("EVP_DES_EDE3_ECB");
             ctx->cipherType = DES_EDE3_ECB_TYPE;
-            ctx->flags      = WOLFSSL_EVP_CIPH_ECB_MODE;
+            ctx->flags     &= ~WOLFSSL_EVP_CIPH_MODE;
+            ctx->flags     |= WOLFSSL_EVP_CIPH_ECB_MODE;
             ctx->keyLen     = 24;
             ctx->block_size = DES_BLOCK_SIZE;
@@ -12955,10 +13664,11 @@
             WOLFSSL_MSG("ARC4");
             ctx->cipherType = ARC4_TYPE;
-            ctx->flags      = WOLFSSL_EVP_CIPH_STREAM_CIPHER;
+            ctx->flags     &= ~WOLFSSL_EVP_CIPH_MODE;
+            ctx->flags     |= WOLFSSL_EVP_CIPH_STREAM_CIPHER;
+            ctx->block_size = 1;
             if (ctx->keyLen == 0)  /* user may have already set */
                 ctx->keyLen = 16;  /* default to 128 */
             if (key)
                 wc_Arc4SetKey(&ctx->cipher.arc4, key, ctx->keyLen);
-            ret = 0;  /* success */
         }
 #endif /* NO_RC4 */
@@ -12968,6 +13678,8 @@
             WOLFSSL_MSG("EVP_IDEA_CBC");
             ctx->cipherType = IDEA_CBC_TYPE;
-            ctx->flags      = WOLFSSL_EVP_CIPH_CBC_MODE;
+            ctx->flags     &= ~WOLFSSL_EVP_CIPH_MODE;
+            ctx->flags     |= WOLFSSL_EVP_CIPH_CBC_MODE;
             ctx->keyLen     = IDEA_KEY_SIZE;
+            ctx->block_size = 8;
             if (enc == 0 || enc == 1)
                 ctx->enc = enc ? 1 : 0;
@@ -12989,11 +13701,8 @@
             ctx->cipherType = NULL_CIPHER_TYPE;
             ctx->keyLen = 0;
-            ret = 0;  /* success */
-        }
-
-        if (ret == 0)
+            ctx->block_size = 16;
+        }
+        (void)ret; /* remove warning. If execution reaches this point, ret=0 */
             return WOLFSSL_SUCCESS;
-        else
-            return 0;  /* overall failure */
     }
 
@@ -13071,5 +13780,5 @@
             case AES_256_CTR_TYPE :
                     WOLFSSL_MSG("AES CTR");
-                    wc_AesCtrEncrypt(&ctx->cipher.aes, dst, src, len);
+                    ret = wc_AesCtrEncrypt(&ctx->cipher.aes, dst, src, len);
                 break;
 #endif /* WOLFSSL_AES_COUNTER */
@@ -13290,10 +13999,10 @@
 
         if (XSTRNCMP(type, "SHA256", 6) == 0) {
-             ctx->macType = WC_SHA256;
+             ctx->macType = WC_HASH_TYPE_SHA256;
              ret = wolfSSL_SHA256_Init(&(ctx->hash.digest.sha256));
         }
     #ifdef WOLFSSL_SHA224
         else if (XSTRNCMP(type, "SHA224", 6) == 0) {
-             ctx->macType = WC_SHA224;
+             ctx->macType = WC_HASH_TYPE_SHA224;
              ret = wolfSSL_SHA224_Init(&(ctx->hash.digest.sha224));
         }
@@ -13301,5 +14010,5 @@
     #ifdef WOLFSSL_SHA384
         else if (XSTRNCMP(type, "SHA384", 6) == 0) {
-             ctx->macType = WC_SHA384;
+             ctx->macType = WC_HASH_TYPE_SHA384;
              ret = wolfSSL_SHA384_Init(&(ctx->hash.digest.sha384));
         }
@@ -13307,11 +14016,17 @@
     #ifdef WOLFSSL_SHA512
         else if (XSTRNCMP(type, "SHA512", 6) == 0) {
-             ctx->macType = WC_SHA512;
+             ctx->macType = WC_HASH_TYPE_SHA512;
              ret = wolfSSL_SHA512_Init(&(ctx->hash.digest.sha512));
+        }
+    #endif
+    #ifndef NO_MD4
+        else if (XSTRNCMP(type, "MD4", 3) == 0) {
+            ctx->macType = WC_HASH_TYPE_MD4;
+            wolfSSL_MD4_Init(&(ctx->hash.digest.md4));
         }
     #endif
     #ifndef NO_MD5
         else if (XSTRNCMP(type, "MD5", 3) == 0) {
-            ctx->macType = WC_MD5;
+            ctx->macType = WC_HASH_TYPE_MD5;
             ret = wolfSSL_MD5_Init(&(ctx->hash.digest.md5));
         }
@@ -13320,5 +14035,5 @@
         /* has to be last since would pick or 224, 256, 384, or 512 too */
         else if (XSTRNCMP(type, "SHA", 3) == 0) {
-             ctx->macType = WC_SHA;
+             ctx->macType = WC_HASH_TYPE_SHA;
              ret = wolfSSL_SHA_Init(&(ctx->hash.digest.sha));
         }
@@ -13331,13 +14046,19 @@
 
 
-    /* WOLFSSL_SUCCESS on ok */
+    /* WOLFSSL_SUCCESS on ok, WOLFSSL_FAILURE on failure */
     int wolfSSL_EVP_DigestUpdate(WOLFSSL_EVP_MD_CTX* ctx, const void* data,
-                                unsigned long sz)
+                                size_t sz)
     {
         WOLFSSL_ENTER("EVP_DigestUpdate");
 
         switch (ctx->macType) {
+#ifndef NO_MD4
+            case WC_HASH_TYPE_MD4:
+                wolfSSL_MD4_Update((MD4_CTX*)&ctx->hash, data,
+                                  (unsigned long)sz);
+                break;
+#endif
 #ifndef NO_MD5
-            case WC_MD5:
+            case WC_HASH_TYPE_MD5:
                 wolfSSL_MD5_Update((MD5_CTX*)&ctx->hash, data,
                                   (unsigned long)sz);
@@ -13345,5 +14066,5 @@
 #endif
 #ifndef NO_SHA
-            case WC_SHA:
+            case WC_HASH_TYPE_SHA:
                 wolfSSL_SHA_Update((SHA_CTX*)&ctx->hash, data,
                                   (unsigned long)sz);
@@ -13351,5 +14072,5 @@
 #endif
 #ifdef WOLFSSL_SHA224
-            case WC_SHA224:
+            case WC_HASH_TYPE_SHA224:
                 wolfSSL_SHA224_Update((SHA224_CTX*)&ctx->hash, data,
                                      (unsigned long)sz);
@@ -13357,5 +14078,5 @@
 #endif
 #ifndef NO_SHA256
-            case WC_SHA256:
+            case WC_HASH_TYPE_SHA256:
                 wolfSSL_SHA256_Update((SHA256_CTX*)&ctx->hash, data,
                                      (unsigned long)sz);
@@ -13363,5 +14084,5 @@
 #endif /* !NO_SHA256 */
 #ifdef WOLFSSL_SHA384
-            case WC_SHA384:
+            case WC_HASH_TYPE_SHA384:
                 wolfSSL_SHA384_Update((SHA384_CTX*)&ctx->hash, data,
                                      (unsigned long)sz);
@@ -13369,5 +14090,5 @@
 #endif
 #ifdef WOLFSSL_SHA512
-            case WC_SHA512:
+            case WC_HASH_TYPE_SHA512:
                 wolfSSL_SHA512_Update((SHA512_CTX*)&ctx->hash, data,
                                      (unsigned long)sz);
@@ -13375,5 +14096,5 @@
 #endif /* WOLFSSL_SHA512 */
             default:
-                return BAD_FUNC_ARG;
+                return WOLFSSL_FAILURE;
         }
 
@@ -13388,6 +14109,12 @@
         WOLFSSL_ENTER("EVP_DigestFinal");
         switch (ctx->macType) {
+#ifndef NO_MD4
+            case WC_HASH_TYPE_MD4:
+                wolfSSL_MD4_Final(md, (MD4_CTX*)&ctx->hash);
+                if (s) *s = MD4_DIGEST_SIZE;
+                break;
+#endif
 #ifndef NO_MD5
-            case WC_MD5:
+            case WC_HASH_TYPE_MD5:
                 wolfSSL_MD5_Final(md, (MD5_CTX*)&ctx->hash);
                 if (s) *s = WC_MD5_DIGEST_SIZE;
@@ -13395,5 +14122,5 @@
 #endif
 #ifndef NO_SHA
-            case WC_SHA:
+            case WC_HASH_TYPE_SHA:
                 wolfSSL_SHA_Final(md, (SHA_CTX*)&ctx->hash);
                 if (s) *s = WC_SHA_DIGEST_SIZE;
@@ -13401,5 +14128,5 @@
 #endif
 #ifdef WOLFSSL_SHA224
-            case WC_SHA224:
+            case WC_HASH_TYPE_SHA224:
                 wolfSSL_SHA224_Final(md, (SHA224_CTX*)&ctx->hash);
                 if (s) *s = WC_SHA224_DIGEST_SIZE;
@@ -13407,5 +14134,5 @@
 #endif
 #ifndef NO_SHA256
-            case WC_SHA256:
+            case WC_HASH_TYPE_SHA256:
                 wolfSSL_SHA256_Final(md, (SHA256_CTX*)&ctx->hash);
                 if (s) *s = WC_SHA256_DIGEST_SIZE;
@@ -13413,5 +14140,5 @@
 #endif /* !NO_SHA256 */
 #ifdef WOLFSSL_SHA384
-            case WC_SHA384:
+            case WC_HASH_TYPE_SHA384:
                 wolfSSL_SHA384_Final(md, (SHA384_CTX*)&ctx->hash);
                 if (s) *s = WC_SHA384_DIGEST_SIZE;
@@ -13419,5 +14146,5 @@
 #endif
 #ifdef WOLFSSL_SHA512
-            case WC_SHA512:
+            case WC_HASH_TYPE_SHA512:
                 wolfSSL_SHA512_Final(md, (SHA512_CTX*)&ctx->hash);
                 if (s) *s = WC_SHA512_DIGEST_SIZE;
@@ -13425,5 +14152,5 @@
 #endif /* WOLFSSL_SHA512 */
             default:
-                return BAD_FUNC_ARG;
+                return WOLFSSL_FAILURE;
         }
 
@@ -13446,4 +14173,5 @@
     {
         int type;
+        int mdlen;
         unsigned char* ret = NULL;
 #ifdef WOLFSSL_SMALL_STACK
@@ -13454,14 +14182,49 @@
         void* heap = NULL;
 
-        WOLFSSL_ENTER("HMAC");
-        if (!md)
+        WOLFSSL_ENTER("wolfSSL_HMAC");
+        if (!md) {
+            WOLFSSL_MSG("Static buffer not supported, pass in md buffer");
             return NULL;  /* no static buffer support */
-
-        if (XSTRNCMP(evp_md, "MD5", 3) == 0)
+        }
+
+#ifndef NO_MD5
+        if (XSTRNCMP(evp_md, "MD5", 3) == 0) {
             type = WC_MD5;
-        else if (XSTRNCMP(evp_md, "SHA", 3) == 0)
+            mdlen = WC_MD5_DIGEST_SIZE;
+        } else
+#endif
+#ifdef WOLFSSL_SHA224
+        if (XSTRNCMP(evp_md, "SHA224", 6) == 0) {
+            type = WC_SHA224;
+            mdlen = WC_SHA224_DIGEST_SIZE;
+        } else
+#endif
+#ifndef NO_SHA256
+        if (XSTRNCMP(evp_md, "SHA256", 6) == 0) {
+            type = WC_SHA256;
+            mdlen = WC_SHA256_DIGEST_SIZE;
+        } else
+#endif
+#ifdef WOLFSSL_SHA384
+        if (XSTRNCMP(evp_md, "SHA384", 6) == 0) {
+            type = WC_SHA384;
+            mdlen = WC_SHA384_DIGEST_SIZE;
+        } else
+#endif
+#ifdef WOLFSSL_SHA512
+        if (XSTRNCMP(evp_md, "SHA512", 6) == 0) {
+            type = WC_SHA512;
+            mdlen = WC_SHA512_DIGEST_SIZE;
+        } else
+#endif
+#ifndef NO_SHA
+        if (XSTRNCMP(evp_md, "SHA", 3) == 0) {
             type = WC_SHA;
-        else
+            mdlen = WC_SHA_DIGEST_SIZE;
+        } else
+#endif
+        {
             return NULL;
+        }
 
     #ifdef WOLFSSL_SMALL_STACK
@@ -13476,6 +14239,5 @@
                     if (wc_HmacFinal(hmac, md) == 0) {
                         if (md_len)
-                            *md_len = (type == WC_MD5) ? (int)WC_MD5_DIGEST_SIZE
-                                                    : (int)WC_SHA_DIGEST_SIZE;
+                            *md_len = mdlen;
                         ret = md;
                     }
@@ -13489,4 +14251,5 @@
     #endif
 
+        (void)evp_md;
         return ret;
     }
@@ -13496,7 +14259,22 @@
         WOLFSSL_ENTER("wolfSSL_ERR_clear_error");
 
-#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+#if defined(DEBUG_WOLFSSL) || defined(WOLFSSL_NGINX)
         wc_ClearErrorNodes();
 #endif
+    }
+
+
+    /* frees all nodes in the current threads error queue
+     *
+     * id  thread id. ERR_remove_state is depriciated and id is ignored. The
+     *     current threads queue will be free'd.
+     */
+    void wolfSSL_ERR_remove_state(unsigned long id)
+    {
+        WOLFSSL_ENTER("wolfSSL_ERR_remove_state");
+        (void)id;
+        if (wc_ERR_remove_state() != 0) {
+            WOLFSSL_MSG("Error with removing the state");
+        }
     }
 
@@ -13508,5 +14286,5 @@
 
 
-
+    #ifndef NO_WOLFSSL_STUB
     void wolfSSL_RAND_add(const void* add, int len, double entropy)
     {
@@ -13514,18 +14292,86 @@
         (void)len;
         (void)entropy;
-
+        WOLFSSL_STUB("RAND_add");
         /* wolfSSL seeds/adds internally, use explicit RNG if you want
            to take control */
     }
-
+    #endif
 
 #ifndef NO_DES3
-    /* WOLFSSL_SUCCESS on ok */
+    /* 0 on ok */
     int wolfSSL_DES_key_sched(WOLFSSL_const_DES_cblock* key,
                               WOLFSSL_DES_key_schedule* schedule)
     {
-        WOLFSSL_ENTER("DES_key_sched");
-        XMEMCPY(schedule, key, sizeof(const_DES_cblock));
-        return WOLFSSL_SUCCESS;
+        WOLFSSL_ENTER("wolfSSL_DES_key_sched");
+
+        if (key == NULL || schedule == NULL) {
+            WOLFSSL_MSG("Null argument passed in");
+        }
+        else {
+            XMEMCPY(schedule, key, sizeof(WOLFSSL_const_DES_cblock));
+        }
+
+        return 0;
+    }
+
+
+    /* intended to behave similar to Kerberos mit_des_cbc_cksum
+     * return the last 4 bytes of cipher text */
+    WOLFSSL_DES_LONG wolfSSL_DES_cbc_cksum(const unsigned char* in,
+            WOLFSSL_DES_cblock* out, long length, WOLFSSL_DES_key_schedule* sc,
+            WOLFSSL_const_DES_cblock* iv)
+    {
+        WOLFSSL_DES_LONG ret;
+        unsigned char* tmp;
+        unsigned char* data   = (unsigned char*)in;
+        long           dataSz = length;
+        byte dynamicFlag = 0; /* when padding the buffer created needs free'd */
+
+        WOLFSSL_ENTER("wolfSSL_DES_cbc_cksum");
+
+        if (in == NULL || out == NULL || sc == NULL || iv == NULL) {
+            WOLFSSL_MSG("Bad argument passed in");
+            return 0;
+        }
+
+        /* if input length is not a multiple of DES_BLOCK_SIZE pad with 0s */
+        if (dataSz % DES_BLOCK_SIZE) {
+            dataSz += DES_BLOCK_SIZE - (dataSz % DES_BLOCK_SIZE);
+            data = (unsigned char*)XMALLOC(dataSz, NULL,
+                                           DYNAMIC_TYPE_TMP_BUFFER);
+            if (data == NULL) {
+                WOLFSSL_MSG("Issue creating temporary buffer");
+                return 0;
+            }
+            dynamicFlag = 1; /* set to free buffer at end */
+            XMEMCPY(data, in, length);
+            XMEMSET(data + length, 0, dataSz - length); /* padding */
+        }
+
+        tmp = (unsigned char*)XMALLOC(dataSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (tmp == NULL) {
+            WOLFSSL_MSG("Issue creating temporary buffer");
+            if (dynamicFlag == 1) {
+                XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            }
+            return 0;
+        }
+
+        wolfSSL_DES_cbc_encrypt(data, tmp, dataSz, sc,
+                (WOLFSSL_DES_cblock*)iv, 1);
+        XMEMCPY((unsigned char*)out, tmp + (dataSz - DES_BLOCK_SIZE),
+                DES_BLOCK_SIZE);
+
+        ret = (((*((unsigned char*)out + 4) & 0xFF) << 24)|
+               ((*((unsigned char*)out + 5) & 0xFF) << 16)|
+               ((*((unsigned char*)out + 6) & 0xFF) << 8) |
+               (*((unsigned char*)out + 7) & 0xFF));
+
+        XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (dynamicFlag == 1) {
+            XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        }
+
+        return ret;
     }
 
@@ -13537,4 +14383,7 @@
     {
         Des myDes;
+        byte lastblock[DES_BLOCK_SIZE];
+        int  lb_sz;
+        long  blk;
 
         WOLFSSL_ENTER("DES_cbc_encrypt");
@@ -13542,9 +14391,23 @@
         /* OpenSSL compat, no ret */
         wc_Des_SetKey(&myDes, (const byte*)schedule, (const byte*)ivec, !enc);
-
-        if (enc)
-            wc_Des_CbcEncrypt(&myDes, output, input, (word32)length);
-        else
-            wc_Des_CbcDecrypt(&myDes, output, input, (word32)length);
+        lb_sz = length%DES_BLOCK_SIZE;
+        blk   = length/DES_BLOCK_SIZE;
+
+        if (enc){
+            wc_Des_CbcEncrypt(&myDes, output, input, (word32)blk*DES_BLOCK_SIZE);
+            if(lb_sz){
+                XMEMSET(lastblock, 0, DES_BLOCK_SIZE);
+                XMEMCPY(lastblock, input+length-lb_sz, lb_sz);
+                wc_Des_CbcEncrypt(&myDes, output+blk*DES_BLOCK_SIZE,
+                    lastblock, (word32)DES_BLOCK_SIZE);
+            }
+        }
+        else {
+            wc_Des_CbcDecrypt(&myDes, output, input, (word32)blk*DES_BLOCK_SIZE);
+            if(lb_sz){
+                wc_Des_CbcDecrypt(&myDes, lastblock, input+length-lb_sz, (word32)DES_BLOCK_SIZE);
+                XMEMCPY(output+length-lb_sz, lastblock, lb_sz);
+            }
+        }
     }
 
@@ -13560,4 +14423,7 @@
         Des3 des;
         byte key[24];/* EDE uses 24 size key */
+        byte lastblock[DES_BLOCK_SIZE];
+        int  lb_sz;
+        long  blk;
 
         WOLFSSL_ENTER("wolfSSL_DES_ede3_cbc_encrypt");
@@ -13567,13 +14433,29 @@
         XMEMCPY(&key[DES_BLOCK_SIZE], *ks2, DES_BLOCK_SIZE);
         XMEMCPY(&key[DES_BLOCK_SIZE * 2], *ks3, DES_BLOCK_SIZE);
+        lb_sz = sz%DES_BLOCK_SIZE;
+        blk   = sz/DES_BLOCK_SIZE;
+
+        /* OpenSSL compat, no ret */
+        wc_Des3Init(&des, NULL, INVALID_DEVID);
 
         if (enc) {
             wc_Des3_SetKey(&des, key, (const byte*)ivec, DES_ENCRYPTION);
-            wc_Des3_CbcEncrypt(&des, output, input, (word32)sz);
+            wc_Des3_CbcEncrypt(&des, output, input, (word32)blk*DES_BLOCK_SIZE);
+            if(lb_sz){
+                XMEMSET(lastblock, 0, DES_BLOCK_SIZE);
+                XMEMCPY(lastblock, input+sz-lb_sz, lb_sz);
+                wc_Des3_CbcEncrypt(&des, output+blk*DES_BLOCK_SIZE,
+                    lastblock, (word32)DES_BLOCK_SIZE);
+            }
         }
         else {
             wc_Des3_SetKey(&des, key, (const byte*)ivec, DES_DECRYPTION);
-            wc_Des3_CbcDecrypt(&des, output, input, (word32)sz);
-        }
+            wc_Des3_CbcDecrypt(&des, output, input, (word32)blk*DES_BLOCK_SIZE);
+            if(lb_sz){
+                wc_Des3_CbcDecrypt(&des, lastblock, input+sz-lb_sz, (word32)DES_BLOCK_SIZE);
+                XMEMCPY(output+sz-lb_sz, lastblock, lb_sz);
+        }
+    }
+        wc_Des3Free(&des);
     }
 
@@ -13586,4 +14468,8 @@
     {
         Des myDes;
+        byte lastblock[DES_BLOCK_SIZE];
+        int  lb_sz;
+        long idx = length;
+        long blk;
 
         WOLFSSL_ENTER("DES_ncbc_encrypt");
@@ -13591,11 +14477,33 @@
         /* OpenSSL compat, no ret */
         wc_Des_SetKey(&myDes, (const byte*)schedule, (const byte*)ivec, !enc);
-
-        if (enc)
-            wc_Des_CbcEncrypt(&myDes, output, input, (word32)length);
-        else
-            wc_Des_CbcDecrypt(&myDes, output, input, (word32)length);
-
-        XMEMCPY(ivec, output + length - sizeof(DES_cblock), sizeof(DES_cblock));
+        lb_sz = length%DES_BLOCK_SIZE;
+        blk   = length/DES_BLOCK_SIZE;
+        idx  -= sizeof(DES_cblock);
+        if (lb_sz) {
+            idx += DES_BLOCK_SIZE - lb_sz;
+        }
+        if (enc){
+            wc_Des_CbcEncrypt(&myDes, output, input,
+                    (word32)blk * DES_BLOCK_SIZE);
+            if (lb_sz){
+                XMEMSET(lastblock, 0, DES_BLOCK_SIZE);
+                XMEMCPY(lastblock, input+length-lb_sz, lb_sz);
+                wc_Des_CbcEncrypt(&myDes, output + blk * DES_BLOCK_SIZE,
+                    lastblock, (word32)DES_BLOCK_SIZE);
+            }
+            XMEMCPY(ivec, output + idx, sizeof(DES_cblock));
+        } else {
+            WOLFSSL_DES_cblock tmp;
+            XMEMCPY(tmp, input + idx, sizeof(DES_cblock));
+            wc_Des_CbcDecrypt(&myDes, output, input,
+                    (word32)blk * DES_BLOCK_SIZE);
+            if (lb_sz){
+                wc_Des_CbcDecrypt(&myDes, lastblock, input + length - lb_sz,
+                        (word32)DES_BLOCK_SIZE);
+                XMEMCPY(output+length-lb_sz, lastblock, lb_sz);
+            }
+            XMEMCPY(ivec, tmp, sizeof(WOLFSSL_DES_cblock));
+        }
+
     }
 
@@ -13609,11 +14517,4 @@
 
 
-    void wolfSSL_ERR_remove_state(unsigned long state)
-    {
-        /* TODO: GetErrors().Remove(); */
-        (void)state;
-    }
-
-
     void wolfSSL_EVP_cleanup(void)
     {
@@ -13626,5 +14527,4 @@
         /* nothing to do here */
     }
-
 
     int wolfSSL_clear(WOLFSSL* ssl)
@@ -13672,5 +14572,7 @@
 #endif
         }
-
+#ifdef SESSION_CERTS
+        ssl->session.chain.count = 0;
+#endif
 #ifdef KEEP_PEER_CERT
         FreeX509(&ssl->peerCert);
@@ -13680,5 +14582,4 @@
         return WOLFSSL_SUCCESS;
     }
-
 
     long wolfSSL_SSL_SESSION_set_timeout(WOLFSSL_SESSION* ses, long t)
@@ -13695,5 +14596,7 @@
     }
 
-
+#endif
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
     long wolfSSL_CTX_set_mode(WOLFSSL_CTX* ctx, long mode)
     {
@@ -13706,22 +14609,29 @@
         return mode;
     }
-
-
+#endif
+
+#ifdef OPENSSL_EXTRA
+
+    #ifndef NO_WOLFSSL_STUB
     long wolfSSL_SSL_get_mode(WOLFSSL* ssl)
     {
         /* TODO: */
         (void)ssl;
+        WOLFSSL_STUB("SSL_get_mode");
         return 0;
     }
-
-
+    #endif
+
+    #ifndef NO_WOLFSSL_STUB
     long wolfSSL_CTX_get_mode(WOLFSSL_CTX* ctx)
     {
         /* TODO: */
         (void)ctx;
+        WOLFSSL_STUB("SSL_CTX_get_mode");
         return 0;
     }
-
-
+    #endif
+
+    #ifndef NO_WOLFSSL_STUB
     void wolfSSL_CTX_set_default_read_ahead(WOLFSSL_CTX* ctx, int m)
     {
@@ -13729,16 +14639,58 @@
         (void)ctx;
         (void)m;
-    }
-
-
+        WOLFSSL_STUB("SSL_CTX_set_default_read_ahead");
+    }
+    #endif
+
+
+    /* Storing app session context id, this value is inherited by WOLFSSL
+     * objects created from WOLFSSL_CTX. Any session that is imported with a
+     * different session context id will be rejected.
+     *
+     * ctx         structure to set context in
+     * sid_ctx     value of context to set
+     * sid_ctx_len length of sid_ctx buffer
+     *
+     * Returns SSL_SUCCESS in success case and SSL_FAILURE when failing
+     */
     int wolfSSL_CTX_set_session_id_context(WOLFSSL_CTX* ctx,
                                            const unsigned char* sid_ctx,
                                            unsigned int sid_ctx_len)
     {
+        WOLFSSL_ENTER("SSL_CTX_set_session_id_context");
+
         /* No application specific context needed for wolfSSL */
-        (void)ctx;
-        (void)sid_ctx;
-        (void)sid_ctx_len;
-        return WOLFSSL_SUCCESS;
+        if (sid_ctx_len > ID_LEN || ctx == NULL || sid_ctx == NULL) {
+            return SSL_FAILURE;
+        }
+        XMEMCPY(ctx->sessionCtx, sid_ctx, sid_ctx_len);
+        ctx->sessionCtxSz = (byte)sid_ctx_len;
+
+        return SSL_SUCCESS;
+    }
+
+
+
+    /* Storing app session context id. Any session that is imported with a
+     * different session context id will be rejected.
+     *
+     * ssl  structure to set context in
+     * id   value of context to set
+     * len  length of sid_ctx buffer
+     *
+     * Returns SSL_SUCCESS in success case and SSL_FAILURE when failing
+     */
+    int wolfSSL_set_session_id_context(WOLFSSL* ssl, const unsigned char* id,
+                                   unsigned int len)
+    {
+        WOLFSSL_STUB("wolfSSL_set_session_id_context");
+
+        if (len > ID_LEN || ssl == NULL || id == NULL) {
+            return SSL_FAILURE;
+        }
+        XMEMCPY(ssl->sessionCtx, id, len);
+        ssl->sessionCtxSz = (byte)len;
+
+        return SSL_SUCCESS;
     }
 
@@ -13754,34 +14706,145 @@
     }
 
+
+    /* returns the unsigned error value and increments the pointer into the
+     * error queue.
+     *
+     * file  pointer to file name
+     * line  gets set to line number of error when not NULL
+     */
+    unsigned long wolfSSL_ERR_get_error_line(const char** file, int* line)
+    {
+    #ifdef DEBUG_WOLFSSL
+        int ret = wc_PullErrorNode(file, NULL, line);
+        if (ret < 0) {
+            if (ret == BAD_STATE_E) return 0; /* no errors in queue */
+            WOLFSSL_MSG("Issue getting error node");
+            WOLFSSL_LEAVE("wolfSSL_ERR_get_error_line", ret);
+            ret = 0 - ret; /* return absolute value of error */
+
+            /* panic and try to clear out nodes */
+            wc_ClearErrorNodes();
+        }
+        return (unsigned long)ret;
+    #else
+        (void)file;
+        (void)line;
+
+        return 0;
+    #endif
+    }
+
+
+#ifdef DEBUG_WOLFSSL
+    static const char WOLFSSL_SYS_ACCEPT_T[]  = "accept";
+    static const char WOLFSSL_SYS_BIND_T[]    = "bind";
+    static const char WOLFSSL_SYS_CONNECT_T[] = "connect";
+    static const char WOLFSSL_SYS_FOPEN_T[]   = "fopen";
+    static const char WOLFSSL_SYS_FREAD_T[]   = "fread";
+    static const char WOLFSSL_SYS_GETADDRINFO_T[] = "getaddrinfo";
+    static const char WOLFSSL_SYS_GETSOCKOPT_T[]  = "getsockopt";
+    static const char WOLFSSL_SYS_GETSOCKNAME_T[] = "getsockname";
+    static const char WOLFSSL_SYS_GETHOSTBYNAME_T[] = "gethostbyname";
+    static const char WOLFSSL_SYS_GETNAMEINFO_T[]   = "getnameinfo";
+    static const char WOLFSSL_SYS_GETSERVBYNAME_T[] = "getservbyname";
+    static const char WOLFSSL_SYS_IOCTLSOCKET_T[]   = "ioctlsocket";
+    static const char WOLFSSL_SYS_LISTEN_T[]        = "listen";
+    static const char WOLFSSL_SYS_OPENDIR_T[]       = "opendir";
+    static const char WOLFSSL_SYS_SETSOCKOPT_T[]    = "setsockopt";
+    static const char WOLFSSL_SYS_SOCKET_T[]        = "socket";
+
+    /* switch with int mapped to function name for compatibility */
+    static const char* wolfSSL_ERR_sys_func(int fun)
+    {
+        switch (fun) {
+            case WOLFSSL_SYS_ACCEPT:      return WOLFSSL_SYS_ACCEPT_T;
+            case WOLFSSL_SYS_BIND:        return WOLFSSL_SYS_BIND_T;
+            case WOLFSSL_SYS_CONNECT:     return WOLFSSL_SYS_CONNECT_T;
+            case WOLFSSL_SYS_FOPEN:       return WOLFSSL_SYS_FOPEN_T;
+            case WOLFSSL_SYS_FREAD:       return WOLFSSL_SYS_FREAD_T;
+            case WOLFSSL_SYS_GETADDRINFO: return WOLFSSL_SYS_GETADDRINFO_T;
+            case WOLFSSL_SYS_GETSOCKOPT:  return WOLFSSL_SYS_GETSOCKOPT_T;
+            case WOLFSSL_SYS_GETSOCKNAME: return WOLFSSL_SYS_GETSOCKNAME_T;
+            case WOLFSSL_SYS_GETHOSTBYNAME: return WOLFSSL_SYS_GETHOSTBYNAME_T;
+            case WOLFSSL_SYS_GETNAMEINFO: return WOLFSSL_SYS_GETNAMEINFO_T;
+            case WOLFSSL_SYS_GETSERVBYNAME: return WOLFSSL_SYS_GETSERVBYNAME_T;
+            case WOLFSSL_SYS_IOCTLSOCKET: return WOLFSSL_SYS_IOCTLSOCKET_T;
+            case WOLFSSL_SYS_LISTEN:      return WOLFSSL_SYS_LISTEN_T;
+            case WOLFSSL_SYS_OPENDIR:     return WOLFSSL_SYS_OPENDIR_T;
+            case WOLFSSL_SYS_SETSOCKOPT:  return WOLFSSL_SYS_SETSOCKOPT_T;
+            case WOLFSSL_SYS_SOCKET:      return WOLFSSL_SYS_SOCKET_T;
+            default:
+                return "NULL";
+        }
+        }
+#endif /* DEBUG_WOLFSSL */
+
+
+    /* @TODO when having an error queue this needs to push to the queue */
+    void wolfSSL_ERR_put_error(int lib, int fun, int err, const char* file,
+            int line)
+    {
+        WOLFSSL_ENTER("wolfSSL_ERR_put_error");
+
+        #ifndef DEBUG_WOLFSSL
+        (void)fun;
+        (void)err;
+        (void)file;
+        (void)line;
+        WOLFSSL_MSG("Not compiled in debug mode");
+        #else
+        WOLFSSL_ERROR_LINE(err, wolfSSL_ERR_sys_func(fun), (unsigned int)line,
+            file, NULL);
+        #endif
+        (void)lib;
+    }
+
+
+    /* Similar to wolfSSL_ERR_get_error_line but takes in a flags argument for
+     * more flexability.
+     *
+     * file  output pointer to file where error happened
+     * line  output to line number of error
+     * data  output data. Is a string if ERR_TXT_STRING flag is used
+     * flags bit flag to adjust data output
+     *
+     * Returns the error value or 0 if no errors are in the queue
+     */
     unsigned long wolfSSL_ERR_get_error_line_data(const char** file, int* line,
                                                   const char** data, int *flags)
     {
-        /* Not implemented */
-        (void)file;
-        (void)line;
-        (void)data;
-        (void)flags;
-        return 0;
-    }
-
-    WOLFSSL_API pem_password_cb* wolfSSL_CTX_get_default_passwd_cb(
-                                                               WOLFSSL_CTX *ctx)
-    {
-        if (ctx == NULL || ctx->passwd_cb == NULL) {
-            return NULL;
-        }
-
-        return ctx->passwd_cb;
-    }
-
-
-    WOLFSSL_API void *wolfSSL_CTX_get_default_passwd_cb_userdata(
-                                                               WOLFSSL_CTX *ctx)
-    {
-        if (ctx == NULL) {
-            return NULL;
-        }
-
-        return ctx->userdata;
+        int ret;
+
+        WOLFSSL_STUB("wolfSSL_ERR_get_error_line_data");
+
+        if (flags != NULL) {
+            if ((*flags & ERR_TXT_STRING) == ERR_TXT_STRING) {
+                ret = wc_PullErrorNode(file, data, line);
+                if (ret < 0) {
+                    if (ret == BAD_STATE_E) return 0; /* no errors in queue */
+                    WOLFSSL_MSG("Error with pulling error node!");
+                    WOLFSSL_LEAVE("wolfSSL_ERR_get_error_line_data", ret);
+                    ret = 0 - ret; /* return absolute value of error */
+
+                    /* panic and try to clear out nodes */
+                    wc_ClearErrorNodes();
+                }
+
+                return (unsigned long)ret;
+            }
+        }
+
+        ret = wc_PullErrorNode(file, NULL, line);
+        if (ret < 0) {
+            if (ret == BAD_STATE_E) return 0; /* no errors in queue */
+            WOLFSSL_MSG("Error with pulling error node!");
+            WOLFSSL_LEAVE("wolfSSL_ERR_get_error_line_data", ret);
+            ret = 0 - ret; /* return absolute value of error */
+
+            /* panic and try to clear out nodes */
+            wc_ClearErrorNodes();
+        }
+
+        return (unsigned long)ret;
     }
 
@@ -13789,6 +14852,6 @@
 
 
-#if defined(KEEP_PEER_CERT)
-    #ifdef SESSION_CERTS
+#if (defined(KEEP_PEER_CERT) && defined(SESSION_CERTS)) || \
+                                   (defined(OPENSSL_ALL) && defined(HAVE_PKCS7))
     /* Decode the X509 DER encoded certificate into a WOLFSSL_X509 object.
      *
@@ -13828,10 +14891,14 @@
         return ret;
     }
-    #endif
-
-
+#endif /* (KEEP_PEER_CERT && SESSION_CERTS) || (OPENSSL_ALL && HAVE_PKCS7) */
+
+
+#ifdef KEEP_PEER_CERT
     WOLFSSL_X509* wolfSSL_get_peer_certificate(WOLFSSL* ssl)
     {
         WOLFSSL_ENTER("SSL_get_peer_certificate");
+        if (ssl == NULL)
+            return NULL;
+
         if (ssl->peerCert.issuer.sz)
             return &ssl->peerCert;
@@ -13851,5 +14918,6 @@
 
 #ifndef NO_CERTS
-#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS) || defined(OPENSSL_EXTRA)
+#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS) || \
+    defined(OPENSSL_EXTRA)  || defined(OPENSSL_EXTRA_X509_SMALL)
 
 /* user externally called free X509, if dynamic go ahead with free, otherwise
@@ -13868,9 +14936,6 @@
 }
 
-#endif /* KEEP_PEER_CERT || SESSION_CERTS || OPENSSSL_EXTRA */
-
-#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS)
-
-    void wolfSSL_FreeX509(WOLFSSL_X509* x509)
+/* Frees an external WOLFSSL_X509 structure */
+void wolfSSL_X509_free(WOLFSSL_X509* x509)
     {
         WOLFSSL_ENTER("wolfSSL_FreeX509");
@@ -13878,4 +14943,100 @@
     }
 
+
+/* copy name into in buffer, at most sz bytes, if buffer is null will
+   malloc buffer, call responsible for freeing                     */
+char* wolfSSL_X509_NAME_oneline(WOLFSSL_X509_NAME* name, char* in, int sz)
+    {
+    int copySz;
+
+    if (name == NULL) {
+        WOLFSSL_MSG("WOLFSSL_X509_NAME pointer was NULL");
+            return NULL;
+    }
+
+    copySz = min(sz, name->sz);
+
+    WOLFSSL_ENTER("wolfSSL_X509_NAME_oneline");
+    if (!name->sz) return in;
+
+    if (!in) {
+    #ifdef WOLFSSL_STATIC_MEMORY
+        WOLFSSL_MSG("Using static memory -- please pass in a buffer");
+        return NULL;
+    #else
+        in = (char*)XMALLOC(name->sz, NULL, DYNAMIC_TYPE_OPENSSL);
+        if (!in ) return in;
+        copySz = name->sz;
+    #endif
+    }
+
+    if (copySz <= 0)
+        return in;
+
+    XMEMCPY(in, name->name, copySz - 1);
+    in[copySz - 1] = 0;
+
+    return in;
+    }
+
+
+/* Wraps wolfSSL_X509_d2i
+ *
+ * returns a WOLFSSL_X509 structure pointer on success and NULL on fail
+ */
+WOLFSSL_X509* wolfSSL_d2i_X509(WOLFSSL_X509** x509, const unsigned char** in,
+        int len)
+    {
+    return wolfSSL_X509_d2i(x509, *in, len);
+    }
+
+
+WOLFSSL_X509* wolfSSL_X509_d2i(WOLFSSL_X509** x509, const byte* in, int len)
+    {
+    WOLFSSL_X509 *newX509 = NULL;
+
+    WOLFSSL_ENTER("wolfSSL_X509_d2i");
+
+    if (in != NULL && len != 0) {
+    #ifdef WOLFSSL_SMALL_STACK
+        DecodedCert* cert = NULL;
+    #else
+        DecodedCert  cert[1];
+    #endif
+
+    #ifdef WOLFSSL_SMALL_STACK
+        cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
+                                     DYNAMIC_TYPE_DCERT);
+        if (cert == NULL)
+            return NULL;
+    #endif
+
+        InitDecodedCert(cert, (byte*)in, len, NULL);
+        if (ParseCertRelative(cert, CERT_TYPE, 0, NULL) == 0) {
+            newX509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL,
+                                             DYNAMIC_TYPE_X509);
+            if (newX509 != NULL) {
+                InitX509(newX509, 1, NULL);
+                if (CopyDecodedToX509(newX509, cert) != 0) {
+                    wolfSSL_X509_free(newX509);
+                    newX509 = NULL;
+                }
+    }
+            }
+        FreeDecodedCert(cert);
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(cert, NULL, DYNAMIC_TYPE_DCERT);
+    #endif
+        }
+
+    if (x509 != NULL)
+        *x509 = newX509;
+
+    return newX509;
+    }
+#endif /* KEEP_PEER_CERT || SESSION_CERTS || OPENSSL_EXTRA ||
+          OPENSSL_EXTRA_X509_SMALL */
+
+#if defined(OPENSSL_ALL) || defined(KEEP_PEER_CERT) || defined(SESSION_CERTS)
     /* return the next, if any, altname from the peer cert */
     char* wolfSSL_X509_get_next_altname(WOLFSSL_X509* cert)
@@ -13899,22 +15060,4 @@
 
 
-    WOLFSSL_X509_NAME* wolfSSL_X509_get_issuer_name(WOLFSSL_X509* cert)
-    {
-        WOLFSSL_ENTER("X509_get_issuer_name");
-        if (cert && cert->issuer.sz != 0)
-            return &cert->issuer;
-        return NULL;
-    }
-
-
-    WOLFSSL_X509_NAME* wolfSSL_X509_get_subject_name(WOLFSSL_X509* cert)
-    {
-        WOLFSSL_ENTER("wolfSSL_X509_get_subject_name");
-        if (cert && cert->subject.sz != 0)
-            return &cert->subject;
-        return NULL;
-    }
-
-
     int wolfSSL_X509_get_isCA(WOLFSSL_X509* x509)
     {
@@ -13930,367 +15073,4 @@
         return isCA;
     }
-
-
-#ifdef OPENSSL_EXTRA
-    int wolfSSL_X509_ext_isSet_by_NID(WOLFSSL_X509* x509, int nid)
-    {
-        int isSet = 0;
-
-        WOLFSSL_ENTER("wolfSSL_X509_ext_isSet_by_NID");
-
-        if (x509 != NULL) {
-            switch (nid) {
-                case BASIC_CA_OID: isSet = x509->basicConstSet; break;
-                case ALT_NAMES_OID: isSet = x509->subjAltNameSet; break;
-                case AUTH_KEY_OID: isSet = x509->authKeyIdSet; break;
-                case SUBJ_KEY_OID: isSet = x509->subjKeyIdSet; break;
-                case KEY_USAGE_OID: isSet = x509->keyUsageSet; break;
-                #ifdef WOLFSSL_SEP
-                    case CERT_POLICY_OID: isSet = x509->certPolicySet; break;
-                #endif /* WOLFSSL_SEP */
-            }
-        }
-
-        WOLFSSL_LEAVE("wolfSSL_X509_ext_isSet_by_NID", isSet);
-
-        return isSet;
-    }
-
-
-    int wolfSSL_X509_ext_get_critical_by_NID(WOLFSSL_X509* x509, int nid)
-    {
-        int crit = 0;
-
-        WOLFSSL_ENTER("wolfSSL_X509_ext_get_critical_by_NID");
-
-        if (x509 != NULL) {
-            switch (nid) {
-                case BASIC_CA_OID: crit = x509->basicConstCrit; break;
-                case ALT_NAMES_OID: crit = x509->subjAltNameCrit; break;
-                case AUTH_KEY_OID: crit = x509->authKeyIdCrit; break;
-                case SUBJ_KEY_OID: crit = x509->subjKeyIdCrit; break;
-                case KEY_USAGE_OID: crit = x509->keyUsageCrit; break;
-                #ifdef WOLFSSL_SEP
-                    case CERT_POLICY_OID: crit = x509->certPolicyCrit; break;
-                #endif /* WOLFSSL_SEP */
-            }
-        }
-
-        WOLFSSL_LEAVE("wolfSSL_X509_ext_get_critical_by_NID", crit);
-
-        return crit;
-    }
-
-
-    int wolfSSL_X509_get_isSet_pathLength(WOLFSSL_X509* x509)
-    {
-        int isSet = 0;
-
-        WOLFSSL_ENTER("wolfSSL_X509_get_isSet_pathLength");
-
-        if (x509 != NULL)
-            isSet = x509->basicConstPlSet;
-
-        WOLFSSL_LEAVE("wolfSSL_X509_get_isSet_pathLength", isSet);
-
-        return isSet;
-    }
-
-
-    word32 wolfSSL_X509_get_pathLength(WOLFSSL_X509* x509)
-    {
-        word32 pathLength = 0;
-
-        WOLFSSL_ENTER("wolfSSL_X509_get_pathLength");
-
-        if (x509 != NULL)
-            pathLength = x509->pathLength;
-
-        WOLFSSL_LEAVE("wolfSSL_X509_get_pathLength", pathLength);
-
-        return pathLength;
-    }
-
-
-    unsigned int wolfSSL_X509_get_keyUsage(WOLFSSL_X509* x509)
-    {
-        word16 usage = 0;
-
-        WOLFSSL_ENTER("wolfSSL_X509_get_keyUsage");
-
-        if (x509 != NULL)
-            usage = x509->keyUsage;
-
-        WOLFSSL_LEAVE("wolfSSL_X509_get_keyUsage", usage);
-
-        return usage;
-    }
-
-
-    byte* wolfSSL_X509_get_authorityKeyID(WOLFSSL_X509* x509,
-                                          byte* dst, int* dstLen)
-    {
-        byte *id = NULL;
-        int copySz = 0;
-
-        WOLFSSL_ENTER("wolfSSL_X509_get_authorityKeyID");
-
-        if (x509 != NULL) {
-            if (x509->authKeyIdSet) {
-                copySz = min(dstLen != NULL ? *dstLen : 0,
-                             (int)x509->authKeyIdSz);
-                id = x509->authKeyId;
-            }
-
-            if (dst != NULL && dstLen != NULL && id != NULL && copySz > 0) {
-                XMEMCPY(dst, id, copySz);
-                id = dst;
-                *dstLen = copySz;
-            }
-        }
-
-        WOLFSSL_LEAVE("wolfSSL_X509_get_authorityKeyID", copySz);
-
-        return id;
-    }
-
-
-    byte* wolfSSL_X509_get_subjectKeyID(WOLFSSL_X509* x509,
-                                        byte* dst, int* dstLen)
-    {
-        byte *id = NULL;
-        int copySz = 0;
-
-        WOLFSSL_ENTER("wolfSSL_X509_get_subjectKeyID");
-
-        if (x509 != NULL) {
-            if (x509->subjKeyIdSet) {
-                copySz = min(dstLen != NULL ? *dstLen : 0,
-                                                        (int)x509->subjKeyIdSz);
-                id = x509->subjKeyId;
-            }
-
-            if (dst != NULL && dstLen != NULL && id != NULL && copySz > 0) {
-                XMEMCPY(dst, id, copySz);
-                id = dst;
-                *dstLen = copySz;
-            }
-        }
-
-        WOLFSSL_LEAVE("wolfSSL_X509_get_subjectKeyID", copySz);
-
-        return id;
-    }
-
-
-    int wolfSSL_X509_NAME_entry_count(WOLFSSL_X509_NAME* name)
-    {
-        int count = 0;
-
-        WOLFSSL_ENTER("wolfSSL_X509_NAME_entry_count");
-
-        if (name != NULL)
-            count = name->fullName.entryCount;
-
-        WOLFSSL_LEAVE("wolfSSL_X509_NAME_entry_count", count);
-        return count;
-    }
-
-
-    /* Used to get a string from the WOLFSSL_X509_NAME structure that
-     * corresponds with the NID value passed in.
-     *
-     * name structure to get string from
-     * nid  NID value to search for
-     * buf  [out] buffer to hold results. If NULL then the buffer size minus the
-     *      null char is returned.
-     * len  size of "buf" passed in
-     *
-     * returns the length of string found, not including the NULL terminator.
-     *         It's possible the function could return a negative value in the
-     *         case that len is less than or equal to 0. A negative value is
-     *         considered an error case.
-     */
-    int wolfSSL_X509_NAME_get_text_by_NID(WOLFSSL_X509_NAME* name,
-                                          int nid, char* buf, int len)
-    {
-        char *text = NULL;
-        int textSz = 0;
-
-        WOLFSSL_ENTER("wolfSSL_X509_NAME_get_text_by_NID");
-
-        switch (nid) {
-            case ASN_COMMON_NAME:
-                text = name->fullName.fullName + name->fullName.cnIdx;
-                textSz = name->fullName.cnLen;
-                break;
-            case ASN_SUR_NAME:
-                text = name->fullName.fullName + name->fullName.snIdx;
-                textSz = name->fullName.snLen;
-                break;
-            case ASN_SERIAL_NUMBER:
-                text = name->fullName.fullName + name->fullName.serialIdx;
-                textSz = name->fullName.serialLen;
-                break;
-            case ASN_COUNTRY_NAME:
-                text = name->fullName.fullName + name->fullName.cIdx;
-                textSz = name->fullName.cLen;
-                break;
-            case ASN_LOCALITY_NAME:
-                text = name->fullName.fullName + name->fullName.lIdx;
-                textSz = name->fullName.lLen;
-                break;
-            case ASN_STATE_NAME:
-                text = name->fullName.fullName + name->fullName.stIdx;
-                textSz = name->fullName.stLen;
-                break;
-            case ASN_ORG_NAME:
-                text = name->fullName.fullName + name->fullName.oIdx;
-                textSz = name->fullName.oLen;
-                break;
-            case ASN_ORGUNIT_NAME:
-                text = name->fullName.fullName + name->fullName.ouIdx;
-                textSz = name->fullName.ouLen;
-                break;
-            default:
-                WOLFSSL_MSG("Unknown NID value");
-                return -1;
-        }
-
-        /* if buf is NULL return size of buffer needed (minus null char) */
-        if (buf == NULL) {
-            return textSz;
-        }
-
-        if (buf != NULL && text != NULL) {
-            textSz = min(textSz + 1, len); /* + 1 to account for null char */
-            if (textSz > 0) {
-                XMEMCPY(buf, text, textSz - 1);
-                buf[textSz - 1] = '\0';
-            }
-        }
-
-        WOLFSSL_LEAVE("wolfSSL_X509_NAME_get_text_by_NID", textSz);
-        return (textSz - 1); /* do not include null character in size */
-    }
-
-    int wolfSSL_X509_NAME_get_index_by_NID(WOLFSSL_X509_NAME* name,
-                                          int nid, int pos)
-    {
-        int ret    = -1;
-
-        WOLFSSL_ENTER("wolfSSL_X509_NAME_get_index_by_NID");
-
-        if (name == NULL) {
-            return BAD_FUNC_ARG;
-        }
-
-        /* these index values are already stored in DecodedName
-           use those when available */
-        if (name->fullName.fullName && name->fullName.fullNameLen > 0) {
-            switch (nid) {
-                case ASN_COMMON_NAME:
-                    if (pos != name->fullName.cnIdx)
-                        ret = name->fullName.cnIdx;
-                    break;
-                default:
-                    WOLFSSL_MSG("NID not yet implemented");
-                    break;
-            }
-        }
-
-        WOLFSSL_LEAVE("wolfSSL_X509_NAME_get_index_by_NID", ret);
-
-        (void)pos;
-        (void)nid;
-
-        return ret;
-    }
-
-
-    WOLFSSL_ASN1_STRING*  wolfSSL_X509_NAME_ENTRY_get_data(
-                                                    WOLFSSL_X509_NAME_ENTRY* in)
-    {
-        WOLFSSL_ENTER("wolfSSL_X509_NAME_ENTRY_get_data");
-        return in->value;
-    }
-
-
-    char* wolfSSL_ASN1_STRING_data(WOLFSSL_ASN1_STRING* asn)
-    {
-        WOLFSSL_ENTER("wolfSSL_ASN1_STRING_data");
-
-        if (asn) {
-            return asn->data;
-        }
-        else {
-            return NULL;
-        }
-    }
-
-
-    int wolfSSL_ASN1_STRING_length(WOLFSSL_ASN1_STRING* asn)
-    {
-        WOLFSSL_ENTER("wolfSSL_ASN1_STRING_length");
-
-        if (asn) {
-            return asn->length;
-        }
-        else {
-            return 0;
-        }
-    }
-#endif
-
-
-    /* copy name into in buffer, at most sz bytes, if buffer is null will
-       malloc buffer, call responsible for freeing                     */
-    char* wolfSSL_X509_NAME_oneline(WOLFSSL_X509_NAME* name, char* in, int sz)
-    {
-        int copySz;
-
-        if (name == NULL) {
-            WOLFSSL_MSG("WOLFSSL_X509_NAME pointer was NULL");
-            return NULL;
-        }
-
-        copySz = min(sz, name->sz);
-
-        WOLFSSL_ENTER("wolfSSL_X509_NAME_oneline");
-        if (!name->sz) return in;
-
-        if (!in) {
-        #ifdef WOLFSSL_STATIC_MEMORY
-            WOLFSSL_MSG("Using static memory -- please pass in a buffer");
-            return NULL;
-        #else
-            in = (char*)XMALLOC(name->sz, NULL, DYNAMIC_TYPE_OPENSSL);
-            if (!in ) return in;
-            copySz = name->sz;
-        #endif
-        }
-
-        if (copySz <= 0)
-            return in;
-
-        XMEMCPY(in, name->name, copySz - 1);
-        in[copySz - 1] = 0;
-
-        return in;
-    }
-
-
-    int wolfSSL_X509_get_signature_type(WOLFSSL_X509* x509)
-    {
-        int type = 0;
-
-        WOLFSSL_ENTER("wolfSSL_X509_get_signature_type");
-
-        if (x509 != NULL)
-            type = x509->sigOID;
-
-        return type;
-    }
-
 
     int wolfSSL_X509_get_signature(WOLFSSL_X509* x509,
@@ -14331,5 +15111,5 @@
         WOLFSSL_ENTER("wolfSSL_X509_get_der");
 
-        if (x509 == NULL || outSz == NULL)
+        if (x509 == NULL || x509->derCert == NULL || outSz == NULL)
             return NULL;
 
@@ -14358,5 +15138,5 @@
 
         return x509->notBefore;
-    }
+            }
 
 
@@ -14378,5 +15158,5 @@
    *inOutSz. Requires inOutSz be non-null */
 byte* wolfSSL_X509_get_device_type(WOLFSSL_X509* x509, byte* in, int *inOutSz)
-{
+    {
     int copySz;
 
@@ -14396,5 +15176,5 @@
         copySz = x509->deviceTypeSz;
     #endif
-    }
+        }
 
     XMEMCPY(in, x509->deviceType, copySz);
@@ -14402,9 +15182,9 @@
 
     return in;
-}
+    }
 
 
 byte* wolfSSL_X509_get_hw_type(WOLFSSL_X509* x509, byte* in, int* inOutSz)
-{
+    {
     int copySz;
 
@@ -14435,5 +15215,5 @@
 byte* wolfSSL_X509_get_hw_serial_number(WOLFSSL_X509* x509,byte* in,
                                         int* inOutSz)
-{
+    {
     int copySz;
 
@@ -14453,5 +15233,5 @@
         copySz = x509->hwSerialNumSz;
     #endif
-    }
+        }
 
     XMEMCPY(in, x509->hwSerialNum, copySz);
@@ -14459,5 +15239,5 @@
 
     return in;
-}
+    }
 
 #endif /* WOLFSSL_SEP */
@@ -14472,5 +15252,5 @@
     if (sk == NULL || x509 == NULL) {
         return WOLFSSL_FAILURE;
-    }
+        }
 
     /* no previous values in stack */
@@ -14479,5 +15259,5 @@
         sk->num += 1;
         return WOLFSSL_SUCCESS;
-    }
+        }
 
     /* stack already has value(s) create a new node and add more */
@@ -14498,5 +15278,5 @@
 
     return WOLFSSL_SUCCESS;
-}
+    }
 
 
@@ -14506,6 +15286,6 @@
 
     if (sk == NULL) {
-        return NULL;
-    }
+            return NULL;
+        }
 
     node = sk->next;
@@ -14516,8 +15296,8 @@
         sk->next = node->next;
         XFREE(node, NULL, DYNAMIC_TYPE_X509);
-    }
+        }
     else { /* last x509 in stack */
         sk->data.x509 = NULL;
-    }
+        }
 
     if (sk->num > 0) {
@@ -14526,10 +15306,59 @@
 
     return x509;
-}
-
-
-/* free structure for x509 stack */
-void wolfSSL_sk_X509_free(WOLF_STACK_OF(WOLFSSL_X509_NAME)* sk) {
+    }
+
+
+/* Getter function for WOLFSSL_X509_NAME pointer
+ *
+ * sk is the stack to retrieve pointer from
+ * i  is the index value in stack
+ *
+ * returns a pointer to a WOLFSSL_X509_NAME structure on success and NULL on
+ *         fail
+ */
+void* wolfSSL_sk_X509_NAME_value(const STACK_OF(WOLFSSL_X509_NAME)* sk, int i)
+    {
+    WOLFSSL_ENTER("wolfSSL_sk_X509_NAME_value");
+
+    for (; sk != NULL && i > 0; i--)
+        sk = sk->next;
+
+    if (i != 0 || sk == NULL)
+            return NULL;
+    return sk->data.name;
+        }
+
+
+/* Getter function for WOLFSSL_X509 pointer
+ *
+ * sk is the stack to retrieve pointer from
+ * i  is the index value in stack
+ *
+ * returns a pointer to a WOLFSSL_X509 structure on success and NULL on
+ *         fail
+ */
+void* wolfSSL_sk_X509_value(STACK_OF(WOLFSSL_X509)* sk, int i)
+{
+    WOLFSSL_ENTER("wolfSSL_sk_X509_value");
+
+    for (; sk != NULL && i > 0; i--)
+        sk = sk->next;
+
+    if (i != 0 || sk == NULL)
+            return NULL;
+    return sk->data.x509;
+        }
+
+
+/* Free's all nodes in X509 stack. This is different then wolfSSL_sk_X509_free
+ * in that it allows for choosing the function to use when freeing an X509s.
+ *
+ * sk  stack to free nodes in
+ * f   X509 free function
+ */
+void wolfSSL_sk_X509_pop_free(STACK_OF(WOLFSSL_X509)* sk, void f (WOLFSSL_X509*)){
     WOLFSSL_STACK* node;
+
+    WOLFSSL_ENTER("wolfSSL_sk_X509_pop_free");
 
     if (sk == NULL) {
@@ -14543,5 +15372,5 @@
         node = node->next;
 
-        wolfSSL_X509_free(tmp->data.x509);
+        f(tmp->data.x509);
         XFREE(tmp, NULL, DYNAMIC_TYPE_X509);
         sk->num -= 1;
@@ -14550,54 +15379,127 @@
     /* free head of stack */
     if (sk->num == 1) {
-	wolfSSL_X509_free(sk->data.x509);
+        f(sk->data.x509);
     }
     XFREE(sk, NULL, DYNAMIC_TYPE_X509);
-}
+    }
+
+
+/* free structure for x509 stack */
+void wolfSSL_sk_X509_free(WOLF_STACK_OF(WOLFSSL_X509_NAME)* sk) {
+    WOLFSSL_STACK* node;
+
+    if (sk == NULL) {
+        return;
+    }
+
+    /* parse through stack freeing each node */
+    node = sk->next;
+    while (sk->num > 1) {
+        WOLFSSL_STACK* tmp = node;
+        node = node->next;
+
+        wolfSSL_X509_free(tmp->data.x509);
+        tmp->data.x509 = NULL;
+        XFREE(tmp, NULL, DYNAMIC_TYPE_X509);
+        sk->num -= 1;
+    }
+
+    /* free head of stack */
+    if (sk->num == 1) {
+        wolfSSL_X509_free(sk->data.x509);
+        sk->data.x509 = NULL;
+    }
+    XFREE(sk, NULL, DYNAMIC_TYPE_X509);
+}
+
 #endif /* NO_CERTS && OPENSSL_EXTRA */
 
-WOLFSSL_X509* wolfSSL_X509_d2i(WOLFSSL_X509** x509, const byte* in, int len)
-{
-    WOLFSSL_X509 *newX509 = NULL;
-
-    WOLFSSL_ENTER("wolfSSL_X509_d2i");
-
-    if (in != NULL && len != 0) {
-    #ifdef WOLFSSL_SMALL_STACK
-        DecodedCert* cert = NULL;
-    #else
-        DecodedCert  cert[1];
-    #endif
-
-    #ifdef WOLFSSL_SMALL_STACK
-        cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
-                                     DYNAMIC_TYPE_DCERT);
-        if (cert == NULL)
+#ifdef OPENSSL_EXTRA
+
+/* Returns the general name at index i from the stack
+ *
+ * sk stack to get general name from
+ * i  index to get
+ *
+ * return a pointer to the internal node of the stack
+ */
+WOLFSSL_ASN1_OBJECT* wolfSSL_sk_GENERAL_NAME_value(WOLFSSL_STACK* sk, int i)
+    {
+    WOLFSSL_STACK* cur;
+    int j;
+
+    WOLFSSL_ENTER("wolfSSL_sk_GENERAL_NAME_value");
+
+    if (i < 0 || sk == NULL) {
+        return NULL;
+    }
+
+    cur = sk;
+    for (j = 0; j < i && cur != NULL; j++) {
+        cur = cur->next;
+    }
+
+    if (cur == NULL) {
             return NULL;
-    #endif
-
-        InitDecodedCert(cert, (byte*)in, len, NULL);
-        if (ParseCertRelative(cert, CERT_TYPE, 0, NULL) == 0) {
-            newX509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL,
-                                             DYNAMIC_TYPE_X509);
-            if (newX509 != NULL) {
-                InitX509(newX509, 1, NULL);
-                if (CopyDecodedToX509(newX509, cert) != 0) {
-                    XFREE(newX509, NULL, DYNAMIC_TYPE_X509);
-                    newX509 = NULL;
-                }
-            }
-        }
-        FreeDecodedCert(cert);
-    #ifdef WOLFSSL_SMALL_STACK
-        XFREE(cert, NULL, DYNAMIC_TYPE_DCERT);
-    #endif
-    }
-
-    if (x509 != NULL)
-        *x509 = newX509;
-
-    return newX509;
-}
-
+    }
+
+    return cur->data.obj;
+    }
+
+
+/* Gets the number of nodes in the stack
+ *
+ * sk  stack to get the number of nodes from
+ *
+ * returns the number of nodes, -1 if no nodes
+ */
+int wolfSSL_sk_GENERAL_NAME_num(WOLFSSL_STACK* sk)
+    {
+    WOLFSSL_ENTER("wolfSSL_sk_GENERAL_NAME_num");
+
+    if (sk == NULL) {
+        return -1;
+    }
+
+    return (int)sk->num;
+}
+
+/* Frees all nodes in a GENERAL NAME stack
+ *
+ * sk stack of nodes to free
+ * f  free function to use, not called with wolfSSL
+ */
+void wolfSSL_sk_GENERAL_NAME_pop_free(WOLFSSL_STACK* sk,
+        void f (WOLFSSL_ASN1_OBJECT*))
+    {
+    WOLFSSL_STACK* node;
+
+    WOLFSSL_ENTER("wolfSSL_sk_GENERAL_NAME_pop_free");
+
+    (void)f;
+    if (sk == NULL) {
+        return;
+    }
+
+    /* parse through stack freeing each node */
+    node = sk->next;
+    while (sk->num > 1) {
+        WOLFSSL_STACK* tmp = node;
+        node = node->next;
+
+        wolfSSL_ASN1_OBJECT_free(tmp->data.obj);
+        XFREE(tmp, NULL, DYNAMIC_TYPE_ASN1);
+        sk->num -= 1;
+    }
+
+    /* free head of stack */
+    if (sk->num == 1) {
+        wolfSSL_ASN1_OBJECT_free(sk->data.obj);
+    }
+    XFREE(sk, NULL, DYNAMIC_TYPE_ASN1);
+
+
+    }
+#endif /* OPENSSL_EXTRA */
 
 #ifndef NO_FILESYSTEM
@@ -14615,5 +15517,6 @@
         long sz = 0;
 
-        XFSEEK(file, 0, XSEEK_END);
+        if(XFSEEK(file, 0, XSEEK_END) != 0)
+            return NULL;
         sz = XFTELL(file);
         XREWIND(file);
@@ -14621,6 +15524,6 @@
         if (sz < 0) {
             WOLFSSL_MSG("Bad tell on FILE");
-            return NULL;
-        }
+        return NULL;
+    }
 
         fileBuffer = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE);
@@ -14666,5 +15569,8 @@
         return NULL;
 
-    XFSEEK(file, 0, XSEEK_END);
+    if(XFSEEK(file, 0, XSEEK_END) != 0){
+        XFCLOSE(file);
+        return NULL;
+    }
     sz = XFTELL(file);
     XREWIND(file);
@@ -14681,5 +15587,5 @@
         XFCLOSE(file);
         return NULL;
-    }
+}
 
     ret = (int)XFREAD(fileBuffer, 1, sz, file);
@@ -14699,5 +15605,5 @@
 
     return x509;
-}
+    }
 
 #endif /* NO_FILESYSTEM */
@@ -14714,29 +15620,10 @@
 
     if (format == WOLFSSL_FILETYPE_PEM) {
-        int ecc = 0;
-    #ifdef WOLFSSL_SMALL_STACK
-        EncryptedInfo* info = NULL;
+    #ifdef WOLFSSL_PEM_TO_DER
+        if (PemToDer(buf, sz, CERT_TYPE, &der, NULL, NULL, NULL) != 0) {
+            FreeDer(&der);
+        }
     #else
-        EncryptedInfo  info[1];
-    #endif
-
-    #ifdef WOLFSSL_SMALL_STACK
-        info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), NULL,
-                                       DYNAMIC_TYPE_ENCRYPTEDINFO);
-        if (info == NULL) {
-            return NULL;
-        }
-    #endif
-
-        info->set = 0;
-        info->ctx = NULL;
-        info->consumed = 0;
-
-        if (PemToDer(buf, sz, CERT_TYPE, &der, NULL, info, &ecc) != 0) {
-            FreeDer(&der);
-        }
-
-    #ifdef WOLFSSL_SMALL_STACK
-        XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO);
+        ret = NOT_COMPILED_IN;
     #endif
     }
@@ -14770,5 +15657,5 @@
                     InitX509(x509, 1, NULL);
                     if (CopyDecodedToX509(x509, cert) != 0) {
-                        XFREE(x509, NULL, DYNAMIC_TYPE_X509);
+                        wolfSSL_X509_free(x509);
                         x509 = NULL;
                     }
@@ -14805,7 +15692,9 @@
                 return NULL;
             }
+            #ifndef WOLFSSL_X509_STORE_CERTS
             ssl->ourCert = wolfSSL_X509_d2i(NULL,
                                               ssl->buffers.certificate->buffer,
                                               ssl->buffers.certificate->length);
+            #endif
         }
         return ssl->ourCert;
@@ -14818,7 +15707,9 @@
                     return NULL;
                 }
+                #ifndef WOLFSSL_X509_STORE_CERTS
                 ssl->ctx->ourCert = wolfSSL_X509_d2i(NULL,
                                                ssl->ctx->certificate->buffer,
                                                ssl->ctx->certificate->length);
+                #endif
                 ssl->ctx->ownOurCert = 1;
             }
@@ -14833,5 +15724,46 @@
 
 
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+#ifndef NO_ASN
+void wolfSSL_ASN1_OBJECT_free(WOLFSSL_ASN1_OBJECT* obj)
+{
+    if (obj == NULL) {
+        return;
+    }
+
+    if ((obj->obj != NULL) && ((obj->dynamic & WOLFSSL_ASN1_DYNAMIC_DATA) != 0)) {
+        WOLFSSL_MSG("Freeing ASN1 data");
+        XFREE((void*)obj->obj, obj->heap, DYNAMIC_TYPE_ASN1);
+        obj->obj = NULL;
+
+    }
+    if ((obj->dynamic & WOLFSSL_ASN1_DYNAMIC) != 0) {
+        WOLFSSL_MSG("Freeing ASN1 OBJECT");
+        XFREE(obj, NULL, DYNAMIC_TYPE_ASN1);
+    }
+}
+#endif /* NO_ASN */
+#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
+
 #ifdef OPENSSL_EXTRA
+#ifndef NO_ASN
+WOLFSSL_ASN1_OBJECT* wolfSSL_ASN1_OBJECT_new(void)
+{
+    WOLFSSL_ASN1_OBJECT* obj;
+
+    obj = (WOLFSSL_ASN1_OBJECT*)XMALLOC(sizeof(WOLFSSL_ASN1_OBJECT), NULL,
+                                        DYNAMIC_TYPE_ASN1);
+    if (obj == NULL) {
+        return NULL;
+    }
+
+    XMEMSET(obj, 0, sizeof(WOLFSSL_ASN1_OBJECT));
+    obj->d.ia5 = &(obj->d.ia5_internal);
+    obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
+    return obj;
+}
+#endif /* NO_ASN */
+
+
 /* return 1 on success 0 on fail */
 int wolfSSL_sk_ASN1_OBJECT_push(WOLF_STACK_OF(WOLFSSL_ASN1_OBJEXT)* sk,
@@ -14902,36 +15834,4 @@
 
 #ifndef NO_ASN
-WOLFSSL_ASN1_OBJECT* wolfSSL_ASN1_OBJECT_new(void)
-{
-    WOLFSSL_ASN1_OBJECT* obj;
-
-    obj = (WOLFSSL_ASN1_OBJECT*)XMALLOC(sizeof(WOLFSSL_ASN1_OBJECT), NULL,
-                                        DYNAMIC_TYPE_ASN1);
-    if (obj == NULL) {
-        return NULL;
-    }
-
-    XMEMSET(obj, 0, sizeof(WOLFSSL_ASN1_OBJECT));
-    return obj;
-}
-
-
-void wolfSSL_ASN1_OBJECT_free(WOLFSSL_ASN1_OBJECT* obj)
-{
-    if (obj == NULL) {
-        return;
-    }
-
-    if (obj->dynamic == 1) {
-        if (obj->obj != NULL) {
-            WOLFSSL_MSG("Freeing ASN1 OBJECT data");
-            XFREE(obj->obj, obj->heap, DYNAMIC_TYPE_ASN1);
-        }
-    }
-
-    XFREE(obj, NULL, DYNAMIC_TYPE_ASN1);
-}
-
-
 /* free structure for x509 stack */
 void wolfSSL_sk_ASN1_OBJECT_free(WOLF_STACK_OF(WOLFSSL_ASN1_OBJECT)* sk)
@@ -14956,5 +15856,5 @@
     /* free head of stack */
     if (sk->num == 1) {
-	    wolfSSL_ASN1_OBJECT_free(sk->data.obj);
+        wolfSSL_ASN1_OBJECT_free(sk->data.obj);
     }
     XFREE(sk, NULL, DYNAMIC_TYPE_ASN1);
@@ -14976,53 +15876,57 @@
 #endif /* NO_ASN */
 
-
-int wolfSSL_set_session_id_context(WOLFSSL* ssl, const unsigned char* id,
-                               unsigned int len)
-{
-    (void)ssl;
-    (void)id;
-    (void)len;
-    return 0;
-}
-
-
 void wolfSSL_set_connect_state(WOLFSSL* ssl)
 {
-    word16 haveRSA = 1;
-    word16 havePSK = 0;
-
-    if (ssl->options.side == WOLFSSL_SERVER_END) {
-        ssl->options.side = WOLFSSL_CLIENT_END;
-
-        #ifdef NO_RSA
-            haveRSA = 0;
-        #endif
-        #ifndef NO_PSK
-            havePSK = ssl->options.havePSK;
-        #endif
-        InitSuites(ssl->suites, ssl->version, ssl->buffers.keySz, haveRSA,
-                   havePSK, ssl->options.haveDH, ssl->options.haveNTRU,
-                   ssl->options.haveECDSAsig, ssl->options.haveECC,
-                   ssl->options.haveStaticECC, ssl->options.side);
-    }
-}
-#endif
+    if (ssl == NULL) {
+        WOLFSSL_MSG("WOLFSSL struct pointer passed in was null");
+        return;
+                }
+
+    #ifndef NO_DH
+    /* client creates its own DH parameters on handshake */
+    if (ssl->buffers.serverDH_P.buffer && ssl->buffers.weOwnDH) {
+        XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap,
+            DYNAMIC_TYPE_PUBLIC_KEY);
+            }
+    ssl->buffers.serverDH_P.buffer = NULL;
+    if (ssl->buffers.serverDH_G.buffer && ssl->buffers.weOwnDH) {
+        XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap,
+            DYNAMIC_TYPE_PUBLIC_KEY);
+        }
+    ssl->buffers.serverDH_G.buffer = NULL;
+    #endif
+
+    if (InitSSL_Side(ssl, WOLFSSL_CLIENT_END) != WOLFSSL_SUCCESS) {
+        WOLFSSL_MSG("Error initializing client side");
+}
+}
+#endif /* OPENSSL_EXTRA */
+
 
 int wolfSSL_get_shutdown(const WOLFSSL* ssl)
 {
+    int isShutdown = 0;
+
     WOLFSSL_ENTER("wolfSSL_get_shutdown");
-    /* in OpenSSL, WOLFSSL_SENT_SHUTDOWN = 1, when closeNotifySent   *
-     * WOLFSSL_RECEIVED_SHUTDOWN = 2, from close notify or fatal err */
-    return ((ssl->options.closeNotify||ssl->options.connReset) << 1)
-            | (ssl->options.sentNotify);
-}
+
+    if (ssl) {
+        /* in OpenSSL, WOLFSSL_SENT_SHUTDOWN = 1, when closeNotifySent   *
+         * WOLFSSL_RECEIVED_SHUTDOWN = 2, from close notify or fatal err */
+        isShutdown = ((ssl->options.closeNotify||ssl->options.connReset) << 1)
+                    | (ssl->options.sentNotify);
+        }
+    return isShutdown;
+    }
 
 
 int wolfSSL_session_reused(WOLFSSL* ssl)
 {
-    return ssl->options.resuming;
-}
-
-#ifdef OPENSSL_EXTRA
+    int resuming = 0;
+    if (ssl)
+        resuming = ssl->options.resuming;
+    return resuming;
+}
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_EXT_CACHE)
 void wolfSSL_SESSION_free(WOLFSSL_SESSION* session)
 {
@@ -15050,18 +15954,41 @@
     if (ssl->version.major == SSLv3_MAJOR) {
         switch (ssl->version.minor) {
+        #ifndef NO_OLD_TLS
+            #ifdef WOLFSSL_ALLOW_SSLV3
             case SSLv3_MINOR :
                 return "SSLv3";
+            #endif
+            #ifdef WOLFSSL_ALLOW_TLSV10
             case TLSv1_MINOR :
                 return "TLSv1";
+            #endif
             case TLSv1_1_MINOR :
                 return "TLSv1.1";
+        #endif
             case TLSv1_2_MINOR :
                 return "TLSv1.2";
+        #ifdef WOLFSSL_TLS13
             case TLSv1_3_MINOR :
+            #ifdef WOLFSSL_TLS13_DRAFT
+                #ifdef WOLFSSL_TLS13_DRAFT_18
+                    return "TLSv1.3 (Draft 18)";
+                #elif defined(WOLFSSL_TLS13_DRAFT_22)
+                    return "TLSv1.3 (Draft 22)";
+                #elif defined(WOLFSSL_TLS13_DRAFT_23)
+                    return "TLSv1.3 (Draft 23)";
+                #elif defined(WOLFSSL_TLS13_DRAFT_26)
+                    return "TLSv1.3 (Draft 26)";
+                #else
+                    return "TLSv1.3 (Draft 28)";
+                #endif
+            #else
                 return "TLSv1.3";
+            #endif
+        #endif
             default:
                 return "unknown";
         }
     }
+#ifdef WOLFSSL_DTLS
     else if (ssl->version.major == DTLS_MAJOR) {
         switch (ssl->version.minor) {
@@ -15074,6 +16001,7 @@
         }
     }
+#endif /* WOLFSSL_DTLS */
     return "unknown";
-}
+    }
 
 
@@ -15082,5 +16010,5 @@
 {
     return LIBWOLFSSL_VERSION_STRING;
-}
+    }
 
 
@@ -15118,6 +16046,9 @@
     }
 
-    return wolfSSL_get_cipher_name_from_suite(cipher->ssl->options.cipherSuite,
-        cipher->ssl->options.cipherSuite0);
+    #ifndef WOLFSSL_CIPHER_INTERNALNAME
+        return wolfSSL_get_cipher_name_iana(cipher->ssl);
+    #else
+        return wolfSSL_get_cipher_name_internal(cipher->ssl);
+    #endif
 }
 
@@ -15125,14 +16056,17 @@
 {
     if (session == NULL) {
-        return NULL;
-    }
+            return NULL;
+        }
 
 #ifdef SESSION_CERTS
-    return wolfSSL_get_cipher_name_from_suite(session->cipherSuite,
-        session->cipherSuite0);
+    #ifndef WOLFSSL_CIPHER_INTERNALNAME
+         return GetCipherNameIana(session->cipherSuite0, session->cipherSuite);
+    #else
+       if return GetCipherNameInternal(ession->cipherSuite0, session->cipherSuite);
+    #endif
 #else
     return NULL;
 #endif
-}
+        }
 
 const char* wolfSSL_get_cipher(WOLFSSL* ssl)
@@ -15140,5 +16074,5 @@
     WOLFSSL_ENTER("wolfSSL_get_cipher");
     return wolfSSL_CIPHER_get_name(wolfSSL_get_current_cipher(ssl));
-}
+    }
 
 /* gets cipher name in the format DHE-RSA-... rather then TLS_DHE... */
@@ -15147,5 +16081,12 @@
     /* get access to cipher_name_idx in internal.c */
     return wolfSSL_get_cipher_name_internal(ssl);
-}
+        }
+
+const char* wolfSSL_get_cipher_name_from_suite(const byte cipherSuite0,
+    const byte cipherSuite)
+{
+    return GetCipherNameInternal(cipherSuite0, cipherSuite);
+    }
+
 
 #ifdef HAVE_ECC
@@ -15168,7 +16109,1288 @@
     return wc_ecc_get_name(wc_ecc_get_oid(ssl->ecdhCurveOID, NULL, NULL));
 }
-#endif
-
-#ifdef OPENSSL_EXTRA
+    #endif
+
+
+#if defined(OPENSSL_EXTRA_X509_SMALL) || defined(KEEP_PEER_CERT) || \
+    defined(SESSION_CERTS)
+/* Smaller subset of X509 compatibility functions. Avoid increasing the size of
+ * this subset and its memory usage */
+
+#if !defined(NO_CERTS)
+/* returns a pointer to a new WOLFSSL_X509 structure on success and NULL on
+ * fail
+ */
+WOLFSSL_X509* wolfSSL_X509_new(void)
+        {
+    WOLFSSL_X509* x509;
+
+                x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL,
+                                                             DYNAMIC_TYPE_X509);
+                if (x509 != NULL) {
+                    InitX509(x509, 1, NULL);
+                }
+
+    return x509;
+            }
+
+WOLFSSL_X509_NAME* wolfSSL_X509_get_subject_name(WOLFSSL_X509* cert)
+{
+    WOLFSSL_ENTER("wolfSSL_X509_get_subject_name");
+    if (cert && cert->subject.sz != 0)
+        return &cert->subject;
+    return NULL;
+    }
+
+
+
+WOLFSSL_X509_NAME* wolfSSL_X509_get_issuer_name(WOLFSSL_X509* cert)
+{
+    WOLFSSL_ENTER("X509_get_issuer_name");
+    if (cert && cert->issuer.sz != 0)
+        return &cert->issuer;
+        return NULL;
+    }
+
+
+int wolfSSL_X509_get_signature_type(WOLFSSL_X509* x509)
+{
+    int type = 0;
+
+    WOLFSSL_ENTER("wolfSSL_X509_get_signature_type");
+
+    if (x509 != NULL)
+        type = x509->sigOID;
+
+    return type;
+}
+
+#if defined(OPENSSL_EXTRA_X509_SMALL)
+#ifdef HAVE_ECC
+    static int SetECKeyExternal(WOLFSSL_EC_KEY* eckey);
+#endif
+
+/* Used to get a string from the WOLFSSL_X509_NAME structure that
+ * corresponds with the NID value passed in.
+ *
+ * name structure to get string from
+ * nid  NID value to search for
+ * buf  [out] buffer to hold results. If NULL then the buffer size minus the
+ *      null char is returned.
+ * len  size of "buf" passed in
+ *
+ * returns the length of string found, not including the NULL terminator.
+ *         It's possible the function could return a negative value in the
+ *         case that len is less than or equal to 0. A negative value is
+ *         considered an error case.
+ */
+int wolfSSL_X509_NAME_get_text_by_NID(WOLFSSL_X509_NAME* name,
+                                      int nid, char* buf, int len)
+{
+    char *text = NULL;
+    int textSz = 0;
+
+    WOLFSSL_ENTER("wolfSSL_X509_NAME_get_text_by_NID");
+
+    switch (nid) {
+        case ASN_COMMON_NAME:
+            text = name->fullName.fullName + name->fullName.cnIdx;
+            textSz = name->fullName.cnLen;
+            break;
+        case ASN_SUR_NAME:
+            text = name->fullName.fullName + name->fullName.snIdx;
+            textSz = name->fullName.snLen;
+            break;
+        case ASN_SERIAL_NUMBER:
+            text = name->fullName.fullName + name->fullName.serialIdx;
+            textSz = name->fullName.serialLen;
+            break;
+        case ASN_COUNTRY_NAME:
+            text = name->fullName.fullName + name->fullName.cIdx;
+            textSz = name->fullName.cLen;
+            break;
+        case ASN_LOCALITY_NAME:
+            text = name->fullName.fullName + name->fullName.lIdx;
+            textSz = name->fullName.lLen;
+            break;
+        case ASN_STATE_NAME:
+            text = name->fullName.fullName + name->fullName.stIdx;
+            textSz = name->fullName.stLen;
+            break;
+        case ASN_ORG_NAME:
+            text = name->fullName.fullName + name->fullName.oIdx;
+            textSz = name->fullName.oLen;
+            break;
+        case ASN_ORGUNIT_NAME:
+            text = name->fullName.fullName + name->fullName.ouIdx;
+            textSz = name->fullName.ouLen;
+            break;
+        case ASN_DOMAIN_COMPONENT:
+            text = name->fullName.fullName + name->fullName.dcIdx[0];
+            textSz = name->fullName.dcLen[0];
+            break;
+    #ifdef WOLFSSL_CERT_EXT
+        case ASN_BUS_CAT:
+            text = name->fullName.fullName + name->fullName.bcIdx;
+            textSz = name->fullName.bcLen;
+            break;
+    #endif
+        default:
+            WOLFSSL_MSG("Entry type not found");
+            return SSL_FATAL_ERROR;
+    }
+
+    /* if buf is NULL return size of buffer needed (minus null char) */
+    if (buf == NULL) {
+        return textSz;
+    }
+
+    if (buf != NULL && text != NULL) {
+        textSz = min(textSz + 1, len); /* + 1 to account for null char */
+        if (textSz > 0) {
+            XMEMCPY(buf, text, textSz - 1);
+            buf[textSz - 1] = '\0';
+        }
+    }
+
+    WOLFSSL_LEAVE("wolfSSL_X509_NAME_get_text_by_NID", textSz);
+    return (textSz - 1); /* do not include null character in size */
+}
+
+
+/* Creates a new WOLFSSL_EVP_PKEY structure that has the public key from x509
+ *
+ * returns a pointer to the created WOLFSSL_EVP_PKEY on success and NULL on fail
+ */
+WOLFSSL_EVP_PKEY* wolfSSL_X509_get_pubkey(WOLFSSL_X509* x509)
+{
+    WOLFSSL_EVP_PKEY* key = NULL;
+    WOLFSSL_ENTER("X509_get_pubkey");
+    if (x509 != NULL) {
+        key = (WOLFSSL_EVP_PKEY*)XMALLOC(
+                    sizeof(WOLFSSL_EVP_PKEY), x509->heap,
+                                                       DYNAMIC_TYPE_PUBLIC_KEY);
+        if (key != NULL) {
+            XMEMSET(key, 0, sizeof(WOLFSSL_EVP_PKEY));
+            if (x509->pubKeyOID == RSAk) {
+                key->type = EVP_PKEY_RSA;
+            }
+            else {
+                key->type = EVP_PKEY_EC;
+            }
+            key->save_type = 0;
+            key->pkey.ptr = (char*)XMALLOC(
+                        x509->pubKey.length, x509->heap,
+                                                       DYNAMIC_TYPE_PUBLIC_KEY);
+            if (key->pkey.ptr == NULL) {
+                XFREE(key, x509->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+        return NULL;
+    }
+            XMEMCPY(key->pkey.ptr, x509->pubKey.buffer, x509->pubKey.length);
+            key->pkey_sz = x509->pubKey.length;
+
+            #ifdef HAVE_ECC
+                key->pkey_curve = (int)x509->pkCurveOID;
+            #endif /* HAVE_ECC */
+
+            /* decode RSA key */
+            #ifndef NO_RSA
+            if (key->type == EVP_PKEY_RSA) {
+                key->ownRsa = 1;
+                key->rsa = wolfSSL_RSA_new();
+                if (key->rsa == NULL) {
+                    XFREE(key, x509->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+                    return NULL;
+    }
+
+                if (wolfSSL_RSA_LoadDer_ex(key->rsa,
+                            (const unsigned char*)key->pkey.ptr, key->pkey_sz,
+                            WOLFSSL_RSA_LOAD_PUBLIC) != SSL_SUCCESS) {
+                    wolfSSL_RSA_free(key->rsa);
+                    key->rsa = NULL;
+                    XFREE(key, x509->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+                    return NULL;
+    }
+}
+            #endif /* NO_RSA */
+
+            /* decode ECC key */
+            #ifdef HAVE_ECC
+            if (key->type == EVP_PKEY_EC) {
+                word32 idx = 0;
+
+                key->ownEcc = 1;
+                key->ecc = wolfSSL_EC_KEY_new();
+                if (key->ecc == NULL || key->ecc->internal == NULL) {
+                    XFREE(key, x509->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+        return NULL;
+    }
+
+                /* not using wolfSSL_EC_KEY_LoadDer because public key in x509
+                 * is in the format of x963 (no sequence at start of buffer) */
+                if (wc_EccPublicKeyDecode((const unsigned char*)key->pkey.ptr,
+                        &idx, (ecc_key*)key->ecc->internal, key->pkey_sz) < 0) {
+                    WOLFSSL_MSG("wc_EccPublicKeyDecode failed");
+                    XFREE(key, x509->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+                    wolfSSL_EC_KEY_free(key->ecc);
+                    key->ecc = NULL;
+                    return NULL;
+}
+
+                if (SetECKeyExternal(key->ecc) != SSL_SUCCESS) {
+                    WOLFSSL_MSG("SetECKeyExternal failed");
+                    XFREE(key, x509->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+                    wolfSSL_EC_KEY_free(key->ecc);
+                    key->ecc = NULL;
+                    return NULL;
+    }
+
+                key->ecc->inSet = 1;
+            }
+            #endif /* HAVE_ECC */
+        }
+    }
+    return key;
+}
+#endif /* OPENSSL_EXTRA_X509_SMALL */
+#endif /* !NO_CERTS */
+
+/* End of smaller subset of X509 compatibility functions. Avoid increasing the
+ * size of this subset and its memory usage */
+#endif /* OPENSSL_EXTRA_X509_SMALL */
+
+#if defined(OPENSSL_EXTRA)
+#if !defined(NO_CERTS)
+    int wolfSSL_X509_ext_isSet_by_NID(WOLFSSL_X509* x509, int nid)
+{
+        int isSet = 0;
+
+        WOLFSSL_ENTER("wolfSSL_X509_ext_isSet_by_NID");
+
+        if (x509 != NULL) {
+            switch (nid) {
+                case BASIC_CA_OID: isSet = x509->basicConstSet; break;
+                case ALT_NAMES_OID: isSet = x509->subjAltNameSet; break;
+                case AUTH_KEY_OID: isSet = x509->authKeyIdSet; break;
+                case SUBJ_KEY_OID: isSet = x509->subjKeyIdSet; break;
+                case KEY_USAGE_OID: isSet = x509->keyUsageSet; break;
+                #ifdef WOLFSSL_SEP
+                    case CERT_POLICY_OID: isSet = x509->certPolicySet; break;
+                #endif /* WOLFSSL_SEP */
+    }
+    }
+
+        WOLFSSL_LEAVE("wolfSSL_X509_ext_isSet_by_NID", isSet);
+
+        return isSet;
+}
+
+
+    int wolfSSL_X509_ext_get_critical_by_NID(WOLFSSL_X509* x509, int nid)
+{
+        int crit = 0;
+
+        WOLFSSL_ENTER("wolfSSL_X509_ext_get_critical_by_NID");
+
+        if (x509 != NULL) {
+            switch (nid) {
+                case BASIC_CA_OID: crit = x509->basicConstCrit; break;
+                case ALT_NAMES_OID: crit = x509->subjAltNameCrit; break;
+                case AUTH_KEY_OID: crit = x509->authKeyIdCrit; break;
+                case SUBJ_KEY_OID: crit = x509->subjKeyIdCrit; break;
+                case KEY_USAGE_OID: crit = x509->keyUsageCrit; break;
+                #ifdef WOLFSSL_SEP
+                    case CERT_POLICY_OID: crit = x509->certPolicyCrit; break;
+                #endif /* WOLFSSL_SEP */
+            }
+}
+
+        WOLFSSL_LEAVE("wolfSSL_X509_ext_get_critical_by_NID", crit);
+
+        return crit;
+}
+
+
+    int wolfSSL_X509_get_isSet_pathLength(WOLFSSL_X509* x509)
+{
+        int isSet = 0;
+
+        WOLFSSL_ENTER("wolfSSL_X509_get_isSet_pathLength");
+
+        if (x509 != NULL)
+            isSet = x509->basicConstPlSet;
+
+        WOLFSSL_LEAVE("wolfSSL_X509_get_isSet_pathLength", isSet);
+
+        return isSet;
+}
+
+
+    word32 wolfSSL_X509_get_pathLength(WOLFSSL_X509* x509)
+{
+        word32 pathLength = 0;
+
+        WOLFSSL_ENTER("wolfSSL_X509_get_pathLength");
+
+        if (x509 != NULL)
+            pathLength = x509->pathLength;
+
+        WOLFSSL_LEAVE("wolfSSL_X509_get_pathLength", pathLength);
+
+        return pathLength;
+}
+
+
+    unsigned int wolfSSL_X509_get_keyUsage(WOLFSSL_X509* x509)
+{
+        word16 usage = 0;
+
+        WOLFSSL_ENTER("wolfSSL_X509_get_keyUsage");
+
+        if (x509 != NULL)
+            usage = x509->keyUsage;
+
+        WOLFSSL_LEAVE("wolfSSL_X509_get_keyUsage", usage);
+
+        return usage;
+}
+
+
+    byte* wolfSSL_X509_get_authorityKeyID(WOLFSSL_X509* x509,
+                                          byte* dst, int* dstLen)
+{
+        byte *id = NULL;
+        int copySz = 0;
+
+        WOLFSSL_ENTER("wolfSSL_X509_get_authorityKeyID");
+
+        if (x509 != NULL) {
+            if (x509->authKeyIdSet) {
+                copySz = min(dstLen != NULL ? *dstLen : 0,
+                             (int)x509->authKeyIdSz);
+                id = x509->authKeyId;
+        }
+
+            if (dst != NULL && dstLen != NULL && id != NULL && copySz > 0) {
+                XMEMCPY(dst, id, copySz);
+                id = dst;
+                *dstLen = copySz;
+    }
+}
+
+        WOLFSSL_LEAVE("wolfSSL_X509_get_authorityKeyID", copySz);
+
+        return id;
+}
+
+
+    byte* wolfSSL_X509_get_subjectKeyID(WOLFSSL_X509* x509,
+                                        byte* dst, int* dstLen)
+{
+        byte *id = NULL;
+        int copySz = 0;
+
+        WOLFSSL_ENTER("wolfSSL_X509_get_subjectKeyID");
+
+        if (x509 != NULL) {
+            if (x509->subjKeyIdSet) {
+                copySz = min(dstLen != NULL ? *dstLen : 0,
+                                                        (int)x509->subjKeyIdSz);
+                id = x509->subjKeyId;
+}
+
+            if (dst != NULL && dstLen != NULL && id != NULL && copySz > 0) {
+                XMEMCPY(dst, id, copySz);
+                id = dst;
+                *dstLen = copySz;
+            }
+}
+
+        WOLFSSL_LEAVE("wolfSSL_X509_get_subjectKeyID", copySz);
+
+        return id;
+    }
+
+
+    int wolfSSL_X509_NAME_entry_count(WOLFSSL_X509_NAME* name)
+{
+        int count = 0;
+
+        WOLFSSL_ENTER("wolfSSL_X509_NAME_entry_count");
+
+        if (name != NULL)
+            count = name->fullName.entryCount;
+
+        WOLFSSL_LEAVE("wolfSSL_X509_NAME_entry_count", count);
+        return count;
+}
+
+
+
+    int wolfSSL_X509_NAME_get_index_by_NID(WOLFSSL_X509_NAME* name,
+                                          int nid, int pos)
+{
+        int ret    = -1;
+
+        WOLFSSL_ENTER("wolfSSL_X509_NAME_get_index_by_NID");
+
+        if (name == NULL) {
+            return BAD_FUNC_ARG;
+}
+
+        /* these index values are already stored in DecodedName
+           use those when available */
+        if (name->fullName.fullName && name->fullName.fullNameLen > 0) {
+            name->fullName.dcMode = 0;
+            switch (nid) {
+                case ASN_COMMON_NAME:
+                    if (pos != name->fullName.cnIdx)
+                        ret = name->fullName.cnIdx;
+                    break;
+                case ASN_DOMAIN_COMPONENT:
+                    name->fullName.dcMode = 1;
+                    if (pos < name->fullName.dcNum - 1){
+                        ret = pos + 1;
+                    } else {
+                        ret = -1;
+                    }
+                    break;
+                default:
+                    WOLFSSL_MSG("NID not yet implemented");
+                    break;
+            }
+        }
+
+        WOLFSSL_LEAVE("wolfSSL_X509_NAME_get_index_by_NID", ret);
+
+        (void)pos;
+        (void)nid;
+
+        return ret;
+    }
+
+
+    WOLFSSL_ASN1_STRING*  wolfSSL_X509_NAME_ENTRY_get_data(
+                                                    WOLFSSL_X509_NAME_ENTRY* in)
+    {
+        WOLFSSL_ENTER("wolfSSL_X509_NAME_ENTRY_get_data");
+        if (in == NULL)
+            return NULL;
+
+        return in->value;
+    }
+
+
+    /* Creates a new WOLFSSL_ASN1_STRING structure.
+ *
+     * returns a pointer to the new structure created on success or NULL if fail
+ */
+    WOLFSSL_ASN1_STRING* wolfSSL_ASN1_STRING_new(void)
+{
+        WOLFSSL_ASN1_STRING* asn1;
+
+        WOLFSSL_ENTER("wolfSSL_ASN1_STRING_new");
+
+        asn1 = (WOLFSSL_ASN1_STRING*)XMALLOC(sizeof(WOLFSSL_ASN1_STRING), NULL,
+                DYNAMIC_TYPE_OPENSSL);
+        if (asn1 != NULL) {
+            XMEMSET(asn1, 0, sizeof(WOLFSSL_ASN1_STRING));
+        }
+
+        return asn1; /* no check for null because error case is returning null*/
+    }
+
+
+    /* used to free a WOLFSSL_ASN1_STRING structure */
+    void wolfSSL_ASN1_STRING_free(WOLFSSL_ASN1_STRING* asn1)
+    {
+        WOLFSSL_ENTER("wolfSSL_ASN1_STRING_free");
+
+        if (asn1 != NULL) {
+            if (asn1->length > 0 && asn1->data != NULL) {
+                XFREE(asn1->data, NULL, DYNAMIC_TYPE_OPENSSL);
+            }
+            XFREE(asn1, NULL, DYNAMIC_TYPE_OPENSSL);
+        }
+    }
+
+
+    /* Creates a new WOLFSSL_ASN1_STRING structure given the input type.
+     *
+     * type is the type of set when WOLFSSL_ASN1_STRING is created
+     *
+     * returns a pointer to the new structure created on success or NULL if fail
+     */
+    WOLFSSL_ASN1_STRING* wolfSSL_ASN1_STRING_type_new(int type)
+    {
+        WOLFSSL_ASN1_STRING* asn1;
+
+        WOLFSSL_ENTER("wolfSSL_ASN1_STRING_type_new");
+
+        asn1 = wolfSSL_ASN1_STRING_new();
+        if (asn1 == NULL) {
+        return NULL;
+}
+        asn1->type = type;
+
+        return asn1;
+    }
+
+
+    /* if dataSz is negative then use XSTRLEN to find length of data
+     * return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on failure */
+    int wolfSSL_ASN1_STRING_set(WOLFSSL_ASN1_STRING* asn1, const void* data,
+            int dataSz)
+{
+        int sz;
+
+        WOLFSSL_ENTER("wolfSSL_ASN1_STRING_set");
+
+        if (data == NULL || asn1 == NULL) {
+            return WOLFSSL_FAILURE;
+        }
+
+        if (dataSz < 0) {
+            sz = (int)XSTRLEN((const char*)data) + 1; /* +1 for null */
+        }
+        else {
+            sz = dataSz;
+        }
+
+        if (sz < 0) {
+            return WOLFSSL_FAILURE;
+        }
+
+        /* free any existing data before copying */
+        if (asn1->data != NULL) {
+            XFREE(asn1->data, NULL, DYNAMIC_TYPE_OPENSSL);
+        }
+
+        /* create new data buffer and copy over */
+        asn1->data = (char*)XMALLOC(sz, NULL, DYNAMIC_TYPE_OPENSSL);
+        if (asn1->data == NULL) {
+            return WOLFSSL_FAILURE;
+        }
+        XMEMCPY(asn1->data, data, sz);
+        asn1->length = sz;
+
+        return WOLFSSL_SUCCESS;
+    }
+
+
+    unsigned char* wolfSSL_ASN1_STRING_data(WOLFSSL_ASN1_STRING* asn)
+    {
+        WOLFSSL_ENTER("wolfSSL_ASN1_STRING_data");
+
+        if (asn) {
+            return (unsigned char*)asn->data;
+        }
+        else {
+        return NULL;
+        }
+    }
+
+
+    int wolfSSL_ASN1_STRING_length(WOLFSSL_ASN1_STRING* asn)
+    {
+        WOLFSSL_ENTER("wolfSSL_ASN1_STRING_length");
+
+        if (asn) {
+            return asn->length;
+        }
+        else {
+            return 0;
+        }
+    }
+
+
+#ifdef XSNPRINTF /* a snprintf function needs to be available */
+    /* Writes the human readable form of x509 to bio.
+     *
+     * bio  WOLFSSL_BIO to write to.
+     * x509 Certificate to write.
+     *
+     * returns WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on failure
+     */
+    int wolfSSL_X509_print(WOLFSSL_BIO* bio, WOLFSSL_X509* x509)
+    {
+        WOLFSSL_ENTER("wolfSSL_X509_print");
+
+        if (bio == NULL || x509 == NULL) {
+            return WOLFSSL_FAILURE;
+        }
+
+        if (wolfSSL_BIO_write(bio, "Certificate:\n",
+                            sizeof("Certificate:\n")) <= 0) {
+                return WOLFSSL_FAILURE;
+        }
+
+        if (wolfSSL_BIO_write(bio, "    Data:\n",
+                            sizeof("    Data:\n")) <= 0) {
+                return WOLFSSL_FAILURE;
+        }
+
+        /* print version of cert */
+        {
+            int version;
+            char tmp[17];
+
+            if ((version = wolfSSL_X509_version(x509)) <= 0) {
+                WOLFSSL_MSG("Error getting X509 version");
+                return WOLFSSL_FAILURE;
+            }
+            if (wolfSSL_BIO_write(bio, "        Version: ",
+                                sizeof("        Version: ")) <= 0) {
+                return WOLFSSL_FAILURE;
+            }
+            XSNPRINTF(tmp, sizeof(tmp), "%d\n", version);
+            if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) {
+                return WOLFSSL_FAILURE;
+            }
+        }
+
+        /* print serial number out */
+        {
+            unsigned char serial[32];
+            int  sz = sizeof(serial);
+
+            XMEMSET(serial, 0, sz);
+            if (wolfSSL_X509_get_serial_number(x509, serial, &sz)
+                    != WOLFSSL_SUCCESS) {
+                WOLFSSL_MSG("Error getting x509 serial number");
+                return WOLFSSL_FAILURE;
+            }
+            if (wolfSSL_BIO_write(bio, "        Serial Number: ",
+                                sizeof("        Serial Number: ")) <= 0) {
+                return WOLFSSL_FAILURE;
+            }
+
+            /* if serial can fit into byte than print on the same line */
+            if (sz <= (int)sizeof(byte)) {
+                char tmp[17];
+                XSNPRINTF(tmp, sizeof(tmp), "%d (0x%x)\n", serial[0],serial[0]);
+                if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) {
+                    return WOLFSSL_FAILURE;
+                }
+            }
+            else {
+                int i;
+                char tmp[100];
+                int  tmpSz = 100;
+                char val[5];
+                int  valSz = 5;
+
+                /* serial is larger than int size so print off hex values */
+                if (wolfSSL_BIO_write(bio, "\n            ",
+                                    sizeof("\n            ")) <= 0) {
+                    return WOLFSSL_FAILURE;
+                }
+                tmp[0] = '\0';
+                for (i = 0; i < sz - 1 && (3 * i) < tmpSz - valSz; i++) {
+                    XSNPRINTF(val, sizeof(val) - 1, "%02x:", serial[i]);
+                    val[3] = '\0'; /* make sure is null terminated */
+                    XSTRNCAT(tmp, val, valSz);
+                }
+                XSNPRINTF(val, sizeof(val) - 1, "%02x\n", serial[i]);
+                val[3] = '\0'; /* make sure is null terminated */
+                XSTRNCAT(tmp, val, valSz);
+                if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) {
+                    return WOLFSSL_FAILURE;
+                }
+            }
+        }
+
+        /* print signature algo */
+        {
+            int   oid;
+            char* sig;
+
+            if ((oid = wolfSSL_X509_get_signature_type(x509)) <= 0) {
+                WOLFSSL_MSG("Error getting x509 signature type");
+                return WOLFSSL_FAILURE;
+            }
+            if (wolfSSL_BIO_write(bio, "    Signature Algorithm: ",
+                                sizeof("    Signature Algorithm: ")) <= 0) {
+                return WOLFSSL_FAILURE;
+            }
+            sig = GetSigName(oid);
+            if (wolfSSL_BIO_write(bio, sig, (int)XSTRLEN(sig)) <= 0) {
+                return WOLFSSL_FAILURE;
+            }
+            if (wolfSSL_BIO_write(bio, "\n", sizeof("\n")) <= 0) {
+                return WOLFSSL_FAILURE;
+            }
+        }
+
+        /* print issuer */
+        {
+            char* issuer;
+        #ifdef WOLFSSL_SMALL_STACK
+            char* buff  = NULL;
+            int   issSz = 0;
+        #else
+            char buff[256];
+            int  issSz = 256;
+    #endif
+
+            issuer  = wolfSSL_X509_NAME_oneline(
+                             wolfSSL_X509_get_issuer_name(x509), buff, issSz);
+
+            if (wolfSSL_BIO_write(bio, "        Issuer: ",
+                                sizeof("        Issuer: ")) <= 0) {
+                #ifdef WOLFSSL_SMALL_STACK
+                XFREE(issuer, NULL, DYNAMIC_TYPE_OPENSSL);
+#endif
+                return WOLFSSL_FAILURE;
+            }
+            if (issuer != NULL) {
+                if (wolfSSL_BIO_write(bio, issuer, (int)XSTRLEN(issuer)) <= 0) {
+                    #ifdef WOLFSSL_SMALL_STACK
+                    XFREE(issuer, NULL, DYNAMIC_TYPE_OPENSSL);
+#endif
+                    return WOLFSSL_FAILURE;
+                }
+            }
+            #ifdef WOLFSSL_SMALL_STACK
+            XFREE(issuer, NULL, DYNAMIC_TYPE_OPENSSL);
+#endif
+            if (wolfSSL_BIO_write(bio, "\n", sizeof("\n")) <= 0) {
+                return WOLFSSL_FAILURE;
+            }
+    }
+
+        /* print validity */
+        {
+            char tmp[80];
+
+            if (wolfSSL_BIO_write(bio, "        Validity\n",
+                                sizeof("        Validity\n")) <= 0) {
+                return WOLFSSL_FAILURE;
+            }
+            if (wolfSSL_BIO_write(bio, "            Not Before: ",
+                                sizeof("            Not Before: ")) <= 0) {
+                return WOLFSSL_FAILURE;
+            }
+            if (GetTimeString(x509->notBefore + 2, ASN_UTC_TIME,
+                tmp, sizeof(tmp)) != WOLFSSL_SUCCESS) {
+                if (GetTimeString(x509->notBefore + 2, ASN_GENERALIZED_TIME,
+                tmp, sizeof(tmp)) != WOLFSSL_SUCCESS) {
+                    WOLFSSL_MSG("Error getting not before date");
+                    return WOLFSSL_FAILURE;
+                }
+            }
+            tmp[sizeof(tmp) - 1] = '\0'; /* make sure null terminated */
+            if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) {
+                return WOLFSSL_FAILURE;
+            }
+            if (wolfSSL_BIO_write(bio, "\n            Not After : ",
+                                sizeof("\n            Not After : ")) <= 0) {
+                return WOLFSSL_FAILURE;
+            }
+            if (GetTimeString(x509->notAfter + 2,ASN_UTC_TIME,
+                tmp, sizeof(tmp)) != WOLFSSL_SUCCESS) {
+                if (GetTimeString(x509->notAfter + 2,ASN_GENERALIZED_TIME,
+                    tmp, sizeof(tmp)) != WOLFSSL_SUCCESS) {
+                    WOLFSSL_MSG("Error getting not before date");
+                    return WOLFSSL_FAILURE;
+                }
+            }
+            tmp[sizeof(tmp) - 1] = '\0'; /* make sure null terminated */
+            if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) {
+                return WOLFSSL_FAILURE;
+            }
+        }
+
+        /* print subject */
+        {
+            char* subject;
+        #ifdef WOLFSSL_SMALL_STACK
+            char* buff  = NULL;
+            int   subSz = 0;
+        #else
+            char buff[256];
+            int  subSz = 256;
+        #endif
+
+            subject  = wolfSSL_X509_NAME_oneline(
+                             wolfSSL_X509_get_subject_name(x509), buff, subSz);
+
+            if (wolfSSL_BIO_write(bio, "\n        Subject: ",
+                                sizeof("\n        Subject: ")) <= 0) {
+                #ifdef WOLFSSL_SMALL_STACK
+                XFREE(subject, NULL, DYNAMIC_TYPE_OPENSSL);
+                #endif
+                return WOLFSSL_FAILURE;
+            }
+            if (subject != NULL) {
+                if (wolfSSL_BIO_write(bio, subject, (int)XSTRLEN(subject)) <= 0) {
+                    #ifdef WOLFSSL_SMALL_STACK
+                    XFREE(subject, NULL, DYNAMIC_TYPE_OPENSSL);
+                    #endif
+                    return WOLFSSL_FAILURE;
+                }
+            }
+            #ifdef WOLFSSL_SMALL_STACK
+            XFREE(subject, NULL, DYNAMIC_TYPE_OPENSSL);
+            #endif
+        }
+
+        /* get and print public key */
+        if (wolfSSL_BIO_write(bio, "\n        Subject Public Key Info:\n",
+                            sizeof("\n        Subject Public Key Info:\n")) <= 0) {
+            return WOLFSSL_FAILURE;
+        }
+        {
+            char tmp[100];
+
+            switch (x509->pubKeyOID) {
+                #ifndef NO_RSA
+                case RSAk:
+                    if (wolfSSL_BIO_write(bio,
+                                "            Public Key Algorithm: RSA\n",
+                         sizeof("            Public Key Algorithm: RSA\n")) <= 0) {
+                        return WOLFSSL_FAILURE;
+                    }
+                #ifdef HAVE_USER_RSA
+                    if (wolfSSL_BIO_write(bio,
+                        "                Build without user RSA to print key\n",
+                 sizeof("                Build without user RSA to print key\n"))
+                        <= 0) {
+                        return WOLFSSL_FAILURE;
+                    }
+                #else
+                    {
+                        RsaKey rsa;
+                        word32 idx = 0;
+                        int  sz;
+                        byte lbit = 0;
+                        int  rawLen;
+                        unsigned char* rawKey;
+
+                        if (wc_InitRsaKey(&rsa, NULL) != 0) {
+                            WOLFSSL_MSG("wc_InitRsaKey failure");
+                            return WOLFSSL_FAILURE;
+                        }
+                        if (wc_RsaPublicKeyDecode(x509->pubKey.buffer,
+                                &idx, &rsa, x509->pubKey.length) != 0) {
+                            WOLFSSL_MSG("Error decoding RSA key");
+                            wc_FreeRsaKey(&rsa);
+                            return WOLFSSL_FAILURE;
+                        }
+                        if ((sz = wc_RsaEncryptSize(&rsa)) < 0) {
+                            WOLFSSL_MSG("Error getting RSA key size");
+                            wc_FreeRsaKey(&rsa);
+                            return WOLFSSL_FAILURE;
+                        }
+                        XSNPRINTF(tmp, sizeof(tmp) - 1, "%s%s: (%d bit)\n%s\n",
+                                "                 ", "Public-Key", 8 * sz,
+                                "                 Modulus:");
+                        tmp[sizeof(tmp) - 1] = '\0';
+                        if (wolfSSL_BIO_write(bio, tmp,
+                                                      (int)XSTRLEN(tmp)) <= 0) {
+                            wc_FreeRsaKey(&rsa);
+                            return WOLFSSL_FAILURE;
+                        }
+
+                        /* print out modulus */
+                        XSNPRINTF(tmp, sizeof(tmp) - 1,"                     ");
+                        tmp[sizeof(tmp) - 1] = '\0';
+                        if (mp_leading_bit(&rsa.n)) {
+                            lbit = 1;
+                            XSTRNCAT(tmp, "00", 3);
+                        }
+
+                        rawLen = mp_unsigned_bin_size(&rsa.n);
+                        rawKey = (unsigned char*)XMALLOC(rawLen, NULL,
+                                DYNAMIC_TYPE_TMP_BUFFER);
+                        if (rawKey == NULL) {
+                            WOLFSSL_MSG("Memory error");
+                            wc_FreeRsaKey(&rsa);
+                            return WOLFSSL_FAILURE;
+                        }
+                        mp_to_unsigned_bin(&rsa.n, rawKey);
+                        for (idx = 0; idx < (word32)rawLen; idx++) {
+                            char val[5];
+                            int valSz = 5;
+
+                            if ((idx == 0) && !lbit) {
+                                XSNPRINTF(val, valSz - 1, "%02x", rawKey[idx]);
+                            }
+                            else if ((idx != 0) && (((idx + lbit) % 15) == 0)) {
+                                tmp[sizeof(tmp) - 1] = '\0';
+                                if (wolfSSL_BIO_write(bio, tmp,
+                                                      (int)XSTRLEN(tmp)) <= 0) {
+                                    XFREE(rawKey, NULL,
+                                        DYNAMIC_TYPE_TMP_BUFFER);
+                                    wc_FreeRsaKey(&rsa);
+                                    return WOLFSSL_FAILURE;
+                                }
+                                XSNPRINTF(tmp, sizeof(tmp) - 1,
+                                        ":\n                     ");
+                                XSNPRINTF(val, valSz - 1, "%02x", rawKey[idx]);
+                            }
+                            else {
+                                XSNPRINTF(val, valSz - 1, ":%02x", rawKey[idx]);
+                            }
+                            XSTRNCAT(tmp, val, valSz);
+                        }
+                        XFREE(rawKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+                        /* print out remaning modulus values */
+                        if ((idx > 0) && (((idx - 1 + lbit) % 15) != 0)) {
+                            tmp[sizeof(tmp) - 1] = '\0';
+                            if (wolfSSL_BIO_write(bio, tmp,
+                                                      (int)XSTRLEN(tmp)) <= 0) {
+                                return WOLFSSL_FAILURE;
+                            }
+                        }
+
+                        /* print out exponent values */
+                        rawLen = mp_unsigned_bin_size(&rsa.e);
+                        if (rawLen < 0) {
+                            WOLFSSL_MSG("Error getting exponent size");
+                            wc_FreeRsaKey(&rsa);
+                            return WOLFSSL_FAILURE;
+                        }
+
+                        if ((word32)rawLen < sizeof(word32)) {
+                            rawLen = sizeof(word32);
+                        }
+                        rawKey = (unsigned char*)XMALLOC(rawLen, NULL,
+                                DYNAMIC_TYPE_TMP_BUFFER);
+                        if (rawKey == NULL) {
+                            WOLFSSL_MSG("Memory error");
+                            wc_FreeRsaKey(&rsa);
+                            return WOLFSSL_FAILURE;
+                        }
+                        XMEMSET(rawKey, 0, rawLen);
+                        mp_to_unsigned_bin(&rsa.e, rawKey);
+                        if ((word32)rawLen <= sizeof(word32)) {
+                            idx = *(word32*)rawKey;
+                        }
+                        XSNPRINTF(tmp, sizeof(tmp) - 1,
+                            "\n                 Exponent: %d\n", idx);
+                        if (wolfSSL_BIO_write(bio, tmp,
+                                                      (int)XSTRLEN(tmp)) <= 0) {
+                            XFREE(rawKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                            wc_FreeRsaKey(&rsa);
+                            return WOLFSSL_FAILURE;
+                        }
+                        XFREE(rawKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                        wc_FreeRsaKey(&rsa);
+                    }
+                #endif /* HAVE_USER_RSA */
+                    break;
+                #endif /* NO_RSA */
+
+#ifdef HAVE_ECC
+                case ECDSAk:
+                    {
+                        word32 i;
+                        ecc_key ecc;
+
+                        if (wolfSSL_BIO_write(bio,
+                                "            Public Key Algorithm: EC\n",
+                         sizeof("            Public Key Algorithm: EC\n")) <= 0) {
+                        return WOLFSSL_FAILURE;
+                        }
+                        if (wc_ecc_init_ex(&ecc, x509->heap, INVALID_DEVID)
+                                != 0) {
+                            return WOLFSSL_FAILURE;
+                        }
+
+                        i = 0;
+                        if (wc_EccPublicKeyDecode(x509->pubKey.buffer, &i,
+                                              &ecc, x509->pubKey.length) != 0) {
+                            wc_ecc_free(&ecc);
+                            return WOLFSSL_FAILURE;
+                        }
+                        XSNPRINTF(tmp, sizeof(tmp) - 1, "%s%s: (%d bit)\n%s\n",
+                                "                 ", "Public-Key",
+                                8 * wc_ecc_size(&ecc),
+                                "                 pub:");
+                        tmp[sizeof(tmp) - 1] = '\0';
+                        if (wolfSSL_BIO_write(bio, tmp,
+                                                      (int)XSTRLEN(tmp)) <= 0) {
+                            wc_ecc_free(&ecc);
+                            return WOLFSSL_FAILURE;
+                        }
+                        XSNPRINTF(tmp, sizeof(tmp) - 1,"                     ");
+                        {
+                            word32 derSz;
+                            byte*  der;
+
+                            derSz = wc_ecc_size(&ecc) * WOLFSSL_BIT_SIZE;
+                            der = (byte*)XMALLOC(derSz, x509->heap,
+                                    DYNAMIC_TYPE_TMP_BUFFER);
+                            if (der == NULL) {
+                                wc_ecc_free(&ecc);
+                                return WOLFSSL_FAILURE;
+                            }
+
+                            if (wc_ecc_export_x963(&ecc, der, &derSz) != 0) {
+                                wc_ecc_free(&ecc);
+                                XFREE(der, x509->heap, DYNAMIC_TYPE_TMP_BUFFER);
+                                return WOLFSSL_FAILURE;
+                            }
+                            for (i = 0; i < derSz; i++) {
+                                char val[5];
+                                int valSz = 5;
+
+                                if (i == 0) {
+                                    XSNPRINTF(val, valSz - 1, "%02x", der[i]);
+                                }
+                                else if ((i % 15) == 0) {
+                                    tmp[sizeof(tmp) - 1] = '\0';
+                                    if (wolfSSL_BIO_write(bio, tmp,
+                                                (int)XSTRLEN(tmp)) <= 0) {
+                                        wc_ecc_free(&ecc);
+                                        XFREE(der, x509->heap,
+                                                DYNAMIC_TYPE_TMP_BUFFER);
+                                        return WOLFSSL_FAILURE;
+                                    }
+                                    XSNPRINTF(tmp, sizeof(tmp) - 1,
+                                        ":\n                     ");
+                                    XSNPRINTF(val, valSz - 1, "%02x", der[i]);
+                                }
+                                else {
+                                    XSNPRINTF(val, valSz - 1, ":%02x", der[i]);
+                                }
+                                XSTRNCAT(tmp, val, valSz);
+                            }
+
+                            /* print out remaning modulus values */
+                            if ((i > 0) && (((i - 1) % 15) != 0)) {
+                                tmp[sizeof(tmp) - 1] = '\0';
+                                if (wolfSSL_BIO_write(bio, tmp,
+                                                      (int)XSTRLEN(tmp)) <= 0) {
+                                    wc_ecc_free(&ecc);
+                                    XFREE(der, x509->heap,
+                                                DYNAMIC_TYPE_TMP_BUFFER);
+                                    return WOLFSSL_FAILURE;
+                                }
+                            }
+
+                            XFREE(der, x509->heap, DYNAMIC_TYPE_TMP_BUFFER);
+                        }
+                        XSNPRINTF(tmp, sizeof(tmp) - 1, "\n%s%s: %s\n",
+                                "                ", "ASN1 OID",
+                                ecc.dp->name);
+                        if (wolfSSL_BIO_write(bio, tmp,
+                                                      (int)XSTRLEN(tmp)) <= 0) {
+                            wc_ecc_free(&ecc);
+                            return WOLFSSL_FAILURE;
+                        }
+                        wc_ecc_free(&ecc);
+                    }
+                    break;
+                #endif /* HAVE_ECC */
+                default:
+                    WOLFSSL_MSG("Unknown key type");
+                    return WOLFSSL_FAILURE;
+            }
+        }
+
+        /* print out extensions */
+        if (wolfSSL_BIO_write(bio, "        X509v3 extensions:\n",
+                            sizeof("        X509v3 extensions:\n")) <= 0) {
+            return WOLFSSL_FAILURE;
+        }
+
+        /* print subject key id */
+        if (x509->subjKeyIdSet && x509->subjKeyId != NULL &&
+                x509->subjKeyIdSz > 0) {
+            char tmp[100];
+            word32 i;
+            char val[5];
+            int valSz = 5;
+
+
+            if (wolfSSL_BIO_write(bio,
+                        "            X509v3 Subject Key Identifier:\n",
+                 sizeof("            X509v3 Subject Key Identifier:\n"))
+                 <= 0) {
+                return WOLFSSL_FAILURE;
+            }
+
+            XSNPRINTF(tmp, sizeof(tmp) - 1, "                 ");
+            for (i = 0; i < sizeof(tmp) && i < (x509->subjKeyIdSz - 1); i++) {
+                XSNPRINTF(val, valSz - 1, "%02X:", x509->subjKeyId[i]);
+                XSTRNCAT(tmp, val, valSz);
+            }
+            XSNPRINTF(val, valSz - 1, "%02X\n", x509->subjKeyId[i]);
+            XSTRNCAT(tmp, val, valSz);
+            if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) {
+                return WOLFSSL_FAILURE;
+            }
+        }
+
+        /* printf out authority key id */
+        if (x509->authKeyIdSet && x509->authKeyId != NULL &&
+                x509->authKeyIdSz > 0) {
+            char tmp[100];
+            word32 i;
+            char val[5];
+            int valSz = 5;
+
+            if (wolfSSL_BIO_write(bio,
+                        "            X509v3 Authority Key Identifier:\n",
+                 sizeof("            X509v3 Authority Key Identifier:\n"))
+                 <= 0) {
+                return WOLFSSL_FAILURE;
+            }
+
+            XSNPRINTF(tmp, sizeof(tmp) - 1, "                 keyid");
+            for (i = 0; i < x509->authKeyIdSz; i++) {
+                /* check if buffer is almost full */
+                if (XSTRLEN(tmp) >= sizeof(tmp) - valSz) {
+                    if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) {
+                        return WOLFSSL_FAILURE;
+                    }
+                    tmp[0] = '\0';
+                }
+                XSNPRINTF(val, valSz - 1, ":%02X", x509->authKeyId[i]);
+                XSTRNCAT(tmp, val, valSz);
+            }
+            if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) {
+                return WOLFSSL_FAILURE;
+            }
+
+            /* print issuer */
+            {
+                char* issuer;
+            #ifdef WOLFSSL_SMALL_STACK
+                char* buff  = NULL;
+                int   issSz = 0;
+            #else
+                char buff[256];
+                int  issSz = 256;
+            #endif
+
+                issuer  = wolfSSL_X509_NAME_oneline(
+                               wolfSSL_X509_get_issuer_name(x509), buff, issSz);
+
+                if (wolfSSL_BIO_write(bio, "\n                 DirName:",
+                                    sizeof("\n                 DirName:")) <= 0) {
+                    #ifdef WOLFSSL_SMALL_STACK
+                    XFREE(issuer, NULL, DYNAMIC_TYPE_OPENSSL);
+                    #endif
+                    return WOLFSSL_FAILURE;
+                }
+                if (issuer != NULL) {
+                    if (wolfSSL_BIO_write(bio, issuer, (int)XSTRLEN(issuer)) <= 0) {
+                        #ifdef WOLFSSL_SMALL_STACK
+                        XFREE(issuer, NULL, DYNAMIC_TYPE_OPENSSL);
+                        #endif
+                        return WOLFSSL_FAILURE;
+                    }
+                }
+                #ifdef WOLFSSL_SMALL_STACK
+                XFREE(issuer, NULL, DYNAMIC_TYPE_OPENSSL);
+                #endif
+                if (wolfSSL_BIO_write(bio, "\n", sizeof("\n")) <= 0) {
+                    return WOLFSSL_FAILURE;
+                }
+            }
+        }
+
+        /* print basic constraint */
+        if (x509->basicConstSet) {
+            char tmp[100];
+
+            if (wolfSSL_BIO_write(bio,
+                        "\n            X509v3 Basic Constraints:\n",
+                 sizeof("\n            X509v3 Basic Constraints:\n"))
+                 <= 0) {
+                return WOLFSSL_FAILURE;
+            }
+            XSNPRINTF(tmp, sizeof(tmp),
+                    "                    CA:%s\n",
+                    (x509->isCa)? "TRUE": "FALSE");
+            if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) {
+                return WOLFSSL_FAILURE;
+            }
+        }
+
+        /* print out signature */
+        {
+            unsigned char* sig;
+            int sigSz;
+            int i;
+            char tmp[100];
+            int sigOid = wolfSSL_X509_get_signature_type(x509);
+
+            if (wolfSSL_BIO_write(bio,
+                                "    Signature Algorithm: ",
+                         sizeof("    Signature Algorithm: ")) <= 0) {
+                return WOLFSSL_FAILURE;
+            }
+            XSNPRINTF(tmp, sizeof(tmp) - 1,"%s\n", GetSigName(sigOid));
+            tmp[sizeof(tmp) - 1] = '\0';
+            if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp)) <= 0) {
+                return WOLFSSL_FAILURE;
+            }
+
+            sigSz = (int)x509->sig.length;
+            if (sigSz <= 0) {
+                /* if sigSz invalid return here to avoid overhead of malloc */
+                return WOLFSSL_FAILURE;
+            }
+
+            sig = (unsigned char*)XMALLOC(sigSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            if (sig == NULL) {
+                return WOLFSSL_FAILURE;
+            }
+
+            if (wolfSSL_X509_get_signature(x509, sig, &sigSz) <= 0) {
+                XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                return WOLFSSL_FAILURE;
+            }
+            XSNPRINTF(tmp, sizeof(tmp) - 1,"         ");
+            tmp[sizeof(tmp) - 1] = '\0';
+            for (i = 0; i < sigSz; i++) {
+                char val[5];
+                int valSz = 5;
+
+                if (i == 0) {
+                    XSNPRINTF(val, valSz - 1, "%02x", sig[i]);
+                }
+                else if (((i % 18) == 0)) {
+                    tmp[sizeof(tmp) - 1] = '\0';
+                    if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp))
+                            <= 0) {
+                        XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                        return WOLFSSL_FAILURE;
+                    }
+                    XSNPRINTF(tmp, sizeof(tmp) - 1,
+                            ":\n         ");
+                    XSNPRINTF(val, valSz - 1, "%02x", sig[i]);
+                }
+                else {
+                    XSNPRINTF(val, valSz - 1, ":%02x", sig[i]);
+                }
+                XSTRNCAT(tmp, val, valSz);
+            }
+            XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+            /* print out remaning sig values */
+            if ((i > 0) && (((i - 1) % 18) != 0)) {
+                    tmp[sizeof(tmp) - 1] = '\0';
+                    if (wolfSSL_BIO_write(bio, tmp, (int)XSTRLEN(tmp))
+                            <= 0) {
+                        return WOLFSSL_FAILURE;
+                    }
+            }
+        }
+
+        /* done with print out */
+        if (wolfSSL_BIO_write(bio, "\n", sizeof("\n")) <= 0) {
+            return WOLFSSL_FAILURE;
+        }
+
+        return WOLFSSL_SUCCESS;
+    }
+#endif /* XSNPRINTF */
+
+#endif /* NO_CERTS */
 
 char* wolfSSL_CIPHER_description(const WOLFSSL_CIPHER* cipher, char* in,
@@ -15426,13 +17648,15 @@
 #endif /* NO_SESSION_CACHE */
 
-#ifndef NO_CERTS
-void wolfSSL_X509_free(WOLFSSL_X509* x509)
-{
-    WOLFSSL_ENTER("wolfSSL_X509_free");
-    ExternalFreeX509(x509);
-}
-#endif /* NO_CERTS */
-
-
+
+
+/* was do nothing */
+/*
+void OPENSSL_free(void* buf)
+{
+    (void)buf;
+}
+*/
+
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_OCSP_parse_url(char* url, char** host, char** port, char** path,
                    int* ssl)
@@ -15443,19 +17667,8 @@
     (void)path;
     (void)ssl;
+    WOLFSSL_STUB("OCSP_parse_url");
     return 0;
 }
-
-
-WOLFSSL_METHOD* wolfSSLv2_client_method(void)
-{
-    return 0;
-}
-
-
-WOLFSSL_METHOD* wolfSSLv2_server_method(void)
-{
-    return 0;
-}
-
+#endif
 
 #ifndef NO_MD4
@@ -15489,8 +17702,27 @@
 
 
-WOLFSSL_BIO* wolfSSL_BIO_pop(WOLFSSL_BIO* top)
-{
-    (void)top;
-    return 0;
+/* Removes a WOLFSSL_BIO struct from the WOLFSSL_BIO linked list.
+ *
+ * bio is the WOLFSSL_BIO struct in the list and removed.
+ *
+ * The return WOLFSSL_BIO struct is the next WOLFSSL_BIO in the list or NULL if
+ * there is none.
+ */
+WOLFSSL_BIO* wolfSSL_BIO_pop(WOLFSSL_BIO* bio)
+{
+    if (bio == NULL) {
+        WOLFSSL_MSG("Bad argument passed in");
+        return NULL;
+    }
+
+    if (bio->prev != NULL) {
+        bio->prev->next = bio->next;
+    }
+
+    if (bio->next != NULL) {
+        bio->next->prev = bio->prev;
+    }
+
+    return bio->next;
 }
 
@@ -15498,7 +17730,5 @@
 int wolfSSL_BIO_pending(WOLFSSL_BIO* bio)
 {
-    if (bio && bio->type == BIO_MEMORY)
-        return bio->memLen;
-    return 0;
+    return (int)wolfSSL_BIO_ctrl_pending(bio);
 }
 
@@ -15510,5 +17740,5 @@
 
     WOLFSSL_ENTER("BIO_s_mem");
-    meth.type = BIO_MEMORY;
+    meth.type = WOLFSSL_BIO_MEMORY;
 
     return &meth;
@@ -15518,35 +17748,35 @@
 WOLFSSL_BIO_METHOD* wolfSSL_BIO_f_base64(void)
 {
-    return 0;
-}
-
-
+    static WOLFSSL_BIO_METHOD meth;
+
+    WOLFSSL_ENTER("wolfSSL_BIO_f_base64");
+    meth.type = WOLFSSL_BIO_BASE64;
+
+    return &meth;
+}
+
+
+/* Set the flag for the bio.
+ *
+ * bio   the structre to set the flag in
+ * flags the flag to use
+ */
 void wolfSSL_BIO_set_flags(WOLFSSL_BIO* bio, int flags)
 {
-    (void)bio;
-    (void)flags;
-}
-
-
-
+    WOLFSSL_ENTER("wolfSSL_BIO_set_flags");
+
+    if (bio != NULL) {
+        bio->flags |= flags;
+    }
+}
+
+
+#ifndef NO_WOLFSSL_STUB
 void wolfSSL_RAND_screen(void)
 {
-
-}
-
-
-const char* wolfSSL_RAND_file_name(char* fname, unsigned long len)
-{
-    (void)fname;
-    (void)len;
-    return 0;
-}
-
-
-int wolfSSL_RAND_write_file(const char* fname)
-{
-    (void)fname;
-    return 0;
-}
+    WOLFSSL_STUB("RAND_screen");
+}
+#endif
+
 
 
@@ -15562,51 +17792,56 @@
 
 
-int wolfSSL_RAND_egd(const char* path)
-{
-    (void)path;
+#ifndef NO_WOLFSSL_STUB
+WOLFSSL_COMP_METHOD* wolfSSL_COMP_zlib(void)
+{
+    WOLFSSL_STUB("COMP_zlib");
     return 0;
 }
-
-
-
-WOLFSSL_COMP_METHOD* wolfSSL_COMP_zlib(void)
-{
+#endif
+
+#ifndef NO_WOLFSSL_STUB
+WOLFSSL_COMP_METHOD* wolfSSL_COMP_rle(void)
+{
+    WOLFSSL_STUB("COMP_rle");
     return 0;
 }
-
-
-WOLFSSL_COMP_METHOD* wolfSSL_COMP_rle(void)
-{
-    return 0;
-}
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_COMP_add_compression_method(int method, void* data)
 {
     (void)method;
     (void)data;
+    WOLFSSL_STUB("COMP_add_compression_method");
     return 0;
 }
-
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 void wolfSSL_set_dynlock_create_callback(WOLFSSL_dynlock_value* (*f)(
                                                           const char*, int))
 {
+    WOLFSSL_STUB("CRYPTO_set_dynlock_create_callback");
     (void)f;
 }
-
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 void wolfSSL_set_dynlock_lock_callback(
              void (*f)(int, WOLFSSL_dynlock_value*, const char*, int))
 {
+    WOLFSSL_STUB("CRYPTO_set_set_dynlock_lock_callback");
     (void)f;
 }
-
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 void wolfSSL_set_dynlock_destroy_callback(
                   void (*f)(WOLFSSL_dynlock_value*, const char*, int))
 {
+    WOLFSSL_STUB("CRYPTO_set_set_dynlock_destroy_callback");
     (void)f;
 }
-
+#endif
 
 
@@ -15617,5 +17852,5 @@
 
 
-
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_X509_LOOKUP_add_dir(WOLFSSL_X509_LOOKUP* lookup, const char* dir,
                                long len)
@@ -15624,12 +17859,14 @@
     (void)dir;
     (void)len;
+    WOLFSSL_STUB("X509_LOOKUP_add_dir");
     return 0;
 }
-
+#endif
 
 int wolfSSL_X509_LOOKUP_load_file(WOLFSSL_X509_LOOKUP* lookup,
                                  const char* file, long type)
 {
-#ifndef NO_FILESYSTEM
+#if !defined(NO_FILESYSTEM) && \
+    (defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM))
     int           ret = WOLFSSL_FAILURE;
     XFILE         fp;
@@ -15639,4 +17876,6 @@
     byte*         prev = NULL;
     WOLFSSL_X509* x509;
+    const char* header = NULL;
+    const char* footer = NULL;
 
     if (type != X509_FILETYPE_PEM)
@@ -15644,8 +17883,11 @@
 
     fp = XFOPEN(file, "r");
-    if (fp == NULL)
+    if (fp == XBADFILE)
         return BAD_FUNC_ARG;
 
-    XFSEEK(fp, 0, XSEEK_END);
+    if(XFSEEK(fp, 0, XSEEK_END) != 0) {
+        XFCLOSE(fp);
+        return WOLFSSL_BAD_FILE;
+    }
     sz = XFTELL(fp);
     XREWIND(fp);
@@ -15666,5 +17908,7 @@
     prev = curr = pem;
     do {
-        if (XSTRNSTR((char*)curr, BEGIN_X509_CRL, (unsigned int)sz) != NULL) {
+        /* get PEM header and footer based on type */
+        if (wc_PemGetHeaderFooter(CRL_TYPE, &header, &footer) == 0 &&
+                XSTRNSTR((char*)curr, header, (unsigned int)sz) != NULL) {
 #ifdef HAVE_CRL
             WOLFSSL_CERT_MANAGER* cm = lookup->store->cm;
@@ -15681,7 +17925,8 @@
                 goto end;
 #endif
-            curr = (byte*)XSTRNSTR((char*)curr, END_X509_CRL, (unsigned int)sz);
-        }
-        else if (XSTRNSTR((char*)curr, BEGIN_CERT, (unsigned int)sz) != NULL) {
+            curr = (byte*)XSTRNSTR((char*)curr, footer, (unsigned int)sz);
+        }
+        else if (wc_PemGetHeaderFooter(CERT_TYPE, &header, &footer) == 0 &&
+                XSTRNSTR((char*)curr, header, (unsigned int)sz) != NULL) {
             x509 = wolfSSL_X509_load_certificate_buffer(curr, (int)sz,
                                                         WOLFSSL_FILETYPE_PEM);
@@ -15692,5 +17937,5 @@
             if (ret != WOLFSSL_SUCCESS)
                 goto end;
-            curr = (byte*)XSTRNSTR((char*)curr, END_CERT, (unsigned int)sz);
+            curr = (byte*)XSTRNSTR((char*)curr, footer, (unsigned int)sz);
         }
         else
@@ -15719,5 +17964,4 @@
 }
 
-
 WOLFSSL_X509_LOOKUP_METHOD* wolfSSL_X509_LOOKUP_hash_dir(void)
 {
@@ -15738,4 +17982,7 @@
                                                WOLFSSL_X509_LOOKUP_METHOD* m)
 {
+    if (store == NULL)
+        return NULL;
+
     /* Method is a dummy value and is not needed. */
     (void)m;
@@ -15747,4 +17994,74 @@
 
 #ifndef NO_CERTS
+/* Converts the X509 to DER format and outputs it into bio.
+ *
+ * bio  is the structure to hold output DER
+ * x509 certificate to create DER from
+ *
+ * returns WOLFSSL_SUCCESS on success
+ */
+int wolfSSL_i2d_X509_bio(WOLFSSL_BIO* bio, WOLFSSL_X509* x509)
+{
+    WOLFSSL_ENTER("wolfSSL_i2d_X509_bio");
+
+    if (bio == NULL || x509 == NULL) {
+        return WOLFSSL_FAILURE;
+    }
+
+    if (x509->derCert != NULL) {
+        word32 len = x509->derCert->length;
+        byte*  der = x509->derCert->buffer;
+
+        if (wolfSSL_BIO_write(bio, der, len) == (int)len) {
+            return SSL_SUCCESS;
+        }
+    }
+
+    return WOLFSSL_FAILURE;
+}
+
+
+/* Converts an internal structure to a DER buffer
+ *
+ * x509 structure to get DER buffer from
+ * out  buffer to hold result. If NULL then *out is NULL then a new buffer is
+ *      created.
+ *
+ * returns the size of the DER result on success
+ */
+int wolfSSL_i2d_X509(WOLFSSL_X509* x509, unsigned char** out)
+{
+    const unsigned char* der;
+    int derSz = 0;
+
+    if (x509 == NULL || out == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    der = wolfSSL_X509_get_der(x509, &derSz);
+    if (der == NULL) {
+        return MEMORY_E;
+    }
+
+    if (*out == NULL) {
+        *out = (unsigned char*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_OPENSSL);
+        if (*out == NULL) {
+            return MEMORY_E;
+        }
+    }
+
+    XMEMCPY(*out, der, derSz);
+
+    return derSz;
+}
+
+
+/* Converts the DER from bio and creates a WOLFSSL_X509 structure from it.
+ *
+ * bio  is the structure holding DER
+ * x509 certificate to create from DER. Can be NULL
+ *
+ * returns pointer to WOLFSSL_X509 structure on success and NULL on fail
+ */
 WOLFSSL_X509* wolfSSL_d2i_X509_bio(WOLFSSL_BIO* bio, WOLFSSL_X509** x509)
 {
@@ -15831,5 +18148,114 @@
 
 
-/* return 1 on success, 0 on failure */
+/* helper function to get DER buffer from WOLFSSL_EVP_PKEY */
+static int wolfSSL_i2d_PrivateKey(WOLFSSL_EVP_PKEY* key, unsigned char** der)
+{
+    *der = (unsigned char*)key->pkey.ptr;
+
+    return key->pkey_sz;
+}
+
+
+
+/* Creates a new WC_PKCS12 structure
+ *
+ * pass  password to use
+ * name  friendlyName to use
+ * pkey  private key to go into PKCS12 bundle
+ * cert  certificate to go into PKCS12 bundle
+ * ca    extra certificates that can be added to bundle. Can be NULL
+ * keyNID  type of encryption to use on the key (-1 means no encryption)
+ * certNID type of ecnryption to use on the certificate
+ * itt     number of iterations with encryption
+ * macItt  number of iterations with mac creation
+ * keyType flag for signature and/or encryption key
+ *
+ * returns a pointer to a new WC_PKCS12 structure on success and NULL on fail
+ */
+WC_PKCS12* wolfSSL_PKCS12_create(char* pass, char* name,
+        WOLFSSL_EVP_PKEY* pkey, WOLFSSL_X509* cert,
+        WOLF_STACK_OF(WOLFSSL_X509)* ca,
+        int keyNID, int certNID, int itt, int macItt, int keyType)
+{
+    WC_PKCS12*      pkcs12;
+    WC_DerCertList* list = NULL;
+    word32 passSz;
+    byte* keyDer;
+    word32 keyDerSz;
+    byte* certDer;
+    int certDerSz;
+
+    int ret;
+
+    WOLFSSL_ENTER("wolfSSL_PKCS12_create()");
+
+    if (pass == NULL || pkey == NULL || cert == NULL) {
+        WOLFSSL_LEAVE("wolfSSL_PKCS12_create()", BAD_FUNC_ARG);
+        return NULL;
+    }
+    passSz = (word32)XSTRLEN(pass);
+
+    if ((ret = wolfSSL_i2d_PrivateKey(pkey, &keyDer)) < 0) {
+        WOLFSSL_LEAVE("wolfSSL_PKCS12_create", ret);
+        return NULL;
+    }
+    keyDerSz = ret;
+
+    certDer = (byte*)wolfSSL_X509_get_der(cert, &certDerSz);
+    if (certDer == NULL) {
+        return NULL;
+    }
+
+    if (ca != NULL) {
+        WC_DerCertList* cur;
+        unsigned long numCerts = ca->num;
+        byte* curDer;
+        int   curDerSz = 0;
+        WOLFSSL_STACK* sk = ca;
+
+        while (numCerts > 0 && sk != NULL) {
+            cur = (WC_DerCertList*)XMALLOC(sizeof(WC_DerCertList), NULL,
+                    DYNAMIC_TYPE_PKCS);
+            if (cur == NULL) {
+                wc_FreeCertList(list, NULL);
+                return NULL;
+            }
+
+            curDer = (byte*)wolfSSL_X509_get_der(sk->data.x509, &curDerSz);
+            if (curDer == NULL || curDerSz < 0) {
+                XFREE(cur, NULL, DYNAMIC_TYPE_PKCS);
+                wc_FreeCertList(list, NULL);
+                return NULL;
+            }
+
+            cur->buffer = (byte*)XMALLOC(curDerSz, NULL, DYNAMIC_TYPE_PKCS);
+            if (cur->buffer == NULL) {
+                XFREE(cur, NULL, DYNAMIC_TYPE_PKCS);
+                wc_FreeCertList(list, NULL);
+                return NULL;
+            }
+            XMEMCPY(cur->buffer, curDer, curDerSz);
+            cur->bufferSz = curDerSz;
+            cur->next = list;
+            list = cur;
+
+            sk = sk->next;
+            numCerts--;
+        }
+    }
+
+    pkcs12 = wc_PKCS12_create(pass, passSz, name, keyDer, keyDerSz,
+            certDer, certDerSz, list, keyNID, certNID, itt, macItt,
+            keyType, NULL);
+
+    if (ca != NULL) {
+        wc_FreeCertList(list, NULL);
+    }
+
+    return pkcs12;
+}
+
+
+/* return WOLFSSL_SUCCESS on success, WOLFSSL_FAILURE on failure */
 int wolfSSL_PKCS12_parse(WC_PKCS12* pkcs12, const char* psw,
       WOLFSSL_EVP_PKEY** pkey, WOLFSSL_X509** cert, WOLF_STACK_OF(WOLFSSL_X509)** ca)
@@ -15846,12 +18272,15 @@
     WOLFSSL_ENTER("wolfSSL_PKCS12_parse");
 
+    /* make sure we init return args */
+    if (pkey) *pkey = NULL;
+    if (cert) *cert = NULL;
+    if (ca)   *ca = NULL;
+
     if (pkcs12 == NULL || psw == NULL || pkey == NULL || cert == NULL) {
         WOLFSSL_MSG("Bad argument value");
-        return 0;
+        return WOLFSSL_FAILURE;
     }
 
     heap  = wc_PKCS12_GetHeap(pkcs12);
-    *pkey = NULL;
-    *cert = NULL;
 
     if (ca == NULL) {
@@ -15860,5 +18289,4 @@
     }
     else {
-        *ca = NULL;
         ret = wc_PKCS12_parse(pkcs12, psw, &pk, &pkSz, &certData, &certDataSz,
             &certList);
@@ -15866,5 +18294,5 @@
     if (ret < 0) {
         WOLFSSL_LEAVE("wolfSSL_PKCS12_parse", ret);
-        return 0;
+        return WOLFSSL_FAILURE;
     }
 
@@ -15890,5 +18318,5 @@
                 current = next;
             }
-            return 0;
+            return WOLFSSL_FAILURE;
         }
         XMEMSET(*ca, 0, sizeof(WOLF_STACK_OF(WOLFSSL_X509)));
@@ -15928,5 +18356,5 @@
                         current = next;
                     }
-                    return 0;
+                    return WOLFSSL_FAILURE;
                 }
                 FreeDecodedCert(&DeCert);
@@ -15951,5 +18379,5 @@
                         current = next;
                     }
-                    return 0;
+                    return WOLFSSL_FAILURE;
                 }
             }
@@ -15973,5 +18401,5 @@
             }
             XFREE(certData, heap, DYNAMIC_TYPE_PKCS);
-            return 0;
+            return WOLFSSL_FAILURE;
         }
         InitX509(*cert, 1, heap);
@@ -15990,5 +18418,5 @@
             }
             wolfSSL_X509_free(*cert); *cert = NULL;
-            return 0;
+            return WOLFSSL_FAILURE;
         }
         FreeDecodedCert(&DeCert);
@@ -16000,7 +18428,5 @@
     ret = BAD_STATE_E;
     if (pk != NULL) { /* decode key if present */
-        /* using dynamic type public key because of wolfSSL_EVP_PKEY_free */
-        *pkey = (WOLFSSL_EVP_PKEY*)XMALLOC(sizeof(WOLFSSL_EVP_PKEY),
-                                               heap, DYNAMIC_TYPE_PUBLIC_KEY);
+        *pkey = wolfSSL_PKEY_new_ex(heap);
         if (*pkey == NULL) {
             wolfSSL_X509_free(*cert); *cert = NULL;
@@ -16009,5 +18435,5 @@
             }
             XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY);
-            return 0;
+            return WOLFSSL_FAILURE;
         }
         #ifndef NO_RSA
@@ -16022,6 +18448,31 @@
                 if ((ret = wc_RsaPrivateKeyDecode(pk, &keyIdx, &key, pkSz))
                                                                          == 0) {
-                    (*pkey)->type = RSAk;
+                    (*pkey)->type = EVP_PKEY_RSA;
+                    (*pkey)->rsa  = wolfSSL_RSA_new();
+                    (*pkey)->ownRsa = 1; /* we own RSA */
+                    if ((*pkey)->rsa == NULL) {
+                        WOLFSSL_MSG("issue creating EVP RSA key");
+                        wolfSSL_X509_free(*cert); *cert = NULL;
+                        if (ca != NULL) {
+                            wolfSSL_sk_X509_free(*ca); *ca = NULL;
+                        }
+                        wolfSSL_EVP_PKEY_free(*pkey); *pkey = NULL;
+                        XFREE(pk, heap, DYNAMIC_TYPE_PKCS);
+                        return WOLFSSL_FAILURE;
+                    }
+                    if ((ret = wolfSSL_RSA_LoadDer_ex((*pkey)->rsa, pk, pkSz,
+                                    WOLFSSL_RSA_LOAD_PRIVATE)) != SSL_SUCCESS) {
+                        WOLFSSL_MSG("issue loading RSA key");
+                        wolfSSL_X509_free(*cert); *cert = NULL;
+                        if (ca != NULL) {
+                            wolfSSL_sk_X509_free(*ca); *ca = NULL;
+                        }
+                        wolfSSL_EVP_PKEY_free(*pkey); *pkey = NULL;
+                        XFREE(pk, heap, DYNAMIC_TYPE_PKCS);
+                        return WOLFSSL_FAILURE;
+                    }
+
                     WOLFSSL_MSG("Found PKCS12 RSA key");
+                    ret = 0; /* set in success state for upcoming ECC check */
                 }
                 wc_FreeRsaKey(&key);
@@ -16041,7 +18492,7 @@
                         wolfSSL_sk_X509_free(*ca); *ca = NULL;
                     }
-                    XFREE(*pkey, heap, DYNAMIC_TYPE_PUBLIC_KEY); *pkey = NULL;
-                    XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY);
-                    return 0;
+                    wolfSSL_EVP_PKEY_free(*pkey); *pkey = NULL;
+                    XFREE(pk, heap, DYNAMIC_TYPE_PKCS);
+                    return WOLFSSL_FAILURE;
                 }
 
@@ -16052,10 +18503,10 @@
                         wolfSSL_sk_X509_free(*ca); *ca = NULL;
                     }
-                    XFREE(*pkey, heap, DYNAMIC_TYPE_PUBLIC_KEY); *pkey = NULL;
-                    XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY);
+                    wolfSSL_EVP_PKEY_free(*pkey); *pkey = NULL;
+                    XFREE(pk, heap, DYNAMIC_TYPE_PKCS);
                     WOLFSSL_MSG("Bad PKCS12 key format");
-                    return 0;
+                    return WOLFSSL_FAILURE;
                 }
-                (*pkey)->type = ECDSAk;
+                (*pkey)->type = EVP_PKEY_EC;
                 (*pkey)->pkey_curve = key.dp->oidSum;
                 wc_ecc_free(&key);
@@ -16069,8 +18520,8 @@
                 wolfSSL_sk_X509_free(*ca); *ca = NULL;
             }
-            XFREE(*pkey, heap, DYNAMIC_TYPE_PUBLIC_KEY); *pkey = NULL;
-            XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY);
+            wolfSSL_EVP_PKEY_free(*pkey); *pkey = NULL;
+            XFREE(pk, heap, DYNAMIC_TYPE_PKCS);
             WOLFSSL_MSG("Bad PKCS12 key format");
-            return 0;
+            return WOLFSSL_FAILURE;
         }
         #endif /* HAVE_ECC */
@@ -16084,5 +18535,5 @@
     (void)ca;
 
-    return 1;
+    return WOLFSSL_SUCCESS;
 }
 #endif /* !defined(NO_ASN) && !defined(NO_PWDBASED) */
@@ -16100,7 +18551,74 @@
 WOLFSSL_STACK* wolfSSL_X509_STORE_CTX_get_chain(WOLFSSL_X509_STORE_CTX* ctx)
 {
+    WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_get_chain");
+
     if (ctx == NULL) {
         return NULL;
     }
+
+#ifdef SESSION_CERTS
+    /* if chain is null but sesChain is available then populate stack */
+    if (ctx->chain == NULL && ctx->sesChain != NULL) {
+        int i;
+        WOLFSSL_X509_CHAIN* c = ctx->sesChain;
+        WOLFSSL_STACK*     sk = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK),
+                                    NULL, DYNAMIC_TYPE_X509);
+
+        if (sk == NULL) {
+            return NULL;
+        }
+
+        XMEMSET(sk, 0, sizeof(WOLFSSL_STACK));
+        ctx->chain = sk;
+
+        for (i = 0; i < c->count && i < MAX_CHAIN_DEPTH; i++) {
+            WOLFSSL_X509* x509 = wolfSSL_get_chain_X509(c, i);
+
+            if (x509 == NULL) {
+                WOLFSSL_MSG("Unable to get x509 from chain");
+                wolfSSL_sk_X509_free(sk);
+                return NULL;
+            }
+
+            if (wolfSSL_sk_X509_push(sk, x509) != SSL_SUCCESS) {
+                WOLFSSL_MSG("Unable to load x509 into stack");
+                wolfSSL_sk_X509_free(sk);
+                wolfSSL_X509_free(x509);
+                return NULL;
+            }
+        }
+
+#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || defined(OPENSSL_EXTRA)
+        /* add CA used to verify top of chain to the list */
+        if (c->count > 0) {
+            WOLFSSL_X509* x509 = wolfSSL_get_chain_X509(c, c->count - 1);
+            if (x509 != NULL) {
+                WOLFSSL_X509* issuer = NULL;
+                if (wolfSSL_X509_STORE_CTX_get1_issuer(&issuer, ctx, x509)
+                        == WOLFSSL_SUCCESS) {
+                    /* check that the certificate being looked up is not self
+                     * signed and that a issuer was found */
+                    if (issuer != NULL && wolfSSL_X509_NAME_cmp(&x509->issuer,
+                                &x509->subject) != 0) {
+                        if (wolfSSL_sk_X509_push(sk, issuer) != SSL_SUCCESS) {
+                            WOLFSSL_MSG("Unable to load CA x509 into stack");
+                            wolfSSL_sk_X509_free(sk);
+                            wolfSSL_X509_free(issuer);
+                            return NULL;
+                        }
+                    }
+                    else {
+                        WOLFSSL_MSG("Certificate is self signed");
+                    }
+                }
+                else {
+                    WOLFSSL_MSG("Could not find CA for certificate");
+                }
+            }
+        }
+#endif
+
+    }
+#endif /* SESSION_CERTS */
 
     return ctx->chain;
@@ -16136,22 +18654,40 @@
 }
 
-
 WOLFSSL_X509_STORE* wolfSSL_X509_STORE_new(void)
 {
     WOLFSSL_X509_STORE* store = NULL;
 
-    store = (WOLFSSL_X509_STORE*)XMALLOC(sizeof(WOLFSSL_X509_STORE), NULL,
-                                         DYNAMIC_TYPE_X509_STORE);
-    if (store != NULL) {
-        store->cm = wolfSSL_CertManagerNew();
-        if (store->cm == NULL) {
-            XFREE(store, NULL, DYNAMIC_TYPE_X509_STORE);
-            store = NULL;
-        }
-        else
-            store->isDynamic = 1;
-    }
+    if((store = (WOLFSSL_X509_STORE*)XMALLOC(sizeof(WOLFSSL_X509_STORE), NULL,
+                            DYNAMIC_TYPE_X509_STORE)) == NULL)
+        goto err_exit;
+
+    if((store->cm = wolfSSL_CertManagerNew()) == NULL)
+        goto err_exit;
+
+    store->isDynamic = 1;
+
+#ifdef HAVE_CRL
+    store->crl = NULL;
+    if((store->crl = (WOLFSSL_X509_CRL *)XMALLOC(sizeof(WOLFSSL_X509_CRL),
+                                NULL, DYNAMIC_TYPE_TMP_BUFFER)) == NULL)
+        goto err_exit;
+    if(InitCRL(store->crl, NULL) < 0)
+        goto err_exit;
+#endif
 
     return store;
+
+err_exit:
+    if(store == NULL)
+        return NULL;
+    if(store->cm != NULL)
+        wolfSSL_CertManagerFree(store->cm);
+#ifdef HAVE_CRL
+    if(store->crl != NULL)
+        wolfSSL_X509_CRL_free(store->crl);
+#endif
+    wolfSSL_X509_STORE_free(store);
+
+    return NULL;
 }
 
@@ -16161,5 +18697,9 @@
     if (store != NULL && store->isDynamic) {
         if (store->cm != NULL)
-        wolfSSL_CertManagerFree(store->cm);
+            wolfSSL_CertManagerFree(store->cm);
+#ifdef HAVE_CRL
+        if (store->crl != NULL)
+            wolfSSL_X509_CRL_free(store->crl);
+#endif
         XFREE(store, NULL, DYNAMIC_TYPE_X509_STORE);
     }
@@ -16172,4 +18712,7 @@
 
     WOLFSSL_ENTER("wolfSSL_X509_STORE_set_flags");
+
+    if (store == NULL)
+        return WOLFSSL_FAILURE;
 
     if ((flag & WOLFSSL_CRL_CHECKALL) || (flag & WOLFSSL_CRL_CHECK)) {
@@ -16190,5 +18733,5 @@
 }
 
-
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_X509_STORE_get_by_subject(WOLFSSL_X509_STORE_CTX* ctx, int idx,
                             WOLFSSL_X509_NAME* name, WOLFSSL_X509_OBJECT* obj)
@@ -16198,7 +18741,8 @@
     (void)name;
     (void)obj;
+    WOLFSSL_STUB("X509_STORE_get_by_subject");
     return 0;
 }
-
+#endif
 
 WOLFSSL_X509_STORE_CTX* wolfSSL_X509_STORE_CTX_new(void)
@@ -16207,6 +18751,8 @@
                                     sizeof(WOLFSSL_X509_STORE_CTX), NULL,
                                     DYNAMIC_TYPE_X509_CTX);
-    if (ctx != NULL)
+    if (ctx != NULL) {
+        ctx->param = NULL;
         wolfSSL_X509_STORE_CTX_init(ctx, NULL, NULL, NULL);
+    }
 
     return ctx;
@@ -16221,5 +18767,15 @@
     if (ctx != NULL) {
         ctx->store = store;
+        #ifndef WOLFSSL_X509_STORE_CERTS
         ctx->current_cert = x509;
+        #else
+        if(x509 != NULL){
+            ctx->current_cert = wolfSSL_X509_d2i(NULL, x509->derCert->buffer,x509->derCert->length);
+            if(ctx->current_cert == NULL)
+                return WOLFSSL_FATAL_ERROR;
+        } else
+            ctx->current_cert = NULL;
+        #endif
+
         ctx->chain  = sk;
         ctx->domain = NULL;
@@ -16231,5 +18787,16 @@
         ctx->error_depth = 0;
         ctx->discardSessionCerts = 0;
-        return WOLFSSL_SUCCESS;
+#ifdef OPENSSL_EXTRA
+        if (ctx->param == NULL) {
+            ctx->param = (WOLFSSL_X509_VERIFY_PARAM*)XMALLOC(
+                           sizeof(WOLFSSL_X509_VERIFY_PARAM),
+                           NULL,DYNAMIC_TYPE_OPENSSL);
+            if (ctx->param == NULL){
+                WOLFSSL_MSG("wolfSSL_X509_STORE_CTX_init failed");
+                return SSL_FATAL_ERROR;
+            }
+        }
+#endif
+        return SSL_SUCCESS;
     }
     return WOLFSSL_FATAL_ERROR;
@@ -16242,8 +18809,15 @@
         if (ctx->store != NULL)
             wolfSSL_X509_STORE_free(ctx->store);
+        #ifndef WOLFSSL_KEEP_STORE_CERTS
         if (ctx->current_cert != NULL)
             wolfSSL_FreeX509(ctx->current_cert);
+        #endif
         if (ctx->chain != NULL)
             wolfSSL_sk_X509_free(ctx->chain);
+#ifdef OPENSSL_EXTRA
+        if (ctx->param != NULL){
+            XFREE(ctx->param,NULL,DYNAMIC_TYPE_OPENSSL);
+        }
+#endif
         XFREE(ctx, NULL, DYNAMIC_TYPE_X509_CTX);
     }
@@ -16254,4 +18828,5 @@
 {
     (void)ctx;
+    /* Do nothing */
 }
 
@@ -16270,78 +18845,214 @@
 #endif /* NO_CERTS */
 
-
+#if !defined(NO_FILESYSTEM)
+static void *wolfSSL_d2i_X509_fp_ex(XFILE file, void **x509, int type)
+{
+    void *newx509 = NULL;
+    DerBuffer*   der = NULL;
+    byte *fileBuffer = NULL;
+
+    if (file != XBADFILE)
+    {
+        long sz = 0;
+
+        if(XFSEEK(file, 0, XSEEK_END) != 0)
+            return NULL;
+        sz = XFTELL(file);
+        XREWIND(file);
+
+        if (sz < 0)
+        {
+            WOLFSSL_MSG("Bad tell on FILE");
+            return NULL;
+        }
+
+        fileBuffer = (byte *)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE);
+        if (fileBuffer != NULL)
+        {
+            if((long)XFREAD(fileBuffer, 1, sz, file) != sz)
+            {
+                WOLFSSL_MSG("File read failed");
+                goto err_exit;
+            }
+            if(type == CERT_TYPE)
+                newx509 = (void *)wolfSSL_X509_d2i(NULL, fileBuffer, (int)sz);
+            #ifdef HAVE_CRL
+            else if(type == CRL_TYPE)
+                newx509 = (void *)wolfSSL_d2i_X509_CRL(NULL, fileBuffer, (int)sz);
+            #endif
+            #if !defined(NO_ASN) && !defined(NO_PWDBASED)
+            else if(type == PKCS12_TYPE){
+                if((newx509 = wc_PKCS12_new()) == NULL)
+                    goto err_exit;
+                if(wc_d2i_PKCS12(fileBuffer, (int)sz, (WC_PKCS12*)newx509) < 0)
+                    goto err_exit;
+            }
+            #endif
+            else goto err_exit;
+            if(newx509 == NULL)
+            {
+                WOLFSSL_MSG("X509 failed");
+                goto err_exit;
+            }
+        }
+    }
+    if (x509 != NULL)
+        *x509 = newx509;
+
+    goto _exit;
+
+err_exit:
+    if(newx509 != NULL){
+        if(type == CERT_TYPE)
+            wolfSSL_X509_free((WOLFSSL_X509*)newx509);
+        #ifdef HAVE_CRL
+        else {
+           if(type == CRL_TYPE)
+                wolfSSL_X509_CRL_free((WOLFSSL_X509_CRL*)newx509);
+        }
+        #endif
+    }
+_exit:
+    if(der != NULL)
+        FreeDer(&der);
+    if(fileBuffer != NULL)
+        XFREE(fileBuffer, NULL, DYNAMIC_TYPE_FILE);
+    return newx509;
+}
+
+WOLFSSL_X509_PKCS12 *wolfSSL_d2i_PKCS12_fp(XFILE fp, WOLFSSL_X509_PKCS12 **pkcs12)
+{
+    WOLFSSL_ENTER("wolfSSL_d2i_PKCS12_fp");
+    return (WOLFSSL_X509_PKCS12 *)wolfSSL_d2i_X509_fp_ex(fp, (void **)pkcs12, PKCS12_TYPE);
+}
+
+WOLFSSL_X509 *wolfSSL_d2i_X509_fp(XFILE fp, WOLFSSL_X509 **x509)
+{
+    WOLFSSL_ENTER("wolfSSL_d2i_X509_fp");
+    return (WOLFSSL_X509 *)wolfSSL_d2i_X509_fp_ex(fp, (void **)x509, CERT_TYPE);
+}
+#endif /* !NO_FILESYSTEM */
+
+
+#ifdef HAVE_CRL
+#ifndef NO_FILESYSTEM
+WOLFSSL_X509_CRL *wolfSSL_d2i_X509_CRL_fp(XFILE fp, WOLFSSL_X509_CRL **crl)
+{
+    WOLFSSL_ENTER("wolfSSL_d2i_X509_CRL_fp");
+    return (WOLFSSL_X509_CRL *)wolfSSL_d2i_X509_fp_ex(fp, (void **)crl, CRL_TYPE);
+}
+#endif /* !NO_FILESYSTEM */
+
+
+WOLFSSL_X509_CRL* wolfSSL_d2i_X509_CRL(WOLFSSL_X509_CRL** crl, const unsigned char* in, int len)
+{
+    WOLFSSL_X509_CRL *newcrl = NULL;
+    int ret ;
+
+    WOLFSSL_ENTER("wolfSSL_d2i_X509_CRL");
+
+    if(in == NULL){
+        WOLFSSL_MSG("Bad argument value");
+        return NULL;
+    }
+
+    newcrl = (WOLFSSL_X509_CRL*)XMALLOC(sizeof(WOLFSSL_X509_CRL), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (newcrl == NULL){
+        WOLFSSL_MSG("New CRL allocation failed");
+        return NULL;
+    }
+    if (InitCRL(newcrl, NULL) < 0) {
+        WOLFSSL_MSG("Init tmp CRL failed");
+        goto err_exit;
+    }
+    ret = BufferLoadCRL(newcrl, in, len, WOLFSSL_FILETYPE_ASN1, 1);
+    if (ret != WOLFSSL_SUCCESS){
+        WOLFSSL_MSG("Buffer Load CRL failed");
+        goto err_exit;
+    }
+    if(crl){
+        *crl = newcrl;
+    }
+    goto _exit;
+
+err_exit:
+    if(newcrl != NULL)
+        wolfSSL_X509_CRL_free(newcrl);
+    newcrl = NULL;
+_exit:
+    return newcrl;
+}
+
+void wolfSSL_X509_CRL_free(WOLFSSL_X509_CRL *crl)
+{
+    WOLFSSL_ENTER("wolfSSL_X509_CRL_free");
+
+    FreeCRL(crl, 1);
+    return;
+}
+#endif /* HAVE_CRL */
+
+#ifndef NO_WOLFSSL_STUB
 WOLFSSL_ASN1_TIME* wolfSSL_X509_CRL_get_lastUpdate(WOLFSSL_X509_CRL* crl)
 {
     (void)crl;
+    WOLFSSL_STUB("X509_CRL_get_lastUpdate");
     return 0;
 }
-
-
+#endif
+#ifndef NO_WOLFSSL_STUB
 WOLFSSL_ASN1_TIME* wolfSSL_X509_CRL_get_nextUpdate(WOLFSSL_X509_CRL* crl)
 {
     (void)crl;
+    WOLFSSL_STUB("X509_CRL_get_nextUpdate");
     return 0;
 }
-
-
-
-WOLFSSL_EVP_PKEY* wolfSSL_X509_get_pubkey(WOLFSSL_X509* x509)
-{
-    WOLFSSL_EVP_PKEY* key = NULL;
-    if (x509 != NULL) {
-        key = (WOLFSSL_EVP_PKEY*)XMALLOC(
-                    sizeof(WOLFSSL_EVP_PKEY), x509->heap,
-                                                       DYNAMIC_TYPE_PUBLIC_KEY);
-        if (key != NULL) {
-            key->type = x509->pubKeyOID;
-            key->save_type = 0;
-            key->pkey.ptr = (char*)XMALLOC(
-                        x509->pubKey.length, x509->heap,
-                                                       DYNAMIC_TYPE_PUBLIC_KEY);
-            if (key->pkey.ptr == NULL) {
-                XFREE(key, x509->heap, DYNAMIC_TYPE_PUBLIC_KEY);
-                return NULL;
-            }
-            XMEMCPY(key->pkey.ptr,
-                                  x509->pubKey.buffer, x509->pubKey.length);
-            key->pkey_sz = x509->pubKey.length;
-            #ifdef HAVE_ECC
-                key->pkey_curve = (int)x509->pkCurveOID;
-            #endif /* HAVE_ECC */
-        }
-    }
-    return key;
-}
-
-
+#endif
+
+
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_X509_CRL_verify(WOLFSSL_X509_CRL* crl, WOLFSSL_EVP_PKEY* key)
 {
     (void)crl;
     (void)key;
+    WOLFSSL_STUB("X509_CRL_verify");
     return 0;
 }
-
-
-void wolfSSL_X509_STORE_CTX_set_error(WOLFSSL_X509_STORE_CTX* ctx, int err)
-{
-    (void)ctx;
-    (void)err;
-}
-
-
-void wolfSSL_X509_OBJECT_free_contents(WOLFSSL_X509_OBJECT* obj)
-{
-    (void)obj;
-}
-
-
-WOLFSSL_EVP_PKEY* wolfSSL_PKEY_new()
+#endif
+#endif /* OPENSSL_EXTRA */
+
+#if defined(OPENSSL_EXTRA_X509_SMALL)
+/* Subset of OPENSSL_EXTRA for PKEY operations PKEY free is needed by the
+ * subset of X509 API */
+
+WOLFSSL_EVP_PKEY* wolfSSL_PKEY_new(void){
+    return wolfSSL_PKEY_new_ex(NULL);
+}
+
+
+WOLFSSL_EVP_PKEY* wolfSSL_PKEY_new_ex(void* heap)
 {
     WOLFSSL_EVP_PKEY* pkey;
-
-    pkey = (WOLFSSL_EVP_PKEY*)XMALLOC(sizeof(WOLFSSL_EVP_PKEY), NULL,
+    int ret;
+    WOLFSSL_ENTER("wolfSSL_PKEY_new");
+    pkey = (WOLFSSL_EVP_PKEY*)XMALLOC(sizeof(WOLFSSL_EVP_PKEY), heap,
             DYNAMIC_TYPE_PUBLIC_KEY);
     if (pkey != NULL) {
         XMEMSET(pkey, 0, sizeof(WOLFSSL_EVP_PKEY));
+        pkey->heap = heap;
+        pkey->type = WOLFSSL_EVP_PKEY_DEFAULT;
+#ifndef HAVE_FIPS
+        ret = wc_InitRng_ex(&pkey->rng, heap, INVALID_DEVID);
+#else
+        ret = wc_InitRng(&pkey->rng);
+#endif
+        if (ret != 0){
+            wolfSSL_EVP_PKEY_free(pkey);
+            WOLFSSL_MSG("memory falure");
+            return NULL;
+        }
+    }
+    else {
+        WOLFSSL_MSG("memory failure");
     }
 
@@ -16352,34 +19063,92 @@
 void wolfSSL_EVP_PKEY_free(WOLFSSL_EVP_PKEY* key)
 {
+    WOLFSSL_ENTER("wolfSSL_EVP_PKEY_free");
     if (key != NULL) {
-        if (key->pkey.ptr != NULL)
-            XFREE(key->pkey.ptr, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
-        XFREE(key, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
-    }
-}
-
-
+        wc_FreeRng(&key->rng);
+
+        if (key->pkey.ptr != NULL) {
+            XFREE(key->pkey.ptr, key->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+            key->pkey.ptr = NULL;
+        }
+        switch(key->type)
+        {
+            #ifndef NO_RSA
+            case EVP_PKEY_RSA:
+                if (key->rsa != NULL && key->ownRsa == 1) {
+                    wolfSSL_RSA_free(key->rsa);
+                    key->rsa = NULL;
+                }
+                break;
+            #endif /* NO_RSA */
+
+            #ifdef HAVE_ECC
+            case EVP_PKEY_EC:
+                if (key->ecc != NULL && key->ownEcc == 1) {
+                    wolfSSL_EC_KEY_free(key->ecc);
+                    key->ecc = NULL;
+                }
+                break;
+            #endif /* HAVE_ECC */
+
+            default:
+            break;
+        }
+        XFREE(key, key->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+    }
+}
+#endif /* OPENSSL_EXTRA_X509_SMALL */
+
+
+#ifdef OPENSSL_EXTRA
+
+void wolfSSL_X509_STORE_CTX_set_time(WOLFSSL_X509_STORE_CTX* ctx,
+                                    unsigned long flags,
+                                    time_t t)
+{
+    (void)flags;
+
+    if (ctx == NULL || ctx->param == NULL)
+        return;
+
+    ctx->param->check_time = t;
+    ctx->param->flags |= WOLFSSL_USE_CHECK_TIME;
+}
+
+#ifndef NO_WOLFSSL_STUB
+void wolfSSL_X509_OBJECT_free_contents(WOLFSSL_X509_OBJECT* obj)
+{
+    (void)obj;
+    WOLFSSL_STUB("X509_OBJECT_free_contents");
+}
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_X509_cmp_current_time(const WOLFSSL_ASN1_TIME* asnTime)
 {
     (void)asnTime;
+    WOLFSSL_STUB("X509_cmp_current_time");
     return 0;
 }
-
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_sk_X509_REVOKED_num(WOLFSSL_X509_REVOKED* revoked)
 {
     (void)revoked;
+    WOLFSSL_STUB("sk_X509_REVOKED_num");
     return 0;
 }
-
-
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 WOLFSSL_X509_REVOKED* wolfSSL_X509_CRL_get_REVOKED(WOLFSSL_X509_CRL* crl)
 {
     (void)crl;
+    WOLFSSL_STUB("X509_CRL_get_REVOKED");
     return 0;
 }
-
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 WOLFSSL_X509_REVOKED* wolfSSL_sk_X509_REVOKED_value(
                                     WOLFSSL_X509_REVOKED* revoked, int value)
@@ -16387,7 +19156,39 @@
     (void)revoked;
     (void)value;
+    WOLFSSL_STUB("sk_X509_REVOKED_value");
     return 0;
 }
-
+#endif
+
+/* Used to create a new WOLFSSL_ASN1_INTEGER structure.
+ * returns a pointer to new structure on success and NULL on failure
+ */
+WOLFSSL_ASN1_INTEGER* wolfSSL_ASN1_INTEGER_new(void)
+{
+    WOLFSSL_ASN1_INTEGER* a;
+
+    a = (WOLFSSL_ASN1_INTEGER*)XMALLOC(sizeof(WOLFSSL_ASN1_INTEGER), NULL,
+                                       DYNAMIC_TYPE_OPENSSL);
+    if (a == NULL) {
+        return NULL;
+    }
+
+    XMEMSET(a, 0, sizeof(WOLFSSL_ASN1_INTEGER));
+    a->data    = a->intData;
+    a->dataMax = WOLFSSL_ASN1_INTEGER_MAX;
+    return a;
+}
+
+
+/* free's internal elements of WOLFSSL_ASN1_INTEGER and free's "in" itself */
+void wolfSSL_ASN1_INTEGER_free(WOLFSSL_ASN1_INTEGER* in)
+{
+    if (in != NULL) {
+        if (in->isDynamic) {
+            XFREE(in->data, NULL, DYNAMIC_TYPE_OPENSSL);
+        }
+        XFREE(in, NULL, DYNAMIC_TYPE_OPENSSL);
+    }
+}
 
 
@@ -16399,17 +19200,23 @@
     WOLFSSL_ENTER("wolfSSL_X509_get_serialNumber");
 
-    a = (WOLFSSL_ASN1_INTEGER*)XMALLOC(sizeof(WOLFSSL_ASN1_INTEGER), NULL,
-                                       DYNAMIC_TYPE_OPENSSL);
+    a = wolfSSL_ASN1_INTEGER_new();
     if (a == NULL)
         return NULL;
 
     /* Make sure there is space for the data, ASN.1 type and length. */
-    if (x509->serialSz > (int)(sizeof(WOLFSSL_ASN1_INTEGER) - 2)) {
-        XFREE(a, NULL, DYNAMIC_TYPE_OPENSSL);
-        return NULL;
+    if (x509->serialSz > (WOLFSSL_ASN1_INTEGER_MAX - 2)) {
+        /* dynamicly create data buffer, +2 for type and length */
+        a->data = (unsigned char*)XMALLOC(x509->serialSz + 2, NULL,
+                DYNAMIC_TYPE_OPENSSL);
+        if (a->data == NULL) {
+            wolfSSL_ASN1_INTEGER_free(a);
+            return NULL;
+        }
+        a->dataMax   = x509->serialSz + 2;
+        a->isDynamic = 1;
     }
 
     a->data[i++] = ASN_INTEGER;
-    a->data[i++] = (unsigned char)x509->serialSz;
+    i += SetLength(x509->serialSz, a->data + i);
     XMEMCPY(&a->data[i], x509->serial, x509->serialSz);
 
@@ -16417,7 +19224,8 @@
 }
 
+#endif /* OPENSSL_EXTRA */
 
 #if defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX) || \
-    defined(WOLFSSL_HAPROXY)
+    defined(WOLFSSL_HAPROXY) || defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)
 int wolfSSL_ASN1_TIME_print(WOLFSSL_BIO* bio, const WOLFSSL_ASN1_TIME* asnTime)
 {
@@ -16474,7 +19282,99 @@
     return buf;
 }
-#endif /* WOLFSSL_MYSQL_COMPATIBLE */
-
-
+#endif /* WOLFSSL_MYSQL_COMPATIBLE || WOLFSSL_NGINX || WOLFSSL_HAPROXY ||
+    OPENSSL_EXTRA*/
+
+
+#ifdef OPENSSL_EXTRA
+
+#if !defined(NO_ASN_TIME) && !defined(USER_TIME) && \
+    !defined(TIME_OVERRIDES) && !defined(NO_FILESYSTEM)
+
+WOLFSSL_ASN1_TIME* wolfSSL_ASN1_TIME_adj(WOLFSSL_ASN1_TIME *s, time_t t,
+                                    int offset_day, long offset_sec)
+{
+    const time_t sec_per_day = 24*60*60;
+    struct tm* ts = NULL;
+    struct tm* tmpTime = NULL;
+    time_t t_adj = 0;
+    time_t offset_day_sec = 0;
+
+#if defined(NEED_TMP_TIME)
+    struct tm tmpTimeStorage;
+    tmpTime = &tmpTimeStorage;
+#else
+    (void)tmpTime;
+#endif
+
+    WOLFSSL_ENTER("wolfSSL_ASN1_TIME_adj");
+
+    if (s == NULL){
+        s = (WOLFSSL_ASN1_TIME*)XMALLOC(sizeof(WOLFSSL_ASN1_TIME), NULL,
+                                        DYNAMIC_TYPE_OPENSSL);
+        if (s == NULL){
+            return NULL;
+        }
+    }
+
+    /* compute GMT time with offset */
+    offset_day_sec = offset_day * sec_per_day;
+    t_adj          = t + offset_day_sec + offset_sec;
+    ts             = (struct tm *)XGMTIME(&t_adj, tmpTime);
+    if (ts == NULL){
+        WOLFSSL_MSG("failed to get time data.");
+        XFREE(s, NULL, DYNAMIC_TYPE_OPENSSL);
+        return NULL;
+    }
+
+    /* create ASN1 time notation */
+    /* UTC Time */
+    if (ts->tm_year >= 50 && ts->tm_year < 150){
+        char utc_str[ASN_UTC_TIME_SIZE];
+        int utc_year = 0,utc_mon,utc_day,utc_hour,utc_min,utc_sec;
+        byte *data_ptr = NULL;
+
+        if (ts->tm_year >= 50 && ts->tm_year < 100){
+            utc_year = ts->tm_year;
+        } else if (ts->tm_year >= 100 && ts->tm_year < 150){
+            utc_year = ts->tm_year - 100;
+        }
+        utc_mon  = ts->tm_mon + 1;
+        utc_day  = ts->tm_mday;
+        utc_hour = ts->tm_hour;
+        utc_min  = ts->tm_min;
+        utc_sec  = ts->tm_sec;
+        XSNPRINTF((char *)utc_str, ASN_UTC_TIME_SIZE,
+                  "%02d%02d%02d%02d%02d%02dZ",
+                  utc_year, utc_mon, utc_day, utc_hour, utc_min, utc_sec);
+        data_ptr  = s->data;
+        *data_ptr = (byte) ASN_UTC_TIME; data_ptr++;
+        *data_ptr = (byte) ASN_UTC_TIME_SIZE; data_ptr++;
+        XMEMCPY(data_ptr,(byte *)utc_str, ASN_UTC_TIME_SIZE);
+    /* GeneralizedTime */
+    } else {
+        char gt_str[ASN_GENERALIZED_TIME_MAX];
+        int gt_year,gt_mon,gt_day,gt_hour,gt_min,gt_sec;
+        byte *data_ptr = NULL;
+
+        gt_year = ts->tm_year + 1900;
+        gt_mon  = ts->tm_mon + 1;
+        gt_day  = ts->tm_mday;
+        gt_hour = ts->tm_hour;
+        gt_min  = ts->tm_min;
+        gt_sec  = ts->tm_sec;
+        XSNPRINTF((char *)gt_str, ASN_GENERALIZED_TIME_MAX,
+                  "%4d%02d%02d%02d%02d%02dZ",
+                  gt_year, gt_mon, gt_day, gt_hour, gt_min,gt_sec);
+        data_ptr  = s->data;
+        *data_ptr = (byte) ASN_GENERALIZED_TIME; data_ptr++;
+        *data_ptr = (byte) ASN_GENERALIZED_TIME_SIZE; data_ptr++;
+        XMEMCPY(data_ptr,(byte *)gt_str, ASN_GENERALIZED_TIME_SIZE);
+    }
+
+    return s;
+}
+#endif /* !NO_ASN_TIME && !USER_TIME && !TIME_OVERRIDES && !NO_FILESYSTEM */
+
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_ASN1_INTEGER_cmp(const WOLFSSL_ASN1_INTEGER* a,
                             const WOLFSSL_ASN1_INTEGER* b)
@@ -16482,13 +19382,17 @@
     (void)a;
     (void)b;
+    WOLFSSL_STUB("ASN1_INTEGER_cmp");
     return 0;
 }
-
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 long wolfSSL_ASN1_INTEGER_get(const WOLFSSL_ASN1_INTEGER* i)
 {
     (void)i;
+    WOLFSSL_STUB("ASN1_INTEGER_get");
     return 0;
 }
+#endif
 
 
@@ -16507,16 +19411,47 @@
 
 
+/* Gets an index to store SSL structure at.
+ *
+ * Returns positive index on success and negative values on failure
+ */
 int wolfSSL_get_ex_data_X509_STORE_CTX_idx(void)
 {
     WOLFSSL_ENTER("wolfSSL_get_ex_data_X509_STORE_CTX_idx");
+
+    /* store SSL at index 0 */
     return 0;
 }
 
 
+/* Set an error stat in the X509 STORE CTX
+ *
+ */
+void wolfSSL_X509_STORE_CTX_set_error(WOLFSSL_X509_STORE_CTX* ctx, int er)
+{
+    WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_set_error");
+
+    if (ctx != NULL) {
+        ctx->error = er;
+    }
+}
+
+
+/* Sets a function callback that will send information about the state of all
+ * WOLFSSL objects that have been created by the WOLFSSL_CTX structure passed
+ * in.
+ *
+ * ctx WOLFSSL_CTX structre to set callback function in
+ * f   callback function to use
+ */
 void wolfSSL_CTX_set_info_callback(WOLFSSL_CTX* ctx,
        void (*f)(const WOLFSSL* ssl, int type, int val))
 {
-    (void)ctx;
-    (void)f;
+    WOLFSSL_ENTER("wolfSSL_CTX_set_info_callback");
+    if (ctx == NULL) {
+        WOLFSSL_MSG("Bad function argument");
+    }
+    else {
+        ctx->CBIS = f;
+    }
 }
 
@@ -16526,45 +19461,680 @@
     WOLFSSL_ENTER("wolfSSL_ERR_peek_error");
 
-#ifdef OPENSSL_EXTRA
     return wolfSSL_ERR_peek_error_line_data(NULL, NULL, NULL, NULL);
-#else
-    return 0;
-#endif
-}
-
-
+}
+
+
+/* This function is to find global error values that are the same through out
+ * all library version. With wolfSSL having only one set of error codes the
+ * return value is pretty straight forward. The only thing needed is all wolfSSL
+ * error values are typically negative.
+ *
+ * Returns the error reason
+ */
 int wolfSSL_ERR_GET_REASON(unsigned long err)
 {
-#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+    int ret = (int)err;
+
+    WOLFSSL_ENTER("wolfSSL_ERR_GET_REASON");
+
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
     /* Nginx looks for this error to know to stop parsing certificates. */
     if (err == ((ERR_LIB_PEM << 24) | PEM_R_NO_START_LINE))
         return PEM_R_NO_START_LINE;
 #endif
-    (void)err;
-    return 0;
-}
-
-
-char* wolfSSL_alert_type_string_long(int alertID)
-{
-    (void)alertID;
-    return 0;
-}
-
-
-char* wolfSSL_alert_desc_string_long(int alertID)
-{
-    (void)alertID;
-    return 0;
-}
-
-
-char* wolfSSL_state_string_long(const WOLFSSL* ssl)
-{
-    (void)ssl;
-    return 0;
-}
-
-
+
+    /* check if error value is in range of wolfSSL errors */
+    ret = 0 - ret; /* setting as negative value */
+    /* wolfCrypt range is less than MAX (-100)
+       wolfSSL range is MIN (-300) and lower */
+    if (ret < MAX_CODE_E) {
+        return ret;
+    }
+    else {
+        WOLFSSL_MSG("Not in range of typical error values");
+        ret = (int)err;
+    }
+
+    return ret;
+}
+
+
+/* returns a string that describes the alert
+ *
+ * alertID the alert value to look up
+ */
+const char* wolfSSL_alert_type_string_long(int alertID)
+{
+    WOLFSSL_ENTER("wolfSSL_aalert_type_string_long");
+
+    switch (alertID) {
+        case close_notify:
+            {
+                static const char close_notify_str[] =
+                    "close_notify";
+                return close_notify_str;
+            }
+
+        case unexpected_message:
+            {
+                static const char unexpected_message_str[] =
+                    "unexpected_message";
+                return unexpected_message_str;
+            }
+
+        case bad_record_mac:
+            {
+                static const char bad_record_mac_str[] =
+                    "bad_record_mac";
+                return bad_record_mac_str;
+            }
+
+        case record_overflow:
+            {
+                static const char record_overflow_str[] =
+                    "record_overflow";
+                return record_overflow_str;
+            }
+
+        case decompression_failure:
+            {
+                static const char decompression_failure_str[] =
+                    "decompression_failure";
+                return decompression_failure_str;
+            }
+
+        case handshake_failure:
+            {
+                static const char handshake_failure_str[] =
+                    "handshake_failure";
+                return handshake_failure_str;
+            }
+
+        case no_certificate:
+            {
+                static const char no_certificate_str[] =
+                    "no_certificate";
+                return no_certificate_str;
+            }
+
+        case bad_certificate:
+            {
+                static const char bad_certificate_str[] =
+                    "bad_certificate";
+                return bad_certificate_str;
+            }
+
+        case unsupported_certificate:
+            {
+                static const char unsupported_certificate_str[] =
+                    "unsupported_certificate";
+                return unsupported_certificate_str;
+            }
+
+        case certificate_revoked:
+            {
+                static const char certificate_revoked_str[] =
+                    "certificate_revoked";
+                return certificate_revoked_str;
+            }
+
+        case certificate_expired:
+            {
+                static const char certificate_expired_str[] =
+                    "certificate_expired";
+                return certificate_expired_str;
+            }
+
+        case certificate_unknown:
+            {
+                static const char certificate_unknown_str[] =
+                    "certificate_unknown";
+                return certificate_unknown_str;
+            }
+
+        case illegal_parameter:
+            {
+                static const char illegal_parameter_str[] =
+                    "illegal_parameter";
+                return illegal_parameter_str;
+            }
+
+        case decode_error:
+            {
+                static const char decode_error_str[] =
+                    "decode_error";
+                return decode_error_str;
+            }
+
+        case decrypt_error:
+            {
+                static const char decrypt_error_str[] =
+                    "decrypt_error";
+                return decrypt_error_str;
+            }
+
+    #ifdef WOLFSSL_MYSQL_COMPATIBLE
+    /* catch name conflict for enum protocol with MYSQL build */
+        case wc_protocol_version:
+            {
+                static const char wc_protocol_version_str[] =
+                    "wc_protocol_version";
+                return wc_protocol_version_str;
+            }
+
+    #else
+        case protocol_version:
+            {
+                static const char protocol_version_str[] =
+                    "protocol_version";
+                return protocol_version_str;
+            }
+
+    #endif
+        case no_renegotiation:
+            {
+                static const char no_renegotiation_str[] =
+                    "no_renegotiation";
+                return no_renegotiation_str;
+            }
+
+        case unrecognized_name:
+            {
+                static const char unrecognized_name_str[] =
+                    "unrecognized_name";
+                return unrecognized_name_str;
+            }
+
+        case bad_certificate_status_response:
+            {
+                static const char bad_certificate_status_response_str[] =
+                    "bad_certificate_status_response";
+                return bad_certificate_status_response_str;
+            }
+
+        case no_application_protocol:
+            {
+                static const char no_application_protocol_str[] =
+                    "no_application_protocol";
+                return no_application_protocol_str;
+            }
+
+        default:
+            WOLFSSL_MSG("Unknown Alert");
+            return NULL;
+    }
+}
+
+
+const char* wolfSSL_alert_desc_string_long(int alertID)
+{
+    WOLFSSL_ENTER("wolfSSL_alert_desc_string_long");
+    return wolfSSL_alert_type_string_long(alertID);
+}
+
+
+/* Gets the current state of the WOLFSSL structure
+ *
+ * ssl WOLFSSL structure to get state of
+ *
+ * Returns a human readable string of the WOLFSSL structure state
+ */
+const char* wolfSSL_state_string_long(const WOLFSSL* ssl)
+{
+
+    static const char* OUTPUT_STR[14][6][3] = {
+        {
+            {"SSLv3 Initialization","SSLv3 Initialization","SSLv3 Initialization"},
+            {"TLSv1 Initialization","TLSv2 Initialization","TLSv2 Initialization"},
+            {"TLSv1_1 Initialization","TLSv1_1 Initialization","TLSv1_1 Initialization"},
+            {"TLSv1_2 Initialization","TLSv1_2 Initialization","TLSv1_2 Initialization"},
+            {"DTLSv1 Initialization","DTLSv1 Initialization","DTLSv1 Initialization"},
+            {"DTLSv1_2 Initialization","DTLSv1_2 Initialization","DTLSv1_2 Initialization"},
+        },
+        {
+            {"SSLv3 read Server Hello Verify Request",
+             "SSLv3 write Server Hello Verify Request",
+             "SSLv3 Server Hello Verify Request"},
+            {"TLSv1 read Server Hello Verify Request",
+             "TLSv1 write Server Hello Verify Request",
+             "TLSv1 Server Hello Verify Request"},
+            {"TLSv1_1 read Server Hello Verify Request",
+            "TLSv1_1 write Server Hello Verify Request",
+             "TLSv1_1 Server Hello Verify Request"},
+            {"TLSv1_2 read Server Hello Verify Request",
+            "TLSv1_2 write Server Hello Verify Request",
+             "TLSv1_2 Server Hello Verify Request"},
+            {"DTLSv1 read Server Hello Verify Request",
+             "DTLSv1 write Server Hello Verify Request",
+             "DTLSv1 Server Hello Verify Request"},
+            {"DTLSv1_2 read Server Hello Verify Request",
+             "DTLSv1_2 write Server Hello Verify Request",
+             "DTLSv1_2 Server Hello Verify Request"},
+        },
+        {
+            {"SSLv3 read Server Hello",
+             "SSLv3 write Server Hello",
+             "SSLv3 Server Hello"},
+            {"TLSv1 read Server Hello",
+             "TLSv1 write Server Hello",
+             "TLSv1 Server Hello"},
+            {"TLSv1_1 read Server Hello",
+            "TLSv1_1 write Server Hello",
+             "TLSv1_1 Server Hello"},
+            {"TLSv1_2 read Server Hello",
+            "TLSv1_2 write Server Hello",
+             "TLSv1_2 Server Hello"},
+            {"DTLSv1 read Server Hello",
+            "DTLSv1 write Server Hello",
+             "DTLSv1 Server Hello"},
+            {"DTLSv1_2 read Server Hello"
+             "DTLSv1_2 write Server Hello",
+             "DTLSv1_2 Server Hello",
+            },
+        },
+        {
+            {"SSLv3 read Server Session Ticket",
+             "SSLv3 write Server Session Ticket",
+             "SSLv3 Server Session Ticket"},
+            {"TLSv1 read Server Session Ticket",
+             "TLSv1 write Server Session Ticket",
+             "TLSv1 Server Session Ticket"},
+            {"TLSv1_1 read Server Session Ticket",
+             "TLSv1_1 write Server Session Ticket",
+             "TLSv1_1 Server Session Ticket"},
+            {"TLSv1_2 read Server Session Ticket",
+             "TLSv1_2 write Server Session Ticket",
+             "TLSv1_2 Server Session Ticket"},
+            {"DTLSv1 read Server Session Ticket",
+             "DTLSv1 write Server Session Ticket",
+             "DTLSv1 Server Session Ticket"},
+            {"DTLSv1_2 read Server Session Ticket",
+             "DTLSv1_2 write Server Session Ticket",
+             "DTLSv1_2 Server Session Ticket"},
+        },
+        {
+            {"SSLv3 read Server Cert",
+             "SSLv3 write Server Cert",
+             "SSLv3 Server Cert"},
+            {"TLSv1 read Server Cert",
+             "TLSv1 write Server Cert",
+             "TLSv1 Server Cert"},
+            {"TLSv1_1 read Server Cert",
+             "TLSv1_1 write Server Cert",
+             "TLSv1_1 Server Cert"},
+            {"TLSv1_2 read Server Cert",
+             "TLSv1_2 write Server Cert",
+             "TLSv1_2 Server Cert"},
+            {"DTLSv1 read Server Cert",
+             "DTLSv1 write Server Cert",
+             "DTLSv1 Server Cert"},
+            {"DTLSv1_2 read Server Cert",
+             "DTLSv1_2 write Server Cert",
+             "DTLSv1_2 Server Cert"},
+        },
+        {
+            {"SSLv3 read Server Key Exchange",
+             "SSLv3 write Server Key Exchange",
+             "SSLv3 Server Key Exchange"},
+            {"TLSv1 read Server Key Exchange",
+             "TLSv1 write Server Key Exchange",
+             "TLSv1 Server Key Exchange"},
+            {"TLSv1_1 read Server Key Exchange",
+             "TLSv1_1 write Server Key Exchange",
+             "TLSv1_1 Server Key Exchange"},
+            {"TLSv1_2 read Server Key Exchange",
+             "TLSv1_2 write Server Key Exchange",
+             "TLSv1_2 Server Key Exchange"},
+            {"DTLSv1 read Server Key Exchange",
+             "DTLSv1 write Server Key Exchange",
+             "DTLSv1 Server Key Exchange"},
+            {"DTLSv1_2 read Server Key Exchange",
+             "DTLSv1_2 write Server Key Exchange",
+             "DTLSv1_2 Server Key Exchange"},
+        },
+        {
+            {"SSLv3 read Server Hello Done",
+             "SSLv3 write Server Hello Done",
+             "SSLv3 Server Hello Done"},
+            {"TLSv1 read Server Hello Done",
+             "TLSv1 write Server Hello Done",
+             "TLSv1 Server Hello Done"},
+            {"TLSv1_1 read Server Hello Done",
+             "TLSv1_1 write Server Hello Done",
+             "TLSv1_1 Server Hello Done"},
+            {"TLSv1_2 read Server Hello Done",
+             "TLSv1_2 write Server Hello Done",
+             "TLSv1_2 Server Hello Done"},
+            {"DTLSv1 read Server Hello Done",
+             "DTLSv1 write Server Hello Done",
+             "DTLSv1 Server Hello Done"},
+            {"DTLSv1_2 read Server Hello Done",
+             "DTLSv1_2 write Server Hello Done",
+             "DTLSv1_2 Server Hello Done"},
+        },
+        {
+            {"SSLv3 read Server Change CipherSpec",
+             "SSLv3 write Server Change CipherSpec",
+             "SSLv3 Server Change CipherSpec"},
+            {"TLSv1 read Server Change CipherSpec",
+             "TLSv1 write Server Change CipherSpec",
+             "TLSv1 Server Change CipherSpec"},
+            {"TLSv1_1 read Server Change CipherSpec",
+             "TLSv1_1 write Server Change CipherSpec",
+             "TLSv1_1 Server Change CipherSpec"},
+            {"TLSv1_2 read Server Change CipherSpec",
+             "TLSv1_2 write Server Change CipherSpec",
+             "TLSv1_2 Server Change CipherSpec"},
+            {"DTLSv1 read Server Change CipherSpec",
+             "DTLSv1 write Server Change CipherSpec",
+             "DTLSv1 Server Change CipherSpec"},
+            {"DTLSv1_2 read Server Change CipherSpec",
+             "DTLSv1_2 write Server Change CipherSpec",
+             "DTLSv1_2 Server Change CipherSpec"},
+        },
+        {
+            {"SSLv3 read Server Finished",
+             "SSLv3 write Server Finished",
+             "SSLv3 Server Finished"},
+            {"TLSv1 read Server Finished",
+             "TLSv1 write Server Finished",
+             "TLSv1 Server Finished"},
+            {"TLSv1_1 read Server Finished",
+             "TLSv1_1 write Server Finished",
+             "TLSv1_1 Server Finished"},
+            {"TLSv1_2 read Server Finished",
+             "TLSv1_2 write Server Finished",
+             "TLSv1_2 Server Finished"},
+            {"DTLSv1 read Server Finished",
+             "DTLSv1 write Server Finished",
+             "DTLSv1 Server Finished"},
+            {"DTLSv1_2 read Server Finished",
+             "DTLSv1_2 write Server Finished",
+             "DTLSv1_2 Server Finished"},
+        },
+        {
+            {"SSLv3 read Client Hello",
+             "SSLv3 write Client Hello",
+             "SSLv3 Client Hello"},
+            {"TLSv1 read Client Hello",
+             "TLSv1 write Client Hello",
+             "TLSv1 Client Hello"},
+            {"TLSv1_1 read Client Hello",
+             "TLSv1_1 write Client Hello",
+             "TLSv1_1 Client Hello"},
+            {"TLSv1_2 read Client Hello",
+             "TLSv1_2 write Client Hello",
+             "TLSv1_2 Client Hello"},
+            {"DTLSv1 read Client Hello",
+             "DTLSv1 write Client Hello",
+             "DTLSv1 Client Hello"},
+            {"DTLSv1_2 read Client Hello",
+             "DTLSv1_2 write Client Hello",
+             "DTLSv1_2 Client Hello"},
+        },
+        {
+            {"SSLv3 read Client Key Exchange",
+             "SSLv3 write Client Key Exchange",
+             "SSLv3 Client Key Exchange"},
+            {"TLSv1 read Client Key Exchange",
+             "TLSv1 write Client Key Exchange",
+             "TLSv1 Client Key Exchange"},
+            {"TLSv1_1 read Client Key Exchange",
+             "TLSv1_1 write Client Key Exchange",
+             "TLSv1_1 Client Key Exchange"},
+            {"TLSv1_2 read Client Key Exchange",
+             "TLSv1_2 write Client Key Exchange",
+             "TLSv1_2 Client Key Exchange"},
+            {"DTLSv1 read Client Key Exchange",
+             "DTLSv1 write Client Key Exchange",
+             "DTLSv1 Client Key Exchange"},
+            {"DTLSv1_2 read Client Key Exchange",
+             "DTLSv1_2 write Client Key Exchange",
+             "DTLSv1_2 Client Key Exchange"},
+        },
+        {
+            {"SSLv3 read Client Change CipherSpec",
+             "SSLv3 write Client Change CipherSpec",
+             "SSLv3 Client Change CipherSpec"},
+            {"TLSv1 read Client Change CipherSpec",
+             "TLSv1 write Client Change CipherSpec",
+             "TLSv1 Client Change CipherSpec"},
+            {"TLSv1_1 read Client Change CipherSpec",
+             "TLSv1_1 write Client Change CipherSpec",
+             "TLSv1_1 Client Change CipherSpec"},
+            {"TLSv1_2 read Client Change CipherSpec",
+             "TLSv1_2 write Client Change CipherSpec",
+             "TLSv1_2 Client Change CipherSpec"},
+            {"DTLSv1 read Client Change CipherSpec",
+             "DTLSv1 write Client Change CipherSpec",
+             "DTLSv1 Client Change CipherSpec"},
+            {"DTLSv1_2 read Client Change CipherSpec",
+             "DTLSv1_2 write Client Change CipherSpec",
+             "DTLSv1_2 Client Change CipherSpec"},
+        },
+        {
+            {"SSLv3 read Client Finished",
+             "SSLv3 write Client Finished",
+             "SSLv3 Client Finished"},
+            {"TLSv1 read Client Finished",
+             "TLSv1 write Client Finished",
+             "TLSv1 Client Finished"},
+            {"TLSv1_1 read Client Finished",
+             "TLSv1_1 write Client Finished",
+             "TLSv1_1 Client Finished"},
+            {"TLSv1_2 read Client Finished",
+             "TLSv1_2 write Client Finished",
+             "TLSv1_2 Client Finished"},
+            {"DTLSv1 read Client Finished",
+             "DTLSv1 write Client Finished",
+             "DTLSv1 Client Finished"},
+            {"DTLSv1_2 read Client Finished",
+             "DTLSv1_2 write Client Finished",
+             "DTLSv1_2 Client Finished"},
+        },
+        {
+            {"SSLv3 Handshake Done",
+             "SSLv3 Handshake Done",
+             "SSLv3 Handshake Done"},
+            {"TLSv1 Handshake Done",
+             "TLSv1 Handshake Done",
+             "TLSv1 Handshake Done"},
+            {"TLSv1_1 Handshake Done",
+             "TLSv1_1 Handshake Done",
+             "TLSv1_1 Handshake Done"},
+            {"TLSv1_2 Handshake Done",
+             "TLSv1_2 Handshake Done",
+             "TLSv1_2 Handshake Done"},
+            {"DTLSv1 Handshake Done",
+             "DTLSv1 Handshake Done",
+             "DTLSv1 Handshake Done"},
+            {"DTLSv1_2 Handshake Done"
+             "DTLSv1_2 Handshake Done"
+             "DTLSv1_2 Handshake Done"}
+        }
+    };
+    enum ProtocolVer {
+        SSL_V3 = 0,
+        TLS_V1,
+        TLS_V1_1,
+        TLS_V1_2,
+        DTLS_V1,
+        DTLS_V1_2,
+        UNKNOWN = 100
+    };
+
+    enum IOMode {
+        SS_READ = 0,
+        SS_WRITE,
+        SS_NEITHER
+    };
+
+    enum SslState {
+        ss_null_state = 0,
+        ss_server_helloverify,
+        ss_server_hello,
+        ss_sessionticket,
+        ss_server_cert,
+        ss_server_keyexchange,
+        ss_server_hellodone,
+        ss_server_changecipherspec,
+        ss_server_finished,
+        ss_client_hello,
+        ss_client_keyexchange,
+        ss_client_changecipherspec,
+        ss_client_finished,
+        ss_handshake_done
+    };
+
+    int protocol = 0;
+    int cbmode = 0;
+    int state = 0;
+
+    WOLFSSL_ENTER("wolfSSL_state_string_long");
+    if (ssl == NULL) {
+        WOLFSSL_MSG("Null argument passed in");
+        return NULL;
+    }
+
+    /* Get state of callback */
+    if (ssl->cbmode == SSL_CB_MODE_WRITE){
+        cbmode =  SS_WRITE;
+    } else if (ssl->cbmode == SSL_CB_MODE_READ){
+        cbmode =  SS_READ;
+    } else {
+        cbmode =  SS_NEITHER;
+    }
+
+    /* Get protocol version */
+    switch (ssl->version.major){
+        case SSLv3_MAJOR:
+            switch (ssl->version.minor){
+                case TLSv1_MINOR:
+                    protocol = TLS_V1;
+                    break;
+                case TLSv1_1_MINOR:
+                    protocol = TLS_V1_1;
+                    break;
+                case TLSv1_2_MINOR:
+                    protocol = TLS_V1_2;
+                    break;
+                case SSLv3_MINOR:
+                    protocol = SSL_V3;
+                    break;
+                default:
+                    protocol = UNKNOWN;
+            }
+            break;
+        case DTLS_MAJOR:
+            switch (ssl->version.minor){
+        case DTLS_MINOR:
+            protocol = DTLS_V1;
+            break;
+        case DTLSv1_2_MINOR:
+            protocol = DTLS_V1_2;
+            break;
+        default:
+            protocol = UNKNOWN;
+    }
+    break;
+    default:
+        protocol = UNKNOWN;
+    }
+
+    /* accept process */
+    if (ssl->cbmode == SSL_CB_MODE_READ){
+        state = ssl->cbtype;
+        switch (state) {
+            case hello_verify_request:
+                state = ss_server_helloverify;
+                break;
+            case session_ticket:
+                state = ss_sessionticket;
+                break;
+            case server_hello:
+                state = ss_server_hello;
+                break;
+            case server_hello_done:
+                state = ss_server_hellodone;
+                break;
+            case certificate:
+                state = ss_server_cert;
+                break;
+            case server_key_exchange:
+                state = ss_server_keyexchange;
+                break;
+            case client_hello:
+                state = ss_client_hello;
+                break;
+            case client_key_exchange:
+                state = ss_client_keyexchange;
+                break;
+            case finished:
+                if (ssl->options.side == WOLFSSL_SERVER_END)
+                    state = ss_client_finished;
+                else if (ssl->options.side == WOLFSSL_CLIENT_END)
+                    state = ss_server_finished;
+                break;
+            default:
+                WOLFSSL_MSG("Unknown State");
+                state = ss_null_state;
+        }
+    } else {
+        /* Send process */
+        if (ssl->options.side == WOLFSSL_SERVER_END)
+            state = ssl->options.serverState;
+        else
+            state = ssl->options.clientState;
+
+        switch(state){
+            case SERVER_HELLOVERIFYREQUEST_COMPLETE:
+                state = ss_server_helloverify;
+                break;
+            case SERVER_HELLO_COMPLETE:
+                state = ss_server_hello;
+                break;
+            case SERVER_CERT_COMPLETE:
+                state = ss_server_cert;
+                break;
+            case SERVER_KEYEXCHANGE_COMPLETE:
+                state = ss_server_keyexchange;
+                break;
+            case SERVER_HELLODONE_COMPLETE:
+                state = ss_server_hellodone;
+                break;
+            case SERVER_CHANGECIPHERSPEC_COMPLETE:
+                state = ss_server_changecipherspec;
+                break;
+            case SERVER_FINISHED_COMPLETE:
+                state = ss_server_finished;
+                break;
+            case CLIENT_HELLO_COMPLETE:
+                state = ss_client_hello;
+                break;
+            case CLIENT_KEYEXCHANGE_COMPLETE:
+                state = ss_client_keyexchange;
+                break;
+            case CLIENT_CHANGECIPHERSPEC_COMPLETE:
+                state = ss_client_changecipherspec;
+                break;
+            case CLIENT_FINISHED_COMPLETE:
+                state = ss_client_finished;
+                break;
+            case HANDSHAKE_DONE:
+                state = ss_handshake_done;
+                break;
+            default:
+                WOLFSSL_MSG("Unknown State");
+                state = ss_null_state;
+        }
+    }
+
+    if (protocol == UNKNOWN)
+        return NULL;
+    else
+        return OUTPUT_STR[state][protocol][cbmode];
+}
+
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_PEM_def_callback(char* name, int num, int w, void* key)
 {
@@ -16573,21 +20143,15 @@
     (void)w;
     (void)key;
+    WOLFSSL_STUB("PEM_def_callback");
     return 0;
 }
-
-
-unsigned long wolfSSL_set_options(WOLFSSL* ssl, unsigned long op)
-{
-    word16 haveRSA = 1;
-    word16 havePSK = 0;
-    int    keySz   = 0;
-
-    WOLFSSL_ENTER("wolfSSL_set_options");
-
-    if (ssl == NULL) {
-        return 0;
-    }
-
-    /* if SSL_OP_ALL then turn all bug workarounds one */
+#endif
+
+#endif
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+static long wolf_set_options(long old_op, long op)
+{
+    /* if SSL_OP_ALL then turn all bug workarounds on */
     if ((op & SSL_OP_ALL) == SSL_OP_ALL) {
         WOLFSSL_MSG("\tSSL_OP_ALL");
@@ -16606,47 +20170,36 @@
     }
 
-    ssl->options.mask |= op;
-
     /* by default cookie exchange is on with DTLS */
-    if ((ssl->options.mask & SSL_OP_COOKIE_EXCHANGE) == SSL_OP_COOKIE_EXCHANGE) {
+    if ((op & SSL_OP_COOKIE_EXCHANGE) == SSL_OP_COOKIE_EXCHANGE) {
         WOLFSSL_MSG("\tSSL_OP_COOKIE_EXCHANGE : on by default");
     }
 
-    if ((ssl->options.mask & WOLFSSL_OP_NO_SSLv2) == WOLFSSL_OP_NO_SSLv2) {
+    if ((op & WOLFSSL_OP_NO_SSLv2) == WOLFSSL_OP_NO_SSLv2) {
         WOLFSSL_MSG("\tWOLFSSL_OP_NO_SSLv2 : wolfSSL does not support SSLv2");
     }
 
-    if ((ssl->options.mask & SSL_OP_NO_TLSv1_3) == SSL_OP_NO_TLSv1_3) {
+    if ((op & SSL_OP_NO_TLSv1_3) == SSL_OP_NO_TLSv1_3) {
         WOLFSSL_MSG("\tSSL_OP_NO_TLSv1_3");
-        if (ssl->version.minor == TLSv1_3_MINOR)
-            ssl->version.minor = TLSv1_2_MINOR;
-    }
-
-    if ((ssl->options.mask & SSL_OP_NO_TLSv1_2) == SSL_OP_NO_TLSv1_2) {
+    }
+
+    if ((op & SSL_OP_NO_TLSv1_2) == SSL_OP_NO_TLSv1_2) {
         WOLFSSL_MSG("\tSSL_OP_NO_TLSv1_2");
-        if (ssl->version.minor == TLSv1_2_MINOR)
-            ssl->version.minor = TLSv1_1_MINOR;
-    }
-
-    if ((ssl->options.mask & SSL_OP_NO_TLSv1_1) == SSL_OP_NO_TLSv1_1) {
+    }
+
+    if ((op & SSL_OP_NO_TLSv1_1) == SSL_OP_NO_TLSv1_1) {
         WOLFSSL_MSG("\tSSL_OP_NO_TLSv1_1");
-        if (ssl->version.minor == TLSv1_1_MINOR)
-            ssl->version.minor = TLSv1_MINOR;
-    }
-
-    if ((ssl->options.mask & SSL_OP_NO_TLSv1) == SSL_OP_NO_TLSv1) {
+    }
+
+    if ((op & SSL_OP_NO_TLSv1) == SSL_OP_NO_TLSv1) {
         WOLFSSL_MSG("\tSSL_OP_NO_TLSv1");
-        if (ssl->version.minor == TLSv1_MINOR)
-            ssl->version.minor = SSLv3_MINOR;
-    }
-
-    if ((ssl->options.mask & SSL_OP_NO_SSLv3) == SSL_OP_NO_SSLv3) {
+    }
+
+    if ((op & SSL_OP_NO_SSLv3) == SSL_OP_NO_SSLv3) {
         WOLFSSL_MSG("\tSSL_OP_NO_SSLv3");
     }
 
-    if ((ssl->options.mask & SSL_OP_NO_COMPRESSION) == SSL_OP_NO_COMPRESSION) {
+    if ((op & SSL_OP_NO_COMPRESSION) == SSL_OP_NO_COMPRESSION) {
     #ifdef HAVE_LIBZ
         WOLFSSL_MSG("SSL_OP_NO_COMPRESSION");
-        ssl->options.usingCompression = 0;
     #else
         WOLFSSL_MSG("SSL_OP_NO_COMPRESSION: compression not compiled in");
@@ -16654,14 +20207,60 @@
     }
 
+    return old_op | op;
+}
+#endif
+
+#ifdef OPENSSL_EXTRA
+long wolfSSL_set_options(WOLFSSL* ssl, long op)
+{
+    word16 haveRSA = 1;
+    word16 havePSK = 0;
+    int    keySz   = 0;
+
+    WOLFSSL_ENTER("wolfSSL_set_options");
+
+    if (ssl == NULL) {
+        return 0;
+    }
+
+    ssl->options.mask = wolf_set_options(ssl->options.mask, op);
+
+    if ((ssl->options.mask & SSL_OP_NO_TLSv1_3) == SSL_OP_NO_TLSv1_3) {
+        if (ssl->version.minor == TLSv1_3_MINOR)
+            ssl->version.minor = TLSv1_2_MINOR;
+    }
+
+    if ((ssl->options.mask & SSL_OP_NO_TLSv1_2) == SSL_OP_NO_TLSv1_2) {
+        if (ssl->version.minor == TLSv1_2_MINOR)
+            ssl->version.minor = TLSv1_1_MINOR;
+    }
+
+    if ((ssl->options.mask & SSL_OP_NO_TLSv1_1) == SSL_OP_NO_TLSv1_1) {
+        if (ssl->version.minor == TLSv1_1_MINOR)
+            ssl->version.minor = TLSv1_MINOR;
+    }
+
+    if ((ssl->options.mask & SSL_OP_NO_TLSv1) == SSL_OP_NO_TLSv1) {
+        if (ssl->version.minor == TLSv1_MINOR)
+            ssl->version.minor = SSLv3_MINOR;
+    }
+
+    if ((ssl->options.mask & SSL_OP_NO_COMPRESSION) == SSL_OP_NO_COMPRESSION) {
+    #ifdef HAVE_LIBZ
+        ssl->options.usingCompression = 0;
+    #endif
+    }
+
     /* in the case of a version change the cipher suites should be reset */
-    #ifndef NO_PSK
-        havePSK = ssl->options.havePSK;
-    #endif
-    #ifdef NO_RSA
-        haveRSA = 0;
-    #endif
-    #ifndef NO_CERTS
-        keySz = ssl->buffers.keySz;
-    #endif
+#ifndef NO_PSK
+    havePSK = ssl->options.havePSK;
+#endif
+#ifdef NO_RSA
+    haveRSA = 0;
+#endif
+#ifndef NO_CERTS
+    keySz = ssl->buffers.keySz;
+#endif
+
     InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK,
                        ssl->options.haveDH, ssl->options.haveNTRU,
@@ -16673,25 +20272,40 @@
 
 
-unsigned long wolfSSL_get_options(const WOLFSSL* ssl)
+long wolfSSL_get_options(const WOLFSSL* ssl)
 {
     WOLFSSL_ENTER("wolfSSL_get_options");
-
+    if(ssl == NULL)
+        return WOLFSSL_FAILURE;
     return ssl->options.mask;
 }
 
+long wolfSSL_clear_options(WOLFSSL* ssl, long opt)
+{
+    WOLFSSL_ENTER("SSL_clear_options");
+    if(ssl == NULL)
+        return WOLFSSL_FAILURE;
+    ssl->options.mask &= ~opt;
+    return ssl->options.mask;
+}
+
 /*** TBD ***/
+#ifndef NO_WOLFSSL_STUB
 WOLFSSL_API long wolfSSL_clear_num_renegotiations(WOLFSSL *s)
 {
     (void)s;
+    WOLFSSL_STUB("SSL_clear_num_renegotiations");
     return 0;
 }
+#endif
 
 /*** TBD ***/
+#ifndef NO_WOLFSSL_STUB
 WOLFSSL_API long wolfSSL_total_renegotiations(WOLFSSL *s)
 {
     (void)s;
+    WOLFSSL_STUB("SSL_total_renegotiations");
     return 0;
 }
-
+#endif
 
 #ifndef NO_DH
@@ -16750,5 +20364,5 @@
 #endif /* HAVE_PK_CALLBACKS */
 
-#ifdef WOLFSSL_HAPROXY
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY)
 const unsigned char *SSL_SESSION_get0_id_context(const SSL_SESSION *sess, unsigned int *sid_ctx_length)
 {
@@ -16759,23 +20373,38 @@
 
 /*** TBD ***/
+#ifndef NO_WOLFSSL_STUB
 WOLFSSL_API int wolfSSL_sk_SSL_COMP_zero(WOLFSSL_STACK* st)
 {
     (void)st;
     WOLFSSL_STUB("wolfSSL_sk_SSL_COMP_zero");
-    //wolfSSL_set_options(ssl, SSL_OP_NO_COMPRESSION);
+    /* wolfSSL_set_options(ssl, SSL_OP_NO_COMPRESSION); */
     return WOLFSSL_FAILURE;
 }
-
-
-/*** TBD ***/
-WOLFSSL_API long wolfSSL_set_tlsext_status_type(WOLFSSL *s, int type)
-{
-    (void)s;
-    (void)type;
-    WOLFSSL_STUB("wolfSSL_set_tlsext_status_type");
-    return WOLFSSL_FAILURE;
-}
-
-/*** TBD ***/
+#endif
+
+#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
+long wolfSSL_set_tlsext_status_type(WOLFSSL *s, int type)
+{
+    WOLFSSL_ENTER("wolfSSL_set_tlsext_status_type");
+
+    if (s == NULL){
+        return BAD_FUNC_ARG;
+    }
+
+    if (type == TLSEXT_STATUSTYPE_ocsp){
+        int r = 0;
+        r = TLSX_UseCertificateStatusRequest(&s->extensions, type, 0, s,
+                                                             s->heap, s->devId);
+        return (long)r;
+    } else {
+        WOLFSSL_MSG(
+       "SSL_set_tlsext_status_type only supports TLSEXT_STATUSTYPE_ocsp type.");
+        return SSL_FAILURE;
+    }
+
+}
+#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */
+
+#ifndef NO_WOLFSSL_STUB
 WOLFSSL_API long wolfSSL_get_tlsext_status_exts(WOLFSSL *s, void *arg)
 {
@@ -16785,6 +20414,8 @@
     return WOLFSSL_FAILURE;
 }
+#endif
 
 /*** TBD ***/
+#ifndef NO_WOLFSSL_STUB
 WOLFSSL_API long wolfSSL_set_tlsext_status_exts(WOLFSSL *s, void *arg)
 {
@@ -16794,6 +20425,8 @@
     return WOLFSSL_FAILURE;
 }
+#endif
 
 /*** TBD ***/
+#ifndef NO_WOLFSSL_STUB
 WOLFSSL_API long wolfSSL_get_tlsext_status_ids(WOLFSSL *s, void *arg)
 {
@@ -16803,6 +20436,8 @@
     return WOLFSSL_FAILURE;
 }
+#endif
 
 /*** TBD ***/
+#ifndef NO_WOLFSSL_STUB
 WOLFSSL_API long wolfSSL_set_tlsext_status_ids(WOLFSSL *s, void *arg)
 {
@@ -16812,6 +20447,8 @@
     return WOLFSSL_FAILURE;
 }
+#endif
 
 /*** TBD ***/
+#ifndef NO_WOLFSSL_STUB
 WOLFSSL_API int SSL_SESSION_set1_id(WOLFSSL_SESSION *s, const unsigned char *sid, unsigned int sid_len)
 {
@@ -16822,5 +20459,7 @@
     return WOLFSSL_FAILURE;
 }
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 /*** TBD ***/
 WOLFSSL_API int SSL_SESSION_set1_id_context(WOLFSSL_SESSION *s, const unsigned char *sid_ctx, unsigned int sid_ctx_len)
@@ -16832,5 +20471,7 @@
     return WOLFSSL_FAILURE;
 }
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 /*** TBD ***/
 WOLFSSL_API void *X509_get0_tbs_sigalg(const WOLFSSL_X509 *x)
@@ -16840,5 +20481,7 @@
     return NULL;
 }
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 /*** TBD ***/
 WOLFSSL_API void X509_ALGOR_get0(WOLFSSL_ASN1_OBJECT **paobj, int *pptype, const void **ppval, const void *algor)
@@ -16850,5 +20493,7 @@
     WOLFSSL_STUB("X509_ALGOR_get0");
 }
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 /*** TBD ***/
 WOLFSSL_API void *X509_get_X509_PUBKEY(void * x)
@@ -16858,5 +20503,7 @@
     return NULL;
 }
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 /*** TBD ***/
 WOLFSSL_API int X509_PUBKEY_get0_param(WOLFSSL_ASN1_OBJECT **ppkalg, const unsigned char **pk, int *ppklen, void **pa, WOLFSSL_EVP_PKEY *pub)
@@ -16870,5 +20517,7 @@
     return WOLFSSL_FAILURE;
 }
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 /*** TBD ***/
 WOLFSSL_API WOLFSSL_EVP_PKEY *wolfSSL_get_privatekey(const WOLFSSL *ssl)
@@ -16878,22 +20527,7 @@
     return NULL;
 }
-
-/*** TBD ***/
-WOLFSSL_API int EVP_PKEY_bits(WOLFSSL_EVP_PKEY *pkey)
-{
-    (void)pkey;
-    WOLFSSL_STUB("EVP_PKEY_bits");
-    return WOLFSSL_FAILURE;
-}
-
-/*** TBD ***/
-WOLFSSL_API int i2d_X509(WOLFSSL_X509 *x, unsigned char **out)
-{
-    (void)x;
-    (void)out;
-    WOLFSSL_STUB("i2d_X509");
-    return -1;
-}
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 /*** TBD ***/
 WOLFSSL_API int i2t_ASN1_OBJECT(char *buf, int buf_len, WOLFSSL_ASN1_OBJECT *a)
@@ -16905,6 +20539,8 @@
     return -1;
 }
-
-#ifdef WOLFSSL_HAPROXY
+#endif
+
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY)
+#ifndef NO_WOLFSSL_STUB
 /*** TBD ***/
 WOLFSSL_API size_t SSL_get_finished(const WOLFSSL *s, void *buf, size_t count)
@@ -16916,5 +20552,7 @@
     return WOLFSSL_FAILURE;
 }
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 /*** TBD ***/
 WOLFSSL_API size_t SSL_get_peer_finished(const WOLFSSL *s, void *buf, size_t count)
@@ -16926,6 +20564,8 @@
     return WOLFSSL_FAILURE;
 }
+#endif
 #endif /* WOLFSSL_HAPROXY */
 
+#ifndef NO_WOLFSSL_STUB
 /*** TBD ***/
 WOLFSSL_API void SSL_CTX_set_tmp_dh_callback(WOLFSSL_CTX *ctx, WOLFSSL_DH *(*dh) (WOLFSSL *ssl, int is_export, int keylength))
@@ -16935,5 +20575,7 @@
     WOLFSSL_STUB("SSL_CTX_set_tmp_dh_callback");
 }
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 /*** TBD ***/
 WOLFSSL_API WOLF_STACK_OF(SSL_COMP) *SSL_COMP_get_compression_methods(void)
@@ -16942,5 +20584,7 @@
     return NULL;
 }
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 /*** TBD ***/
 WOLFSSL_API int wolfSSL_sk_SSL_CIPHER_num(const void * p)
@@ -16950,19 +20594,10 @@
     return -1;
 }
+#endif
 
 #if !defined(NO_FILESYSTEM)
+#ifndef NO_WOLFSSL_STUB
 /*** TBD ***/
-WOLFSSL_API WOLFSSL_X509 *wolfSSL_PEM_read_X509(FILE *fp, WOLFSSL_X509 **x, pem_password_cb *cb, void *u)
-{
-    (void)fp;
-    (void)x;
-    (void)cb;
-    (void)u;
-    WOLFSSL_STUB("PEM_read_X509");
-    return NULL;
-}
-
-/*** TBD ***/
-WOLFSSL_API WOLFSSL_EVP_PKEY *wolfSSL_PEM_read_PrivateKey(FILE *fp, WOLFSSL_EVP_PKEY **x, pem_password_cb *cb, void *u)
+WOLFSSL_API WOLFSSL_EVP_PKEY *wolfSSL_PEM_read_PrivateKey(XFILE fp, WOLFSSL_EVP_PKEY **x, pem_password_cb *cb, void *u)
 {
     (void)fp;
@@ -16974,5 +20609,7 @@
 }
 #endif
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 /*** TBD ***/
 WOLFSSL_API int X509_STORE_load_locations(WOLFSSL_X509_STORE *ctx, const char *file, const char *dir)
@@ -16984,5 +20621,7 @@
     return WOLFSSL_FAILURE;
 }
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 /*** TBD ***/
 WOLFSSL_API WOLFSSL_CIPHER* wolfSSL_sk_SSL_CIPHER_value(void *ciphers, int idx)
@@ -16993,4 +20632,5 @@
     return NULL;
 }
+#endif
 
 WOLFSSL_API void ERR_load_SSL_strings(void)
@@ -17009,6 +20649,5 @@
 }
 
-WOLFSSL_API long wolfSSL_set_tlsext_status_ocsp_resp(WOLFSSL *s,
-    unsigned char *resp, int len)
+WOLFSSL_API long wolfSSL_set_tlsext_status_ocsp_resp(WOLFSSL *s, unsigned char *resp, int len)
 {
     if (s == NULL)
@@ -17020,5 +20659,5 @@
     return WOLFSSL_SUCCESS;
 }
-#endif
+#endif /* HAVE_OCSP */
 
 long wolfSSL_get_verify_result(const WOLFSSL *ssl)
@@ -17032,84 +20671,136 @@
 
 
+#ifndef NO_WOLFSSL_STUB
+/* shows the number of accepts attempted by CTX in it's lifetime */
 long wolfSSL_CTX_sess_accept(WOLFSSL_CTX* ctx)
 {
+    WOLFSSL_STUB("wolfSSL_CTX_sess_accept");
     (void)ctx;
     return 0;
 }
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
+/* shows the number of connects attempted CTX in it's lifetime */
 long wolfSSL_CTX_sess_connect(WOLFSSL_CTX* ctx)
 {
+    WOLFSSL_STUB("wolfSSL_CTX_sess_connect");
     (void)ctx;
     return 0;
 }
-
-
+#endif
+
+
+#ifndef NO_WOLFSSL_STUB
+/* shows the number of accepts completed by CTX in it's lifetime */
 long wolfSSL_CTX_sess_accept_good(WOLFSSL_CTX* ctx)
 {
+    WOLFSSL_STUB("wolfSSL_CTX_sess_accept_good");
     (void)ctx;
     return 0;
 }
-
-
+#endif
+
+
+#ifndef NO_WOLFSSL_STUB
+/* shows the number of connects completed by CTX in it's lifetime */
 long wolfSSL_CTX_sess_connect_good(WOLFSSL_CTX* ctx)
 {
+    WOLFSSL_STUB("wolfSSL_CTX_sess_connect_good");
     (void)ctx;
     return 0;
 }
-
-
+#endif
+
+
+#ifndef NO_WOLFSSL_STUB
+/* shows the number of renegotiation accepts attempted by CTX */
 long wolfSSL_CTX_sess_accept_renegotiate(WOLFSSL_CTX* ctx)
 {
+    WOLFSSL_STUB("wolfSSL_CTX_sess_accept_renegotiate");
     (void)ctx;
     return 0;
 }
-
-
+#endif
+
+
+#ifndef NO_WOLFSSL_STUB
+/* shows the number of renegotiation accepts attempted by CTX */
 long wolfSSL_CTX_sess_connect_renegotiate(WOLFSSL_CTX* ctx)
 {
+    WOLFSSL_STUB("wolfSSL_CTX_sess_connect_renegotiate");
     (void)ctx;
     return 0;
 }
-
-
+#endif
+
+
+#ifndef NO_WOLFSSL_STUB
 long wolfSSL_CTX_sess_hits(WOLFSSL_CTX* ctx)
 {
+    WOLFSSL_STUB("wolfSSL_CTX_sess_hits");
     (void)ctx;
     return 0;
 }
-
-
+#endif
+
+
+#ifndef NO_WOLFSSL_STUB
 long wolfSSL_CTX_sess_cb_hits(WOLFSSL_CTX* ctx)
 {
+    WOLFSSL_STUB("wolfSSL_CTX_sess_cb_hits");
     (void)ctx;
     return 0;
 }
-
-
+#endif
+
+
+#ifndef NO_WOLFSSL_STUB
 long wolfSSL_CTX_sess_cache_full(WOLFSSL_CTX* ctx)
 {
+    WOLFSSL_STUB("wolfSSL_CTX_sess_cache_full");
     (void)ctx;
     return 0;
 }
-
-
+#endif
+
+
+#ifndef NO_WOLFSSL_STUB
 long wolfSSL_CTX_sess_misses(WOLFSSL_CTX* ctx)
 {
+    WOLFSSL_STUB("wolfSSL_CTX_sess_misses");
     (void)ctx;
     return 0;
 }
-
-
+#endif
+
+
+#ifndef NO_WOLFSSL_STUB
 long wolfSSL_CTX_sess_timeouts(WOLFSSL_CTX* ctx)
 {
+    WOLFSSL_STUB("wolfSSL_CTX_sess_timeouts");
     (void)ctx;
     return 0;
 }
-
-
+#endif
+
+
+/* Return the total number of sessions */
 long wolfSSL_CTX_sess_number(WOLFSSL_CTX* ctx)
 {
+    word32 total = 0;
+
+    WOLFSSL_ENTER("wolfSSL_CTX_sess_number");
     (void)ctx;
-    return 0;
+
+#ifdef WOLFSSL_SESSION_STATS
+    if (wolfSSL_get_session_stats(NULL, &total, NULL, NULL) != SSL_SUCCESS) {
+        WOLFSSL_MSG("Error getting session stats");
+    }
+#else
+    WOLFSSL_MSG("Please use macro WOLFSSL_SESSION_STATS for session stats");
+#endif
+
+    return (long)total;
 }
 
@@ -17215,9 +20906,34 @@
 
 
-/*** TBC ***/
+/* Get the session cache mode for CTX
+ *
+ * ctx  WOLFSSL_CTX struct to get cache mode from
+ *
+ * Returns a bit mask that has the session cache mode */
 WOLFSSL_API long wolfSSL_CTX_get_session_cache_mode(WOLFSSL_CTX* ctx)
 {
-    (void)ctx;
-    return 0;
+    long m = 0;
+
+    WOLFSSL_ENTER("SSL_CTX_set_session_cache_mode");
+
+    if (ctx == NULL) {
+        return m;
+    }
+
+    if (ctx->sessionCacheOff != 1) {
+        m |= SSL_SESS_CACHE_SERVER;
+    }
+
+    if (ctx->sessionCacheFlushOff == 1) {
+        m |= SSL_SESS_CACHE_NO_AUTO_CLEAR;
+    }
+
+#ifdef HAVE_EXT_CACHE
+    if (ctx->internalCacheOff == 1) {
+        m |= SSL_SESS_CACHE_NO_INTERNAL_STORE;
+    }
+#endif
+
+    return m;
 }
 
@@ -17294,5 +21010,5 @@
     }
     else {
-        word32 i, mask, mask2;
+        word32 i;
         word32 sz = sizeof(WOLFSSL_DES_key_schedule);
 
@@ -17305,5 +21021,5 @@
         /* check odd parity */
         for (i = 0; i < sz; i++) {
-            unsigned char c = *((unsigned char*)key + i);
+            unsigned char c = *((unsigned char*)myDes + i);
             if (((c & 0x01) ^
                 ((c >> 1) & 0x01) ^
@@ -17319,68 +21035,9 @@
         }
 
-        /* check is not weak. Weak key list from Nist
-           "Recommendation for the Triple
-           Data Encryption Algorithm
-           (TDEA) Block Cipher" */
-        mask = 0x01010101; mask2 = 0x01010101;
-        if (DES_check(mask, mask2, *key)) {
+        if (wolfSSL_DES_is_weak_key(myDes) == 1) {
             WOLFSSL_MSG("Weak key found");
             return -2;
         }
 
-        mask = 0xFEFEFEFE; mask2 = 0xFEFEFEFE;
-        if (DES_check(mask, mask2, *key)) {
-            WOLFSSL_MSG("Weak key found");
-            return -2;
-        }
-
-        mask = 0xE0E0E0E0; mask2 = 0xF1F1F1F1;
-        if (DES_check(mask, mask2, *key)) {
-            WOLFSSL_MSG("Weak key found");
-            return -2;
-        }
-
-        mask = 0x1F1F1F1F; mask2 = 0x0E0E0E0E;
-        if (DES_check(mask, mask2, *key)) {
-            WOLFSSL_MSG("Weak key found");
-            return -2;
-        }
-
-        /* semi-weak *key check (list from same Nist paper) */
-        mask  = 0x011F011F; mask2 = 0x010E010E;
-        if (DES_check(mask, mask2, *key) ||
-           DES_check(ByteReverseWord32(mask), ByteReverseWord32(mask2), *key)) {
-            WOLFSSL_MSG("Weak key found");
-            return -2;
-        }
-
-        mask  = 0x01E001E0; mask2 = 0x01F101F1;
-        if (DES_check(mask, mask2, *key) ||
-           DES_check(ByteReverseWord32(mask), ByteReverseWord32(mask2), *key)) {
-            WOLFSSL_MSG("Weak key found");
-            return -2;
-        }
-
-        mask  = 0x01FE01FE; mask2 = 0x01FE01FE;
-        if (DES_check(mask, mask2, *key) ||
-           DES_check(ByteReverseWord32(mask), ByteReverseWord32(mask2), *key)) {
-            WOLFSSL_MSG("Weak key found");
-            return -2;
-        }
-
-        mask  = 0x1FE01FE0; mask2 = 0x0EF10EF1;
-        if (DES_check(mask, mask2, *key) ||
-           DES_check(ByteReverseWord32(mask), ByteReverseWord32(mask2), *key)) {
-            WOLFSSL_MSG("Weak key found");
-            return -2;
-        }
-
-        mask  = 0x1FFE1FFE; mask2 = 0x0EFE0EFE;
-        if (DES_check(mask, mask2, *key) ||
-           DES_check(ByteReverseWord32(mask), ByteReverseWord32(mask2), *key)) {
-            WOLFSSL_MSG("Weak key found");
-            return -2;
-        }
-
         /* passed tests, now copy over key */
         XMEMCPY(key, myDes, sizeof(WOLFSSL_const_DES_cblock));
@@ -17391,4 +21048,84 @@
 
 
+/* check is not weak. Weak key list from Nist "Recommendation for the Triple
+ * Data Encryption Algorithm (TDEA) Block Cipher"
+ *
+ * returns 1 if is weak 0 if not
+ */
+int wolfSSL_DES_is_weak_key(WOLFSSL_const_DES_cblock* key)
+{
+    word32 mask, mask2;
+
+    WOLFSSL_ENTER("wolfSSL_DES_is_weak_key");
+
+    if (key == NULL) {
+        WOLFSSL_MSG("NULL key passed in");
+        return 1;
+    }
+
+    mask = 0x01010101; mask2 = 0x01010101;
+    if (DES_check(mask, mask2, *key)) {
+        WOLFSSL_MSG("Weak key found");
+        return 1;
+    }
+
+    mask = 0xFEFEFEFE; mask2 = 0xFEFEFEFE;
+    if (DES_check(mask, mask2, *key)) {
+        WOLFSSL_MSG("Weak key found");
+        return 1;
+    }
+
+    mask = 0xE0E0E0E0; mask2 = 0xF1F1F1F1;
+    if (DES_check(mask, mask2, *key)) {
+        WOLFSSL_MSG("Weak key found");
+        return 1;
+    }
+
+    mask = 0x1F1F1F1F; mask2 = 0x0E0E0E0E;
+    if (DES_check(mask, mask2, *key)) {
+        WOLFSSL_MSG("Weak key found");
+        return 1;
+    }
+
+    /* semi-weak *key check (list from same Nist paper) */
+    mask  = 0x011F011F; mask2 = 0x010E010E;
+    if (DES_check(mask, mask2, *key) ||
+       DES_check(ByteReverseWord32(mask), ByteReverseWord32(mask2), *key)) {
+        WOLFSSL_MSG("Weak key found");
+        return 1;
+    }
+
+    mask  = 0x01E001E0; mask2 = 0x01F101F1;
+    if (DES_check(mask, mask2, *key) ||
+       DES_check(ByteReverseWord32(mask), ByteReverseWord32(mask2), *key)) {
+        WOLFSSL_MSG("Weak key found");
+        return 1;
+    }
+
+    mask  = 0x01FE01FE; mask2 = 0x01FE01FE;
+    if (DES_check(mask, mask2, *key) ||
+       DES_check(ByteReverseWord32(mask), ByteReverseWord32(mask2), *key)) {
+        WOLFSSL_MSG("Weak key found");
+        return 1;
+    }
+
+    mask  = 0x1FE01FE0; mask2 = 0x0EF10EF1;
+    if (DES_check(mask, mask2, *key) ||
+       DES_check(ByteReverseWord32(mask), ByteReverseWord32(mask2), *key)) {
+        WOLFSSL_MSG("Weak key found");
+        return 1;
+    }
+
+    mask  = 0x1FFE1FFE; mask2 = 0x0EFE0EFE;
+    if (DES_check(mask, mask2, *key) ||
+       DES_check(ByteReverseWord32(mask), ByteReverseWord32(mask2), *key)) {
+        WOLFSSL_MSG("Weak key found");
+        return 1;
+    }
+
+    return 0;
+}
+
+
 void wolfSSL_DES_set_key_unchecked(WOLFSSL_const_DES_cblock* myDes,
                                                WOLFSSL_DES_key_schedule* key)
@@ -17400,8 +21137,26 @@
 
 
+/* Sets the parity of the DES key for use */
 void wolfSSL_DES_set_odd_parity(WOLFSSL_DES_cblock* myDes)
 {
-    (void)myDes;
-    WOLFSSL_STUB("wolfSSL_DES_set_odd_parity");
+    word32 i;
+    word32 sz = sizeof(WOLFSSL_DES_cblock);
+
+    WOLFSSL_ENTER("wolfSSL_DES_set_odd_parity");
+
+    for (i = 0; i < sz; i++) {
+        unsigned char c = *((unsigned char*)myDes + i);
+        if ((
+            ((c >> 1) & 0x01) ^
+            ((c >> 2) & 0x01) ^
+            ((c >> 3) & 0x01) ^
+            ((c >> 4) & 0x01) ^
+            ((c >> 5) & 0x01) ^
+            ((c >> 6) & 0x01) ^
+            ((c >> 7) & 0x01)) != 1) {
+            WOLFSSL_MSG("Setting odd parity bit");
+            *((unsigned char*)myDes + i) = *((unsigned char*)myDes + i) | 0x01;
+        }
+    }
 }
 
@@ -17428,7 +21183,14 @@
             return;
         }
-        if (wc_Des_EcbEncrypt(&myDes, (byte*) desb,
-                              (const byte*)desa, sizeof(WOLFSSL_DES_cblock)) != 0){
-            WOLFSSL_MSG("wc_Des_EcbEncrypt return error.");
+        if (enc){
+            if (wc_Des_EcbEncrypt(&myDes, (byte*) desb, (const byte*) desa,
+                        sizeof(WOLFSSL_DES_cblock)) != 0){
+                WOLFSSL_MSG("wc_Des_EcbEncrpyt return error.");
+            }
+        } else {
+            if (wc_Des_EcbDecrypt(&myDes, (byte*) desb, (const byte*) desa,
+                        sizeof(WOLFSSL_DES_cblock)) != 0){
+                WOLFSSL_MSG("wc_Des_EcbDecrpyt return error.");
+            }
         }
     }
@@ -17438,18 +21200,312 @@
 #endif /* NO_DES3 */
 
+#ifndef NO_RC4
+/* Set the key state for Arc4 structure.
+ *
+ * key  Arc4 structure to use
+ * len  length of data buffer
+ * data initial state to set Arc4 structure
+ */
+void wolfSSL_RC4_set_key(WOLFSSL_RC4_KEY* key, int len,
+        const unsigned char* data)
+{
+    typedef char rc4_test[sizeof(WOLFSSL_RC4_KEY) >= sizeof(Arc4) ? 1 : -1];
+    (void)sizeof(rc4_test);
+
+    WOLFSSL_ENTER("wolfSSL_RC4_set_key");
+
+    if (key == NULL || len < 0) {
+        WOLFSSL_MSG("bad argument passed in");
+        return;
+    }
+
+    XMEMSET(key, 0, sizeof(WOLFSSL_RC4_KEY));
+    wc_Arc4SetKey((Arc4*)key, data, (word32)len);
+}
+
+
+/* Encrypt/decrypt with Arc4 structure.
+ *
+ * len length of buffer to encrypt/decrypt (in/out)
+ * in  buffer to encrypt/decrypt
+ * out results of encryption/decryption
+ */
+void wolfSSL_RC4(WOLFSSL_RC4_KEY* key, size_t len,
+        const unsigned char* in, unsigned char* out)
+{
+    WOLFSSL_ENTER("wolfSSL_RC4");
+
+    if (key == NULL || in == NULL || out == NULL) {
+        WOLFSSL_MSG("Bad argument passed in");
+        return;
+    }
+
+    wc_Arc4Process((Arc4*)key, out, in, (word32)len);
+}
+#endif /* NO_RC4 */
+
+#ifndef NO_AES
+
+#ifdef WOLFSSL_AES_DIRECT
+/* AES encrypt direct, it is expected to be blocks of AES_BLOCK_SIZE for input.
+ *
+ * input  Data to encrypt
+ * output Encrypted data after done
+ * key    AES key to use for encryption
+ */
+void wolfSSL_AES_encrypt(const unsigned char* input, unsigned char* output,
+        AES_KEY *key)
+{
+    WOLFSSL_ENTER("wolfSSL_AES_encrypt");
+
+    if (input == NULL || output == NULL || key == NULL) {
+        WOLFSSL_MSG("Null argument passed in");
+        return;
+    }
+
+    wc_AesEncryptDirect((Aes*)key, output, input);
+}
+
+
+/* AES decrypt direct, it is expected to be blocks of AES_BLOCK_SIZE for input.
+ *
+ * input  Data to decrypt
+ * output Decrypted data after done
+ * key    AES key to use for encryption
+ */
+void wolfSSL_AES_decrypt(const unsigned char* input, unsigned char* output,
+        AES_KEY *key)
+{
+    WOLFSSL_ENTER("wolfSSL_AES_decrypt");
+
+    if (input == NULL || output == NULL || key == NULL) {
+        WOLFSSL_MSG("Null argument passed in");
+        return;
+    }
+
+    wc_AesDecryptDirect((Aes*)key, output, input);
+}
+#endif /* WOLFSSL_AES_DIRECT */
+
+/* Setup of an AES key to use for encryption.
+ *
+ * key  key in bytes to use for encryption
+ * bits size of key in bits
+ * aes  AES structure to initialize
+ */
+int wolfSSL_AES_set_encrypt_key(const unsigned char *key, const int bits,
+        AES_KEY *aes)
+{
+    typedef char aes_test[sizeof(AES_KEY) >= sizeof(Aes) ? 1 : -1];
+    (void)sizeof(aes_test);
+
+    WOLFSSL_ENTER("wolfSSL_AES_set_encrypt_key");
+
+    if (key == NULL || aes == NULL) {
+        WOLFSSL_MSG("Null argument passed in");
+        return -1;
+    }
+
+    XMEMSET(aes, 0, sizeof(AES_KEY));
+    if (wc_AesSetKey((Aes*)aes, key, ((bits)/8), NULL, AES_ENCRYPTION) != 0) {
+        WOLFSSL_MSG("Error in setting AES key");
+        return -1;
+    }
+    return 0;
+}
+
+
+/* Setup of an AES key to use for decryption.
+ *
+ * key  key in bytes to use for decryption
+ * bits size of key in bits
+ * aes  AES structure to initialize
+ */
+int wolfSSL_AES_set_decrypt_key(const unsigned char *key, const int bits,
+        AES_KEY *aes)
+{
+    typedef char aes_test[sizeof(AES_KEY) >= sizeof(Aes) ? 1 : -1];
+    (void)sizeof(aes_test);
+
+    WOLFSSL_ENTER("wolfSSL_AES_set_decrypt_key");
+
+    if (key == NULL || aes == NULL) {
+        WOLFSSL_MSG("Null argument passed in");
+        return -1;
+    }
+
+    XMEMSET(aes, 0, sizeof(AES_KEY));
+    if (wc_AesSetKey((Aes*)aes, key, ((bits)/8), NULL, AES_DECRYPTION) != 0) {
+        WOLFSSL_MSG("Error in setting AES key");
+        return -1;
+    }
+    return 0;
+}
+
+
+#ifdef HAVE_AES_ECB
+/* Encrypt/decrypt a 16 byte block of data using the key passed in.
+ *
+ * in  buffer to encrypt/decyrpt
+ * out buffer to hold result of encryption/decryption
+ * key AES structure to use with encryption/decryption
+ * enc AES_ENCRPT for encryption and AES_DECRYPT for decryption
+ */
+void wolfSSL_AES_ecb_encrypt(const unsigned char *in, unsigned char* out,
+                             AES_KEY *key, const int enc)
+{
+    Aes* aes;
+
+    WOLFSSL_ENTER("wolfSSL_AES_ecb_encrypt");
+
+    if (key == NULL || in == NULL || out == NULL) {
+        WOLFSSL_MSG("Error, Null argument passed in");
+        return;
+    }
+
+    aes = (Aes*)key;
+    if (enc == AES_ENCRYPT) {
+        if (wc_AesEcbEncrypt(aes, out, in, AES_BLOCK_SIZE) != 0) {
+            WOLFSSL_MSG("Error with AES CBC encrypt");
+        }
+    }
+    else {
+    #ifdef HAVE_AES_DECRYPT
+        if (wc_AesEcbDecrypt(aes, out, in, AES_BLOCK_SIZE) != 0) {
+            WOLFSSL_MSG("Error with AES CBC decrypt");
+        }
+    #else
+        WOLFSSL_MSG("AES decryption not compiled in");
+    #endif
+    }
+}
+#endif /* HAVE_AES_ECB */
+
+#ifdef HAVE_AES_CBC
+/* Encrypt data using key and iv passed in. iv gets updated to most recent iv
+ * state after encryptiond/decryption.
+ *
+ * in  buffer to encrypt/decyrpt
+ * out buffer to hold result of encryption/decryption
+ * len length of input buffer
+ * key AES structure to use with encryption/decryption
+ * iv  iv to use with operation
+ * enc AES_ENCRPT for encryption and AES_DECRYPT for decryption
+ */
+void wolfSSL_AES_cbc_encrypt(const unsigned char *in, unsigned char* out,
+        size_t len, AES_KEY *key, unsigned char* iv, const int enc)
+{
+    Aes* aes;
+
+    WOLFSSL_ENTER("wolfSSL_AES_cbc_encrypt");
+
+    if (key == NULL || in == NULL || out == NULL || iv == NULL || len == 0) {
+        WOLFSSL_MSG("Error, Null argument passed in");
+        return;
+    }
+
+    aes = (Aes*)key;
+    if (wc_AesSetIV(aes, (const byte*)iv) != 0) {
+        WOLFSSL_MSG("Error with setting iv");
+        return;
+    }
+
+    if (enc == AES_ENCRYPT) {
+        if (wc_AesCbcEncrypt(aes, out, in, (word32)len) != 0) {
+            WOLFSSL_MSG("Error with AES CBC encrypt");
+        }
+    }
+    else {
+        if (wc_AesCbcDecrypt(aes, out, in, (word32)len) != 0) {
+            WOLFSSL_MSG("Error with AES CBC decrypt");
+        }
+    }
+
+    /* to be compatible copy iv to iv buffer after completing operation */
+    XMEMCPY(iv, (byte*)(aes->reg), AES_BLOCK_SIZE);
+}
+#endif /* HAVE_AES_CBC */
+
+
+/* Encrypt data using CFB mode with key and iv passed in. iv gets updated to
+ * most recent iv state after encryptiond/decryption.
+ *
+ * in  buffer to encrypt/decyrpt
+ * out buffer to hold result of encryption/decryption
+ * len length of input buffer
+ * key AES structure to use with encryption/decryption
+ * iv  iv to use with operation
+ * num contains the amount of block used
+ * enc AES_ENCRPT for encryption and AES_DECRYPT for decryption
+ */
+void wolfSSL_AES_cfb128_encrypt(const unsigned char *in, unsigned char* out,
+        size_t len, AES_KEY *key, unsigned char* iv, int* num,
+        const int enc)
+{
+#ifndef WOLFSSL_AES_CFB
+    WOLFSSL_MSG("CFB mode not enabled please use macro WOLFSSL_AES_CFB");
+    (void)in;
+    (void)out;
+    (void)len;
+    (void)key;
+    (void)iv;
+    (void)num;
+    (void)enc;
+
+    return;
+#else
+    Aes* aes;
+
+    WOLFSSL_ENTER("wolfSSL_AES_cbc_encrypt");
+    if (key == NULL || in == NULL || out == NULL || iv == NULL) {
+        WOLFSSL_MSG("Error, Null argument passed in");
+        return;
+    }
+
+    aes = (Aes*)key;
+    if (wc_AesSetIV(aes, (const byte*)iv) != 0) {
+        WOLFSSL_MSG("Error with setting iv");
+        return;
+    }
+
+    if (enc == AES_ENCRYPT) {
+        if (wc_AesCfbEncrypt(aes, out, in, (word32)len) != 0) {
+            WOLFSSL_MSG("Error with AES CBC encrypt");
+        }
+    }
+    else {
+        if (wc_AesCfbDecrypt(aes, out, in, (word32)len) != 0) {
+            WOLFSSL_MSG("Error with AES CBC decrypt");
+        }
+    }
+
+    /* to be compatible copy iv to iv buffer after completing operation */
+    XMEMCPY(iv, (byte*)(aes->reg), AES_BLOCK_SIZE);
+
+    /* store number of left over bytes to num */
+    *num = (aes->left)? AES_BLOCK_SIZE - aes->left : 0;
+#endif /* WOLFSSL_AES_CFB */
+}
+#endif /* NO_AES */
+
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_BIO_printf(WOLFSSL_BIO* bio, const char* format, ...)
 {
     (void)bio;
     (void)format;
+    WOLFSSL_STUB("BIO_printf");
     return 0;
 }
-
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_ASN1_UTCTIME_print(WOLFSSL_BIO* bio, const WOLFSSL_ASN1_UTCTIME* a)
 {
     (void)bio;
     (void)a;
+    WOLFSSL_STUB("ASN1_UTCTIME_print");
     return 0;
 }
+#endif
 
 /* Return the month as a string.
@@ -17458,5 +21514,5 @@
  * returns the month as a string.
  */
-static INLINE const char* MonthStr(const char* n)
+static WC_INLINE const char* MonthStr(const char* n)
 {
     static const char monthStr[12][4] = {
@@ -17495,55 +21551,81 @@
 }
 
-int  wolfSSL_sk_num(WOLFSSL_X509_REVOKED* rev)
-{
-    (void)rev;
-    return 0;
-}
-
-
-void* wolfSSL_sk_value(WOLFSSL_X509_REVOKED* rev, int i)
-{
-    (void)rev;
-    (void)i;
-    return 0;
-}
-
-
+void wolfSSL_ASN1_GENERALIZEDTIME_free(WOLFSSL_ASN1_TIME* asn1Time)
+{
+    WOLFSSL_ENTER("wolfSSL_ASN1_GENERALIZEDTIME_free");
+    if (asn1Time == NULL)
+        return;
+    XMEMSET(asn1Time->data, 0, sizeof(asn1Time->data));
+}
+
+int  wolfSSL_sk_num(WOLF_STACK_OF(WOLFSSL_ASN1_OBJECT)* sk)
+{
+    if (sk == NULL)
+        return 0;
+    return (int)sk->num;
+}
+
+void* wolfSSL_sk_value(WOLF_STACK_OF(WOLFSSL_ASN1_OBJECT)* sk, int i)
+{
+    for (; sk != NULL && i > 0; i--)
+        sk = sk->next;
+    if (sk == NULL)
+        return NULL;
+    return (void*)sk->data.obj;
+}
+
+#endif /* OPENSSL_EXTRA */
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_EXT_CACHE)
 /* stunnel 4.28 needs */
 void wolfSSL_CTX_sess_set_get_cb(WOLFSSL_CTX* ctx,
                     WOLFSSL_SESSION*(*f)(WOLFSSL*, unsigned char*, int, int*))
 {
+    if (ctx == NULL)
+        return;
+
 #ifdef HAVE_EXT_CACHE
     ctx->get_sess_cb = f;
 #else
-    (void)ctx;
     (void)f;
 #endif
 }
-
 
 void wolfSSL_CTX_sess_set_new_cb(WOLFSSL_CTX* ctx,
                              int (*f)(WOLFSSL*, WOLFSSL_SESSION*))
 {
+    if (ctx == NULL)
+        return;
+
 #ifdef HAVE_EXT_CACHE
     ctx->new_sess_cb = f;
 #else
-    (void)ctx;
     (void)f;
 #endif
 }
-
 
 void wolfSSL_CTX_sess_set_remove_cb(WOLFSSL_CTX* ctx, void (*f)(WOLFSSL_CTX*,
                                                         WOLFSSL_SESSION*))
 {
+    if (ctx == NULL)
+        return;
+
 #ifdef HAVE_EXT_CACHE
     ctx->rem_sess_cb = f;
 #else
-    (void)ctx;
     (void)f;
 #endif
 }
-
+#endif /* OPENSSL_EXTRA || HAVE_EXT_CACHE */
+
+#ifdef OPENSSL_EXTRA
+
+/*
+ *
+ * Note: It is expected that the importing and exporting function have been
+ *       built with the same settings. For example if session tickets was
+ *       enabled with the wolfSSL library exporting a session then it is
+ *       expected to be turned on with the wolfSSL library importing the session.
+ */
 int wolfSSL_i2d_SSL_SESSION(WOLFSSL_SESSION* sess, unsigned char** p)
 {
@@ -17555,4 +21637,8 @@
 #endif
     unsigned char *data;
+
+    if (sess == NULL) {
+        return BAD_FUNC_ARG;
+    }
 
     /* bornOn | timeout | sessionID len | sessionID | masterSecret | haveEMS */
@@ -17575,4 +21661,8 @@
     size += OPAQUE16_LEN + sess->ticketLen;
 #endif
+#ifdef OPENSSL_EXTRA
+    /* session context ID len | session context ID */
+    size += OPAQUE8_LEN + sess->sessionCtxSz;
+#endif
 
     if (p != NULL) {
@@ -17589,9 +21679,9 @@
         idx += sess->sessionIDSz;
         XMEMCPY(data + idx, sess->masterSecret, SECRET_LEN); idx += SECRET_LEN;
-        data[idx++] = sess->haveEMS;
+        data[idx++] = (byte)sess->haveEMS;
 #ifdef SESSION_CERTS
-        data[idx++] = sess->chain.count;
+        data[idx++] = (byte)sess->chain.count;
         for (i = 0; i < sess->chain.count; i++) {
-            c16toa(sess->chain.certs[i].length, data + idx);
+            c16toa((word16)sess->chain.certs[i].length, data + idx);
             idx += OPAQUE16_LEN;
             XMEMCPY(data + idx, sess->chain.certs[i].buffer,
@@ -17614,4 +21704,9 @@
         idx += sess->ticketLen;
 #endif
+#ifdef OPENSSL_EXTRA
+        data[idx++] = sess->sessionCtxSz;
+        XMEMCPY(data + idx, sess->sessionCtx, sess->sessionCtxSz);
+        idx += sess->sessionCtxSz;
+#endif
     }
 #endif
@@ -17626,5 +21721,12 @@
 }
 
-/* TODO: no function to free new session. */
+
+/* TODO: no function to free new session.
+ *
+ * Note: It is expected that the importing and exporting function have been
+ *       built with the same settings. For example if session tickets was
+ *       enabled with the wolfSSL library exporting a session then it is
+ *       expected to be turned on with the wolfSSL library importing the session.
+ */
 WOLFSSL_SESSION* wolfSSL_d2i_SSL_SESSION(WOLFSSL_SESSION** sess,
                                 const unsigned char** p, long i)
@@ -17657,6 +21759,9 @@
         if (s == NULL)
             return NULL;
+        XMEMSET(s, 0, sizeof(WOLFSSL_SESSION));
         s->isAlloced = 1;
+#ifdef HAVE_SESSION_TICKET
         s->isDynamic = 0;
+#endif
     }
 
@@ -17760,4 +21865,19 @@
     XMEMCPY(s->ticket, data + idx, s->ticketLen); idx += s->ticketLen;
 #endif
+#ifdef OPENSSL_EXTRA
+    /* byte for length of session context ID */
+    if (i - idx < OPAQUE8_LEN) {
+        ret = BUFFER_ERROR;
+        goto end;
+    }
+    s->sessionCtxSz = data[idx++];
+
+    /* app session context ID */
+    if (i - idx < s->sessionCtxSz) {
+        ret = BUFFER_ERROR;
+        goto end;
+    }
+    XMEMCPY(s->sessionCtx, data + idx, s->sessionCtxSz); idx += s->sessionCtxSz;
+#endif
     (void)idx;
 
@@ -17777,6 +21897,9 @@
 long wolfSSL_SESSION_get_timeout(const WOLFSSL_SESSION* sess)
 {
+    long timeout = 0;
     WOLFSSL_ENTER("wolfSSL_SESSION_get_timeout");
-    return sess->timeout;
+    if (sess)
+        timeout = sess->timeout;
+    return timeout;
 }
 
@@ -17784,6 +21907,9 @@
 long wolfSSL_SESSION_get_time(const WOLFSSL_SESSION* sess)
 {
+    long bornOn = 0;
     WOLFSSL_ENTER("wolfSSL_SESSION_get_time");
-    return sess->bornOn;
+    if (sess)
+        bornOn = sess->bornOn;
+    return bornOn;
 }
 
@@ -17804,5 +21930,5 @@
 #ifdef OPENSSL_EXTRA
 
-#ifdef FORTRESS
+#if defined(FORTRESS) && !defined(NO_FILESYSTEM)
 int wolfSSL_cmp_peer_cert_to_file(WOLFSSL* ssl, const char *fname)
 {
@@ -17813,8 +21939,6 @@
     {
     #ifdef WOLFSSL_SMALL_STACK
-        EncryptedInfo* info = NULL;
         byte           staticBuffer[1]; /* force heap usage */
     #else
-        EncryptedInfo  info[1];
         byte           staticBuffer[FILE_BUFFER_SIZE];
     #endif
@@ -17823,5 +21947,4 @@
         XFILE          file      = XBADFILE;
         size_t         sz        = 0;
-        int            eccKey    = 0;
         WOLFSSL_CTX*   ctx       = ssl->ctx;
         WOLFSSL_X509*  peer_cert = &ssl->peerCert;
@@ -17832,5 +21955,8 @@
             return WOLFSSL_BAD_FILE;
 
-        XFSEEK(file, 0, XSEEK_END);
+        if(XFSEEK(file, 0, XSEEK_END) != 0) {
+            XFCLOSE(file);
+            return WOLFSSL_BAD_FILE;
+        }
         sz = XFTELL(file);
         XREWIND(file);
@@ -17842,32 +21968,16 @@
         }
 
-    #ifdef WOLFSSL_SMALL_STACK
-        info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), NULL,
-                                       DYNAMIC_TYPE_ENCRYPTEDINFO);
-        if (info == NULL)
-            ret = MEMORY_E;
-        else
-    #endif
+
+        if ((myBuffer != NULL) &&
+            (sz > 0) &&
+            (XFREAD(myBuffer, 1, sz, file) == sz) &&
+            (PemToDer(myBuffer, (long)sz, CERT_TYPE,
+                      &fileDer, ctx->heap, NULL, NULL) == 0) &&
+            (fileDer->length != 0) &&
+            (fileDer->length == peer_cert->derCert->length) &&
+            (XMEMCMP(peer_cert->derCert->buffer, fileDer->buffer,
+                                                fileDer->length) == 0))
         {
-            info->set = 0;
-            info->ctx = ctx;
-            info->consumed = 0;
-
-            if ((myBuffer != NULL) &&
-                (sz > 0) &&
-                (XFREAD(myBuffer, 1, sz, file) == sz) &&
-                (PemToDer(myBuffer, sz, CERT_TYPE,
-                          &fileDer, ctx->heap, info, &eccKey) == 0) &&
-                (fileDer->length != 0) &&
-                (fileDer->length == peer_cert->derCert->length) &&
-                (XMEMCMP(peer_cert->derCert->buffer, fileDer->buffer,
-                                                    fileDer->length) == 0))
-            {
-                ret = 0;
-            }
-
-        #ifdef WOLFSSL_SMALL_STACK
-            XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO);
-        #endif
+            ret = 0;
         }
 
@@ -17883,18 +21993,21 @@
 }
 #endif
-
-
+#endif /* OPENSSL_EXTRA */
+
+#if defined(OPENSSL_EXTRA) || \
+    (defined(OPENSSL_EXTRA_X509_SMALL) && !defined(NO_RSA))
 static WC_RNG globalRNG;
 static int initGlobalRNG = 0;
-
-/* WOLFSSL_SUCCESS on ok */
-int wolfSSL_RAND_seed(const void* seed, int len)
-{
-
-    WOLFSSL_MSG("wolfSSL_RAND_seed");
-
-    (void)seed;
-    (void)len;
-
+#endif
+
+#ifdef OPENSSL_EXTRA
+
+/* Not thread safe! Can be called multiple times.
+ * Checks if the global RNG has been created. If not then one is created.
+ *
+ * Returns SSL_SUCCESS when no error is encountered.
+ */
+static int wolfSSL_RAND_Init(void)
+{
     if (initGlobalRNG == 0) {
         if (wc_InitRng(&globalRNG) < 0) {
@@ -17905,9 +22018,333 @@
     }
 
-    return WOLFSSL_SUCCESS;
-}
-
-
-/* WOLFSSL_SUCCESS on ok */
+    return SSL_SUCCESS;
+}
+
+
+/* SSL_SUCCESS on ok */
+int wolfSSL_RAND_seed(const void* seed, int len)
+{
+
+    WOLFSSL_MSG("wolfSSL_RAND_seed");
+
+    (void)seed;
+    (void)len;
+
+    return wolfSSL_RAND_Init();
+}
+
+
+/* Returns the path for reading seed data from.
+ * Uses the env variable $RANDFILE first if set, if not then used $HOME/.rnd
+ *
+ * Note uses stdlib by default unless XGETENV macro is overwritten
+ *
+ * fname buffer to hold path
+ * len   length of fname buffer
+ *
+ * Returns a pointer to fname on success and NULL on failure
+ */
+const char* wolfSSL_RAND_file_name(char* fname, unsigned long len)
+{
+#ifndef NO_FILESYSTEM
+    char* rt;
+    char ap[] = "/.rnd";
+
+    WOLFSSL_ENTER("wolfSSL_RAND_file_name");
+
+    if (fname == NULL) {
+        return NULL;
+    }
+
+    XMEMSET(fname, 0, len);
+    /* if access to stdlib.h */
+    if ((rt = XGETENV("RANDFILE")) != NULL) {
+        if (len > XSTRLEN(rt)) {
+            XMEMCPY(fname, rt, XSTRLEN(rt));
+        }
+        else {
+            WOLFSSL_MSG("RANDFILE too large for buffer");
+            rt = NULL;
+        }
+    }
+
+    /* $RANDFILE was not set or is too large, check $HOME */
+    if (rt == NULL) {
+        WOLFSSL_MSG("Environment variable RANDFILE not set");
+        if ((rt = XGETENV("HOME")) == NULL) {
+            WOLFSSL_MSG("Environment variable HOME not set");
+            return NULL;
+        }
+
+        if (len > XSTRLEN(rt) +  XSTRLEN(ap)) {
+            fname[0] = '\0';
+            XSTRNCAT(fname, rt, len);
+            XSTRNCAT(fname, ap, len - XSTRLEN(rt));
+            return fname;
+        }
+        else {
+            WOLFSSL_MSG("HOME too large for buffer");
+            return NULL;
+        }
+    }
+
+    return fname;
+#else
+    /* no filesystem defined */
+    WOLFSSL_ENTER("wolfSSL_RAND_file_name");
+    WOLFSSL_MSG("No filesystem feature enabled, not compiled in");
+    (void)fname;
+    (void)len;
+    return NULL;
+#endif
+}
+
+
+/* Writes 1024 bytes from the RNG to the given file name.
+ *
+ * fname name of file to write to
+ *
+ * Returns the number of bytes writen
+ */
+int wolfSSL_RAND_write_file(const char* fname)
+{
+    int bytes = 0;
+
+    WOLFSSL_ENTER("RAND_write_file");
+
+    if (fname == NULL) {
+        return SSL_FAILURE;
+    }
+
+#ifndef NO_FILESYSTEM
+    {
+    #ifndef WOLFSSL_SMALL_STACK
+        unsigned char buf[1024];
+    #else
+        unsigned char* buf = (unsigned char *)XMALLOC(1024, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+        if (buf == NULL) {
+            WOLFSSL_MSG("malloc failed");
+            return SSL_FAILURE;
+        }
+    #endif
+        bytes = 1024; /* default size of buf */
+
+        if (initGlobalRNG == 0 && wolfSSL_RAND_Init() != SSL_SUCCESS) {
+            WOLFSSL_MSG("No RNG to use");
+        #ifdef WOLFSSL_SMALL_STACK
+            XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        #endif
+            return 0;
+        }
+
+        if (wc_RNG_GenerateBlock(&globalRNG, buf, bytes) != 0) {
+            WOLFSSL_MSG("Error generating random buffer");
+            bytes = 0;
+        }
+        else {
+            XFILE f;
+
+            f = XFOPEN(fname, "wb");
+            if (f == XBADFILE) {
+                WOLFSSL_MSG("Error opening the file");
+                bytes = 0;
+            }
+            else {
+                XFWRITE(buf, 1, bytes, f);
+                XFCLOSE(f);
+            }
+        }
+        ForceZero(buf, bytes);
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+    }
+#endif
+
+    return bytes;
+}
+
+#ifndef FREERTOS_TCP
+
+/* These constant values are protocol values made by egd */
+#if defined(USE_WOLFSSL_IO) && !defined(USE_WINDOWS_API)
+    #define WOLFSSL_EGD_NBLOCK 0x01
+    #include <sys/un.h>
+#endif
+
+/* This collects entropy from the path nm and seeds the global PRNG with it.
+ * Makes a call to wolfSSL_RAND_Init which is not thread safe.
+ *
+ * nm is the file path to the egd server
+ *
+ * Returns the number of bytes read.
+ */
+int wolfSSL_RAND_egd(const char* nm)
+{
+#if defined(USE_WOLFSSL_IO) && !defined(USE_WINDOWS_API) && !defined(HAVE_FIPS) && \
+    defined(HAVE_HASHDRBG)
+    struct sockaddr_un rem;
+    int fd;
+    int ret = WOLFSSL_SUCCESS;
+    word32 bytes = 0;
+    word32 idx   = 0;
+#ifndef WOLFSSL_SMALL_STACK
+    unsigned char buf[256];
+#else
+    unsigned char* buf;
+    buf = (unsigned char*)XMALLOC(256, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (buf == NULL) {
+        WOLFSSL_MSG("Not enough memory");
+        return WOLFSSL_FATAL_ERROR;
+    }
+#endif
+
+    if (nm == NULL) {
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+        return WOLFSSL_FATAL_ERROR;
+    }
+
+    fd = socket(AF_UNIX, SOCK_STREAM, 0);
+    if (fd < 0) {
+        WOLFSSL_MSG("Error creating socket");
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return WOLFSSL_FATAL_ERROR;
+    }
+    if (ret == WOLFSSL_SUCCESS) {
+        rem.sun_family = AF_UNIX;
+        XSTRNCPY(rem.sun_path, nm, sizeof(rem.sun_path));
+        rem.sun_path[sizeof(rem.sun_path)-1] = '\0';
+    }
+
+    /* connect to egd server */
+    if (ret == WOLFSSL_SUCCESS) {
+        if (connect(fd, (struct sockaddr*)&rem, sizeof(struct sockaddr_un))
+                == -1) {
+            WOLFSSL_MSG("error connecting to egd server");
+            ret = WOLFSSL_FATAL_ERROR;
+        }
+    }
+
+    while (ret == WOLFSSL_SUCCESS && bytes < 255 && idx + 2 < 256) {
+        if (ret == WOLFSSL_SUCCESS) {
+            buf[idx]     = WOLFSSL_EGD_NBLOCK;
+            buf[idx + 1] = 255 - bytes; /* request 255 bytes from server */
+            ret = (int)write(fd, buf + idx, 2);
+            if (ret <= 0 || ret != 2) {
+                if (errno == EAGAIN) {
+                    ret = WOLFSSL_SUCCESS;
+                    continue;
+                }
+                WOLFSSL_MSG("error requesting entropy from egd server");
+                ret = WOLFSSL_FATAL_ERROR;
+            break;
+            }
+        }
+
+        /* attempting to read */
+        buf[idx] = 0;
+        ret = (int)read(fd, buf + idx, 256 - bytes);
+        if (ret == 0) {
+            WOLFSSL_MSG("error reading entropy from egd server");
+            ret = WOLFSSL_FATAL_ERROR;
+            break;
+        }
+        if (ret > 0 && buf[idx] > 0) {
+            bytes += buf[idx]; /* egd stores amount sent in first byte */
+            if (bytes + idx > 255 || buf[idx] > ret) {
+                WOLFSSL_MSG("Buffer error");
+                ret = WOLFSSL_FATAL_ERROR;
+            break;
+            }
+            XMEMMOVE(buf + idx, buf + idx + 1, buf[idx]);
+            idx = bytes;
+            ret = WOLFSSL_SUCCESS;
+            if (bytes >= 255) {
+            break;
+            }
+        }
+        else {
+            if (errno == EAGAIN || errno == EINTR) {
+                WOLFSSL_MSG("EGD would read");
+                ret = WOLFSSL_SUCCESS; /* try again */
+            }
+            else if (buf[idx] == 0) {
+                /* if egd returned 0 then there is no more entropy to be had.
+                   Do not try more reads. */
+                ret = WOLFSSL_SUCCESS;
+            break;
+            }
+            else {
+                WOLFSSL_MSG("Error with read");
+                ret = WOLFSSL_FATAL_ERROR;
+            }
+        }
+    }
+
+    if (bytes > 0 && ret == WOLFSSL_SUCCESS) {
+        wolfSSL_RAND_Init(); /* call to check global RNG is created */
+        if (wc_RNG_DRBG_Reseed(&globalRNG, (const byte*) buf, bytes)
+                != 0) {
+            WOLFSSL_MSG("Error with reseeding DRBG structure");
+            ret = WOLFSSL_FATAL_ERROR;
+        }
+        #ifdef SHOW_SECRETS
+        { /* print out entropy found */
+            word32 i;
+            printf("EGD Entropy = ");
+            for (i = 0; i < bytes; i++) {
+                printf("%02X", buf[i]);
+            }
+            printf("\n");
+        }
+    #endif
+    }
+
+    ForceZero(buf, bytes);
+    #ifdef WOLFSSL_SMALL_STACK
+    XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+    close(fd);
+
+    if (ret == WOLFSSL_SUCCESS) {
+        return bytes;
+    }
+    else {
+        return ret;
+    }
+#else
+    WOLFSSL_MSG("Type of socket needed is not available");
+    WOLFSSL_MSG("\tor using mode where DRBG API is not available");
+    (void)nm;
+
+    return WOLFSSL_FATAL_ERROR;
+#endif /* USE_WOLFSSL_IO && !USE_WINDOWS_API && !HAVE_FIPS && HAVE_HASHDRBG */
+}
+
+#endif /* !FREERTOS_TCP */
+
+void wolfSSL_RAND_Cleanup(void)
+{
+    WOLFSSL_ENTER("wolfSSL_RAND_Cleanup()");
+
+    if (initGlobalRNG != 0) {
+        wc_FreeRng(&globalRNG);
+        initGlobalRNG = 0;
+    }
+}
+
+
+int wolfSSL_RAND_pseudo_bytes(unsigned char* buf, int num)
+{
+    return wolfSSL_RAND_bytes(buf, num);
+}
+
+
+/* SSL_SUCCESS on ok */
 int wolfSSL_RAND_bytes(unsigned char* buf, int num)
 {
@@ -17953,4 +22390,26 @@
 }
 
+
+int wolfSSL_RAND_poll(void)
+{
+    byte  entropy[16];
+    int  ret = 0;
+    word32 entropy_sz = 16;
+
+    WOLFSSL_ENTER("wolfSSL_RAND_poll");
+    if (initGlobalRNG == 0){
+        WOLFSSL_MSG("Global RNG no Init");
+        return  WOLFSSL_FAILURE;
+    }
+    ret = wc_GenerateSeed(&globalRNG.seed, entropy, entropy_sz);
+    if (ret != 0){
+        WOLFSSL_MSG("Bad wc_RNG_GenerateBlock");
+        ret = WOLFSSL_FAILURE;
+    }else
+        ret = WOLFSSL_SUCCESS;
+
+    return ret;
+}
+
 WOLFSSL_BN_CTX* wolfSSL_BN_CTX_new(void)
 {
@@ -17958,6 +22417,6 @@
 
     WOLFSSL_MSG("wolfSSL_BN_CTX_new");
-
     return (WOLFSSL_BN_CTX*)&ctx;
+
 }
 
@@ -17973,18 +22432,18 @@
     (void)ctx;
     WOLFSSL_MSG("wolfSSL_BN_CTX_free");
-
     /* do free since static ctx that does nothing */
 }
-
-
+#endif /* OPENSSL_EXTRA */
+
+
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
 static void InitwolfSSL_BigNum(WOLFSSL_BIGNUM* bn)
 {
-    WOLFSSL_MSG("InitwolfSSL_BigNum");
     if (bn) {
+        XMEMSET(bn, 0, sizeof(WOLFSSL_BIGNUM));
         bn->neg      = 0;
         bn->internal = NULL;
     }
 }
-
 
 WOLFSSL_BIGNUM* wolfSSL_BN_new(void)
@@ -18010,9 +22469,9 @@
 
     InitwolfSSL_BigNum(external);
-    external->internal = mpi;
     if (mp_init(mpi) != MP_OKAY) {
         wolfSSL_BN_free(external);
         return NULL;
     }
+    external->internal = mpi;
 
     return external;
@@ -18025,5 +22484,7 @@
     if (bn) {
         if (bn->internal) {
-            mp_forcezero((mp_int*)bn->internal);
+            mp_int* bni = (mp_int*)bn->internal;
+            mp_forcezero(bni);
+            mp_free(bni);
             XFREE(bn->internal, NULL, DYNAMIC_TYPE_BIGINT);
             bn->internal = NULL;
@@ -18033,5 +22494,7 @@
     }
 }
-
+#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
+
+#ifdef OPENSSL_EXTRA
 
 void wolfSSL_BN_clear_free(WOLFSSL_BIGNUM* bn)
@@ -18096,5 +22559,5 @@
                (mp_int*)m->internal, (mp_int*)r->internal)) == MP_OKAY) {
         return WOLFSSL_SUCCESS;
-    }
+}
 
     WOLFSSL_LEAVE("wolfSSL_BN_mod_exp", ret);
@@ -18102,4 +22565,29 @@
 
     return WOLFSSL_FAILURE;
+}
+
+/* r = (a * p) % m */
+int wolfSSL_BN_mod_mul(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *a,
+        const WOLFSSL_BIGNUM *p, const WOLFSSL_BIGNUM *m, WOLFSSL_BN_CTX *ctx)
+{
+    int ret;
+
+    WOLFSSL_ENTER("wolfSSL_BN_mod_mul");
+
+    (void) ctx;
+    if (r == NULL || a == NULL || p == NULL || m == NULL) {
+        WOLFSSL_MSG("Bad Argument");
+        return SSL_FAILURE;
+}
+
+    if ((ret = mp_mulmod((mp_int*)a->internal,(mp_int*)p->internal,
+               (mp_int*)m->internal, (mp_int*)r->internal)) == MP_OKAY) {
+        return SSL_SUCCESS;
+    }
+
+    WOLFSSL_LEAVE("wolfSSL_BN_mod_mul", ret);
+    (void)ret;
+
+    return SSL_FAILURE;
 }
 
@@ -18119,5 +22607,5 @@
             }
         }
-    }
+}
 
     return bn_one;
@@ -18128,5 +22616,5 @@
 int wolfSSL_BN_num_bytes(const WOLFSSL_BIGNUM* bn)
 {
-    WOLFSSL_MSG("wolfSSL_BN_num_bytes");
+    WOLFSSL_ENTER("wolfSSL_BN_num_bytes");
 
     if (bn == NULL || bn->internal == NULL)
@@ -18140,5 +22628,5 @@
 int wolfSSL_BN_num_bits(const WOLFSSL_BIGNUM* bn)
 {
-    WOLFSSL_MSG("wolfSSL_BN_num_bits");
+    WOLFSSL_ENTER("wolfSSL_BN_num_bits");
 
     if (bn == NULL || bn->internal == NULL)
@@ -18219,5 +22707,5 @@
         WOLFSSL_MSG("NULL bn error");
         return WOLFSSL_FATAL_ERROR;
-    }
+}
 
     if (r == NULL)
@@ -18227,5 +22715,5 @@
         WOLFSSL_MSG("mp_to_unsigned_bin error");
         return WOLFSSL_FATAL_ERROR;
-    }
+}
 
     return mp_unsigned_bin_size((mp_int*)bn->internal);
@@ -18246,5 +22734,5 @@
         if (ret == NULL)
             return NULL;
-    }
+}
 
     /* check ret and ret->internal then read in value */
@@ -18256,5 +22744,5 @@
             return NULL;
         }
-    }
+}
 
     return ret;
@@ -18263,12 +22751,14 @@
 /* return compliant with OpenSSL
  *   1 if success, 0 if error */
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_mask_bits(WOLFSSL_BIGNUM* bn, int n)
 {
     (void)bn;
     (void)n;
-    WOLFSSL_MSG("wolfSSL_BN_mask_bits");
-
-    return WOLFSSL_FAILURE;
-}
+    WOLFSSL_ENTER("wolfSSL_BN_mask_bits");
+    WOLFSSL_STUB("BN_mask_bits");
+    return SSL_FAILURE;
+}
+#endif
 
 
@@ -18302,5 +22792,5 @@
         XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG);
         return ret;
-    }
+}
 #endif
 
@@ -18310,5 +22800,5 @@
         rng = tmpRNG;
         initTmpRng = 1;
-    }
+}
     else if (initGlobalRNG)
         rng = &globalRNG;
@@ -18323,8 +22813,8 @@
             if (mp_read_unsigned_bin((mp_int*)bn->internal,buff,len) != MP_OKAY)
                 WOLFSSL_MSG("mp read bin failed");
-            else
+    else
                 ret = WOLFSSL_SUCCESS;
-        }
-    }
+}
+}
 
     if (initTmpRng)
@@ -18334,4 +22824,89 @@
     XFREE(buff,   NULL, DYNAMIC_TYPE_TMP_BUFFER);
     XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG);
+#endif
+
+    return ret;
+}
+
+
+/* WOLFSSL_SUCCESS on ok
+ * code is same as wolfSSL_BN_rand except for how top and bottom is handled.
+ * top -1 then leave most sig bit alone
+ * top 0 then most sig is set to 1
+ * top is 1 then first two most sig bits are 1
+ *
+ * bottom is hot then odd number */
+int wolfSSL_BN_pseudo_rand(WOLFSSL_BIGNUM* bn, int bits, int top, int bottom)
+{
+    int           ret    = 0;
+    int           len    = bits / 8;
+    int           initTmpRng = 0;
+    WC_RNG*       rng    = NULL;
+#ifdef WOLFSSL_SMALL_STACK
+    WC_RNG*       tmpRNG = NULL;
+    byte*         buff   = NULL;
+#else
+    WC_RNG        tmpRNG[1];
+    byte          buff[1024];
+#endif
+
+    WOLFSSL_MSG("wolfSSL_BN_rand");
+
+    if (bits % 8)
+        len++;
+
+#ifdef WOLFSSL_SMALL_STACK
+    buff   = (byte*)XMALLOC(1024,        NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    tmpRNG = (WC_RNG*) XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (buff == NULL || tmpRNG == NULL) {
+        XFREE(buff,   NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(tmpRNG, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return ret;
+    }
+#endif
+
+    if (bn == NULL || bn->internal == NULL)
+        WOLFSSL_MSG("Bad function arguments");
+    else if (wc_InitRng(tmpRNG) == 0) {
+        rng = tmpRNG;
+        initTmpRng = 1;
+}
+    else if (initGlobalRNG)
+        rng = &globalRNG;
+
+    if (rng) {
+        if (wc_RNG_GenerateBlock(rng, buff, len) != 0)
+            WOLFSSL_MSG("Bad wc_RNG_GenerateBlock");
+        else {
+            switch (top) {
+                case -1:
+                    break;
+
+                case 0:
+                    buff[0] |= 0x80;
+                    break;
+
+                case 1:
+                    buff[0] |= 0x80 | 0x40;
+                    break;
+}
+
+            if (bottom == 1) {
+                buff[len-1] |= 0x01;
+            }
+
+            if (mp_read_unsigned_bin((mp_int*)bn->internal,buff,len) != MP_OKAY)
+                WOLFSSL_MSG("mp read bin failed");
+            else
+                ret = WOLFSSL_SUCCESS;
+        }
+}
+
+    if (initTmpRng)
+        wc_FreeRng(tmpRNG);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(buff,   NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(tmpRNG, NULL, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
 
@@ -18392,4 +22967,5 @@
     byte    decoded[1024];
 #endif
+    int     weOwn = 0;
 
     WOLFSSL_MSG("wolfSSL_BN_hex2bn");
@@ -18408,11 +22984,19 @@
         ret = decSz;
     else {
-        if (*bn == NULL)
+        if (*bn == NULL) {
             *bn = wolfSSL_BN_new();
+            if (*bn != NULL) {
+                weOwn = 1;
+                }
+            }
 
         if (*bn == NULL)
             WOLFSSL_MSG("BN new failed");
-        else if (wolfSSL_BN_bin2bn(decoded, decSz, *bn) == NULL)
+        else if (wolfSSL_BN_bin2bn(decoded, decSz, *bn) == NULL) {
             WOLFSSL_MSG("Bad bin2bn error");
+            if (weOwn == 1) {
+                wolfSSL_BN_free(*bn); /* Free new BN */
+        }
+        }
         else
             ret = WOLFSSL_SUCCESS;
@@ -18436,5 +23020,5 @@
         WOLFSSL_MSG("bn NULL error");
         return NULL;
-    }
+}
 
     ret = wolfSSL_BN_new();
@@ -18448,5 +23032,5 @@
         wolfSSL_BN_free(ret);
         return NULL;
-    }
+}
 
     ret->neg = bn->neg;
@@ -18459,4 +23043,9 @@
 {
     WOLFSSL_MSG("wolfSSL_BN_copy");
+
+    if (r == NULL || bn == NULL) {
+        WOLFSSL_MSG("r or bn NULL error");
+        return NULL;
+    }
 
     if (mp_copy((mp_int*)bn->internal, (mp_int*)r->internal) != MP_OKAY) {
@@ -18468,5 +23057,5 @@
 
     return r;
-}
+    }
 
 /* return code compliant with OpenSSL :
@@ -18477,4 +23066,9 @@
     WOLFSSL_MSG("wolfSSL_BN_set_word");
 
+    if (bn == NULL) {
+        WOLFSSL_MSG("bn NULL error");
+        return WOLFSSL_FAILURE;
+    }
+
     if (mp_set_int((mp_int*)bn->internal, w) != MP_OKAY) {
         WOLFSSL_MSG("mp_init_set_int error");
@@ -18485,7 +23079,35 @@
 }
 
+
+/* Returns the big number as an unsigned long if possible.
+ *
+ * bn  big number structure to get value from
+ *
+ * Returns value or 0xFFFFFFFFL if bigger than unsigned long.
+ */
+unsigned long wolfSSL_BN_get_word(const WOLFSSL_BIGNUM* bn)
+{
+    mp_int* mp;
+
+    WOLFSSL_MSG("wolfSSL_BN_get_word");
+
+    if (bn == NULL) {
+        WOLFSSL_MSG("Invalid argument");
+        return 0;
+    }
+
+    if (wolfSSL_BN_num_bytes(bn) > (int)sizeof(unsigned long)) {
+        WOLFSSL_MSG("bignum is larger than unsigned long");
+        return 0xFFFFFFFFL;
+    }
+    mp = (mp_int*)bn->internal;
+
+    return (unsigned long)(mp->dp[0]);
+    }
+
 /* return code compliant with OpenSSL :
  *   number length in decimal if success, 0 if error
  */
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_BN_dec2bn(WOLFSSL_BIGNUM** bn, const char* str)
 {
@@ -18494,8 +23116,8 @@
 
     WOLFSSL_MSG("wolfSSL_BN_dec2bn");
-
-    return WOLFSSL_FAILURE;
-}
-
+    WOLFSSL_STUB("BN_dec2bn");
+    return SSL_FAILURE;
+    }
+#endif
 
 #if defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY)
@@ -18510,18 +23132,18 @@
         WOLFSSL_MSG("bn NULL error");
         return NULL;
-    }
-
-    if (mp_radix_size((mp_int*)bn->internal, 10, &len) != MP_OKAY) {
+        }
+
+    if (mp_radix_size((mp_int*)bn->internal, MP_RADIX_DEC, &len) != MP_OKAY) {
         WOLFSSL_MSG("mp_radix_size failure");
         return NULL;
     }
 
-    buf = (char*) XMALLOC(len, NULL, DYNAMIC_TYPE_ECC);
+    buf = (char*) XMALLOC(len, NULL, DYNAMIC_TYPE_OPENSSL);
     if (buf == NULL) {
-        WOLFSSL_MSG("wolfSSL_BN_bn2hex malloc buffer failure");
+        WOLFSSL_MSG("BN_bn2dec malloc buffer failure");
         return NULL;
-    }
-
-    if (mp_toradix((mp_int*)bn->internal, buf, 10) != MP_OKAY) {
+}
+
+    if (mp_todecimal((mp_int*)bn->internal, buf) != MP_OKAY) {
         XFREE(buf, NULL, DYNAMIC_TYPE_ECC);
         return NULL;
@@ -18538,5 +23160,5 @@
 
     return NULL;
-}
+    }
 #endif /* defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) */
 
@@ -18559,5 +23181,5 @@
 
     return WOLFSSL_SUCCESS;
-}
+    }
 
 /* return code compliant with OpenSSL :
@@ -18571,5 +23193,5 @@
         WOLFSSL_MSG("bn NULL error");
         return WOLFSSL_FAILURE;
-    }
+            }
 
     if (mp_div_2d((mp_int*)bn->internal, n,
@@ -18577,8 +23199,8 @@
         WOLFSSL_MSG("mp_mul_2d error");
         return WOLFSSL_FAILURE;
-    }
+            }
 
     return WOLFSSL_SUCCESS;
-}
+        }
 
 /* return code compliant with OpenSSL :
@@ -18592,13 +23214,13 @@
         WOLFSSL_MSG("bn NULL error");
         return WOLFSSL_FAILURE;
-    }
+                    }
 
     if (mp_add_d((mp_int*)bn->internal, w, (mp_int*)bn->internal) != MP_OKAY) {
         WOLFSSL_MSG("mp_add_d error");
         return WOLFSSL_FAILURE;
-    }
+                    }
 
     return WOLFSSL_SUCCESS;
-}
+                    }
 
 /* return code compliant with OpenSSL :
@@ -18613,5 +23235,5 @@
         WOLFSSL_MSG("bn NULL error");
         return WOLFSSL_FAILURE;
-    }
+                }
 
     if (mp_add((mp_int*)a->internal, (mp_int*)b->internal,
@@ -18619,8 +23241,8 @@
         WOLFSSL_MSG("mp_add_d error");
         return WOLFSSL_FAILURE;
-    }
+                    }
 
     return WOLFSSL_SUCCESS;
-}
+                    }
 
 #ifdef WOLFSSL_KEY_GEN
@@ -18632,5 +23254,12 @@
                            WOLFSSL_BN_CTX *ctx, WOLFSSL_BN_GENCB *cb)
 {
-    int res;
+    WC_RNG*        rng    = NULL;
+#ifdef WOLFSSL_SMALL_STACK
+    WC_RNG*        tmpRNG = NULL;
+#else
+    WC_RNG         tmpRNG[1];
+#endif
+    int            initTmpRng = 0;
+    int            res = MP_NO;
 
     (void)ctx;
@@ -18642,18 +23271,45 @@
         WOLFSSL_MSG("bn NULL error");
         return WOLFSSL_FATAL_ERROR;
-    }
-
-    if (mp_prime_is_prime((mp_int*)bn->internal, nbchecks, &res) != MP_OKAY) {
-        WOLFSSL_MSG("mp_prime_is_prime error");
-        return WOLFSSL_FATAL_ERROR;
-    }
+                    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG);
+    if (tmpRNG == NULL)
+        return WOLFSSL_FAILURE;
+#endif
+    if (wc_InitRng(tmpRNG) == 0) {
+        rng = tmpRNG;
+        initTmpRng = 1;
+                }
+    else {
+        WOLFSSL_MSG("Bad RNG Init, trying global");
+        if (initGlobalRNG == 0) {
+            WOLFSSL_MSG("Global RNG no Init");
+            }
+        else
+            rng = &globalRNG;
+    }
+
+    if (rng) {
+        if (mp_prime_is_prime_ex((mp_int*)bn->internal,
+                                 nbchecks, &res, rng) != MP_OKAY) {
+            WOLFSSL_MSG("mp_prime_is_prime_ex error");
+            res = MP_NO;
+        }
+    }
+
+    if (initTmpRng)
+        wc_FreeRng(tmpRNG);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG);
+#endif
 
     if (res != MP_YES) {
-        WOLFSSL_MSG("mp_prime_is_prime not prime");
+        WOLFSSL_MSG("mp_prime_is_prime_ex not prime");
         return WOLFSSL_FAILURE;
-    }
+            }
 
     return WOLFSSL_SUCCESS;
-}
+        }
 
 /* return code compliant with OpenSSL :
@@ -18670,16 +23326,15 @@
         WOLFSSL_MSG("bn NULL error");
         return (WOLFSSL_BN_ULONG)WOLFSSL_FATAL_ERROR;
-    }
+        }
 
     if (mp_mod_d((mp_int*)bn->internal, w, &ret) != MP_OKAY) {
         WOLFSSL_MSG("mp_add_d error");
         return (WOLFSSL_BN_ULONG)WOLFSSL_FATAL_ERROR;
-    }
+            }
 
     return ret;
-}
+            }
 #endif /* #ifdef WOLFSSL_KEY_GEN */
 
-#if defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY)
 char *wolfSSL_BN_bn2hex(const WOLFSSL_BIGNUM *bn)
 {
@@ -18687,29 +23342,30 @@
     char *buf;
 
-    WOLFSSL_MSG("wolfSSL_BN_bn2hex");
+    WOLFSSL_ENTER("wolfSSL_BN_bn2hex");
 
     if (bn == NULL || bn->internal == NULL) {
         WOLFSSL_MSG("bn NULL error");
         return NULL;
-    }
-
-    if (mp_radix_size((mp_int*)bn->internal, 16, &len) != MP_OKAY) {
+        }
+
+    if (mp_radix_size((mp_int*)bn->internal, MP_RADIX_HEX, &len) != MP_OKAY) {
         WOLFSSL_MSG("mp_radix_size failure");
         return NULL;
     }
-
-    buf = (char*) XMALLOC(len, NULL, DYNAMIC_TYPE_ECC);
+    len += 1; /* add one for null terminator */
+
+    buf = (char*)XMALLOC(len, NULL, DYNAMIC_TYPE_OPENSSL);
     if (buf == NULL) {
-        WOLFSSL_MSG("wolfSSL_BN_bn2hex malloc buffer failure");
+        WOLFSSL_MSG("BN_bn2hex malloc buffer failure");
         return NULL;
     }
 
-    if (mp_toradix((mp_int*)bn->internal, buf, 16) != MP_OKAY) {
-        XFREE(buf, NULL, DYNAMIC_TYPE_ECC);
+    if (mp_tohex((mp_int*)bn->internal, buf) != MP_OKAY) {
+        XFREE(buf, NULL, DYNAMIC_TYPE_OPENSSL);
         return NULL;
-    }
+            }
 
     return buf;
-}
+        }
 
 #ifndef NO_FILESYSTEM
@@ -18717,14 +23373,14 @@
  *   1 if success, 0 if error
  */
-int wolfSSL_BN_print_fp(FILE *fp, const WOLFSSL_BIGNUM *bn)
-{
+int wolfSSL_BN_print_fp(XFILE fp, const WOLFSSL_BIGNUM *bn)
+        {
     char *buf;
 
-    WOLFSSL_MSG("wolfSSL_BN_print_fp");
-
-    if (fp == NULL || bn == NULL || bn->internal == NULL) {
+    WOLFSSL_ENTER("wolfSSL_BN_print_fp");
+
+    if (fp == XBADFILE || bn == NULL || bn->internal == NULL) {
         WOLFSSL_MSG("bn NULL error");
         return WOLFSSL_FAILURE;
-    }
+            }
 
     buf = wolfSSL_BN_bn2hex(bn);
@@ -18732,40 +23388,13 @@
         WOLFSSL_MSG("wolfSSL_BN_bn2hex failure");
         return WOLFSSL_FAILURE;
-    }
+                }
 
     fprintf(fp, "%s", buf);
-    XFREE(buf, NULL, DYNAMIC_TYPE_ECC);
+    XFREE(buf, NULL, DYNAMIC_TYPE_OPENSSL);
 
     return WOLFSSL_SUCCESS;
-}
-#endif /* !defined(NO_FILESYSTEM) */
-
-#else /* defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) */
-
-char *wolfSSL_BN_bn2hex(const WOLFSSL_BIGNUM *bn)
-{
-    (void)bn;
-
-    WOLFSSL_MSG("wolfSSL_BN_bn2hex need WOLFSSL_KEY_GEN or HAVE_COMP_KEY");
-
-    return (char*)"";
-}
-
-#ifndef NO_FILESYSTEM
-/* return code compliant with OpenSSL :
- *   1 if success, 0 if error
- */
-int wolfSSL_BN_print_fp(FILE *fp, const WOLFSSL_BIGNUM *bn)
-{
-    (void)fp;
-    (void)bn;
-
-    WOLFSSL_MSG("wolfSSL_BN_print_fp not implemented");
-
-    return WOLFSSL_SUCCESS;
-}
-#endif /* !defined(NO_FILESYSTEM) */
-
-#endif /* defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) */
+            }
+#endif /* !NO_FILESYSTEM */
+
 
 WOLFSSL_BIGNUM *wolfSSL_BN_CTX_get(WOLFSSL_BN_CTX *ctx)
@@ -18777,13 +23406,68 @@
 
     return wolfSSL_BN_new();
-}
-
+        }
+
+#ifndef NO_WOLFSSL_STUB
 void wolfSSL_BN_CTX_start(WOLFSSL_BN_CTX *ctx)
-{
+        {
     (void)ctx;
 
     WOLFSSL_ENTER("wolfSSL_BN_CTX_start");
+    WOLFSSL_STUB("BN_CTX_start");
     WOLFSSL_MSG("wolfSSL_BN_CTX_start TBD");
-}
+                    }
+#endif
+
+
+WOLFSSL_BIGNUM *wolfSSL_BN_mod_inverse(WOLFSSL_BIGNUM *r,
+                                       WOLFSSL_BIGNUM *a,
+                                       const WOLFSSL_BIGNUM *n,
+                                       WOLFSSL_BN_CTX *ctx)
+{
+    int dynamic = 0;
+
+    /* ctx is not used */
+    (void)ctx;
+
+    WOLFSSL_ENTER("wolfSSL_BN_mod_inverse");
+
+    /* check parameter */
+    if (r == NULL) {
+        r = wolfSSL_BN_new();
+        if (r == NULL){
+            WOLFSSL_MSG("WolfSSL_BN_new() failed");
+            return NULL;
+        }
+        dynamic = 1;
+                }
+
+    if (a == NULL) {
+        WOLFSSL_MSG("a NULL error");
+        if (dynamic == 1) {
+            wolfSSL_BN_free(r);
+                    }
+        return NULL;
+                }
+
+    if (n == NULL) {
+        WOLFSSL_MSG("n NULL error");
+        if (dynamic == 1) {
+            wolfSSL_BN_free(r);
+            }
+        return NULL;
+        }
+
+    /* Compute inverse of a modulo n and return r */
+    if (mp_invmod((mp_int *)a->internal,(mp_int *)n->internal,
+                  (mp_int*)r->internal) == MP_VAL){
+        WOLFSSL_MSG("mp_invmod() error");
+        if (dynamic == 1) {
+            wolfSSL_BN_free(r);
+            }
+        return NULL;
+        }
+
+    return  r;
+    }
 
 #ifndef NO_DH
@@ -18831,5 +23515,5 @@
         XFREE(external, NULL, DYNAMIC_TYPE_DH);
         return NULL;
-    }
+}
     external->internal = key;
 
@@ -18847,5 +23531,5 @@
             XFREE(dh->internal, NULL, DYNAMIC_TYPE_DH);
             dh->internal = NULL;
-        }
+    }
         wolfSSL_BN_free(dh->priv_key);
         wolfSSL_BN_free(dh->pub_key);
@@ -18903,5 +23587,5 @@
             dh->inSet = 1;
             ret = WOLFSSL_SUCCESS;
-        }
+    }
 
     #ifdef WOLFSSL_SMALL_STACK
@@ -18909,5 +23593,5 @@
         XFREE(g, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
     #endif
-    }
+}
 
 
@@ -18926,4 +23610,39 @@
 
     return wolfSSL_BN_num_bytes(dh->p);
+    }
+
+
+/* This sets a big number with the 1536-bit prime from RFC 3526.
+ *
+ * bn  if not NULL then the big number structure is used. If NULL then a new
+ *     big number structure is created.
+ *
+ * Returns a WOLFSSL_BIGNUM structure on success and NULL with failure.
+ */
+WOLFSSL_BIGNUM* wolfSSL_DH_1536_prime(WOLFSSL_BIGNUM* bn)
+{
+    const char prm[] = {
+        "FFFFFFFFFFFFFFFFC90FDAA22168C234"
+        "C4C6628B80DC1CD129024E088A67CC74"
+        "020BBEA63B139B22514A08798E3404DD"
+        "EF9519B3CD3A431B302B0A6DF25F1437"
+        "4FE1356D6D51C245E485B576625E7EC6"
+        "F44C42E9A637ED6B0BFF5CB6F406B7ED"
+        "EE386BFB5A899FA5AE9F24117C4B1FE6"
+        "49286651ECE45B3DC2007CB8A163BF05"
+        "98DA48361C55D39A69163FA8FD24CF5F"
+        "83655D23DCA3AD961C62F356208552BB"
+        "9ED529077096966D670C354E4ABC9804"
+        "F1746C08CA237327FFFFFFFFFFFFFFFF"
+    };
+
+    WOLFSSL_ENTER("wolfSSL_DH_1536_prime");
+
+    if (wolfSSL_BN_hex2bn(&bn, prm) != SSL_SUCCESS) {
+        WOLFSSL_MSG("Error converting DH 1536 prime to big number");
+        return NULL;
+}
+
+    return bn;
 }
 
@@ -18935,17 +23654,15 @@
 {
     int            ret    = WOLFSSL_FAILURE;
-    word32         pubSz  = 768;
-    word32         privSz = 768;
+    word32         pubSz  = 0;
+    word32         privSz = 0;
     int            initTmpRng = 0;
     WC_RNG*        rng    = NULL;
 #ifdef WOLFSSL_SMALL_STACK
+    WC_RNG*        tmpRNG = NULL;
+#else
+    WC_RNG         tmpRNG[1];
+#endif
     unsigned char* pub    = NULL;
     unsigned char* priv   = NULL;
-    WC_RNG*        tmpRNG = NULL;
-#else
-    unsigned char  pub [768];
-    unsigned char  priv[768];
-    WC_RNG         tmpRNG[1];
-#endif
 
     WOLFSSL_MSG("wolfSSL_DH_generate_key");
@@ -18953,11 +23670,7 @@
 #ifdef WOLFSSL_SMALL_STACK
     tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG);
-    pub    = (unsigned char*)XMALLOC(pubSz,   NULL, DYNAMIC_TYPE_PUBLIC_KEY);
-    priv   = (unsigned char*)XMALLOC(privSz,  NULL, DYNAMIC_TYPE_PRIVATE_KEY);
 
     if (tmpRNG == NULL || pub == NULL || priv == NULL) {
         XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG);
-        XFREE(pub,    NULL, DYNAMIC_TYPE_PUBLIC_KEY);
-        XFREE(priv,   NULL, DYNAMIC_TYPE_PRIVATE_KEY);
         return ret;
     }
@@ -18978,11 +23691,17 @@
         else
             rng = &globalRNG;
-    }
+}
 
     if (rng) {
-       if (wc_DhGenerateKeyPair((DhKey*)dh->internal, rng, priv, &privSz,
+        pubSz = privSz = wolfSSL_BN_num_bytes(dh->p);
+        pub   = (unsigned char*)XMALLOC(pubSz,  NULL, DYNAMIC_TYPE_PUBLIC_KEY);
+        priv  = (unsigned char*)XMALLOC(privSz, NULL, DYNAMIC_TYPE_PRIVATE_KEY);
+        if (pub == NULL || priv == NULL) {
+            WOLFSSL_MSG("Unable to malloc memory");
+    }
+        else if (wc_DhGenerateKeyPair((DhKey*)dh->internal, rng, priv, &privSz,
                                                                pub, &pubSz) < 0)
             WOLFSSL_MSG("Bad wc_DhGenerateKeyPair");
-       else {
+        else {
             if (dh->pub_key)
                 wolfSSL_BN_free(dh->pub_key);
@@ -18991,5 +23710,5 @@
             if (dh->pub_key == NULL) {
                 WOLFSSL_MSG("Bad DH new pub");
-            }
+}
             if (dh->priv_key)
                 wolfSSL_BN_free(dh->priv_key);
@@ -18999,5 +23718,5 @@
             if (dh->priv_key == NULL) {
                 WOLFSSL_MSG("Bad DH new priv");
-            }
+}
 
             if (dh->pub_key && dh->priv_key) {
@@ -19009,6 +23728,6 @@
                    ret = WOLFSSL_SUCCESS;
             }
-        }
-    }
+    }
+}
 
     if (initTmpRng)
@@ -19017,7 +23736,7 @@
 #ifdef WOLFSSL_SMALL_STACK
     XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG);
+#endif
     XFREE(pub,    NULL, DYNAMIC_TYPE_PUBLIC_KEY);
     XFREE(priv,   NULL, DYNAMIC_TYPE_PRIVATE_KEY);
-#endif
 
     return ret;
@@ -19054,5 +23773,5 @@
         XFREE(pub, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
         return ret;
-    }
+        }
 #endif
 
@@ -19068,5 +23787,7 @@
         privSz = wolfSSL_BN_bn2bin(dh->priv_key, priv);
         pubSz  = wolfSSL_BN_bn2bin(otherPub, pub);
-
+        if (dh->inSet == 0 && SetDhInternal(dh) != SSL_SUCCESS){
+                WOLFSSL_MSG("Bad DH set internal");
+    }
         if (privSz <= 0 || pubSz <= 0)
             WOLFSSL_MSG("Bad BN2bin set");
@@ -19076,5 +23797,5 @@
         else
             ret = (int)keySz;
-    }
+}
 
 #ifdef WOLFSSL_SMALL_STACK
@@ -19100,5 +23821,5 @@
         dsa->inSet    = 0;
         dsa->exSet    = 0;
-    }
+}
 }
 
@@ -19115,5 +23836,5 @@
         WOLFSSL_MSG("wolfSSL_DSA_new malloc DsaKey failure");
         return NULL;
-    }
+}
 
     external = (WOLFSSL_DSA*) XMALLOC(sizeof(WOLFSSL_DSA), NULL,
@@ -19123,5 +23844,5 @@
         XFREE(key, NULL, DYNAMIC_TYPE_DSA);
         return NULL;
-    }
+}
 
     InitwolfSSL_DSA(external);
@@ -19131,5 +23852,5 @@
         wolfSSL_DSA_free(external);
         return NULL;
-    }
+}
     external->internal = key;
 
@@ -19147,5 +23868,5 @@
             XFREE(dsa->internal, NULL, DYNAMIC_TYPE_DSA);
             dsa->internal = NULL;
-        }
+}
         wolfSSL_BN_free(dsa->priv_key);
         wolfSSL_BN_free(dsa->pub_key);
@@ -19162,87 +23883,16 @@
 #endif /* NO_DSA */
 
-#ifndef NO_RSA
+#endif /* OPENSSL_EXTRA */
+#if !defined(NO_RSA) && defined(OPENSSL_EXTRA_X509_SMALL)
 static void InitwolfSSL_Rsa(WOLFSSL_RSA* rsa)
 {
     if (rsa) {
-        rsa->n        = NULL;
-        rsa->e        = NULL;
-        rsa->d        = NULL;
-        rsa->p        = NULL;
-        rsa->q        = NULL;
-        rsa->dmp1     = NULL;
-        rsa->dmq1     = NULL;
-        rsa->iqmp     = NULL;
-        rsa->internal = NULL;
-        rsa->inSet    = 0;
-        rsa->exSet    = 0;
-    }
-}
-
-
-WOLFSSL_RSA* wolfSSL_RSA_new(void)
-{
-    WOLFSSL_RSA* external;
-    RsaKey*     key;
-
-    WOLFSSL_MSG("wolfSSL_RSA_new");
-
-    key = (RsaKey*) XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_RSA);
-    if (key == NULL) {
-        WOLFSSL_MSG("wolfSSL_RSA_new malloc RsaKey failure");
-        return NULL;
-    }
-
-    external = (WOLFSSL_RSA*) XMALLOC(sizeof(WOLFSSL_RSA), NULL,
-                                     DYNAMIC_TYPE_RSA);
-    if (external == NULL) {
-        WOLFSSL_MSG("wolfSSL_RSA_new malloc WOLFSSL_RSA failure");
-        XFREE(key, NULL, DYNAMIC_TYPE_RSA);
-        return NULL;
-    }
-
-    InitwolfSSL_Rsa(external);
-    if (wc_InitRsaKey(key, NULL) != 0) {
-        WOLFSSL_MSG("InitRsaKey WOLFSSL_RSA failure");
-        XFREE(external, NULL, DYNAMIC_TYPE_RSA);
-        XFREE(key, NULL, DYNAMIC_TYPE_RSA);
-        return NULL;
-    }
-
-#if !defined(HAVE_FIPS) && !defined(HAVE_USER_RSA) && \
-    !defined(HAVE_FAST_RSA) && defined(WC_RSA_BLINDING)
-    {
-        WC_RNG* rng = NULL;
-
-        rng = (WC_RNG*) XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG);
-        if (rng != NULL && wc_InitRng(rng) != 0) {
-            WOLFSSL_MSG("InitRng failure, attempting to use global RNG");
-            XFREE(rng, NULL, DYNAMIC_TYPE_RNG);
-            rng = NULL;
-        }
-
-        if (initGlobalRNG)
-            rng = &globalRNG;
-
-        if (rng == NULL) {
-            WOLFSSL_MSG("wolfSSL_RSA_new no WC_RNG for blinding");
-            XFREE(external, NULL, DYNAMIC_TYPE_RSA);
-            XFREE(key, NULL, DYNAMIC_TYPE_RSA);
-            return NULL;
-        }
-
-        wc_RsaSetRNG(key, rng);
-    }
-#endif /* WC_RSA_BLINDING */
-
-    external->internal = key;
-
-    return external;
-}
-
+        XMEMSET(rsa, 0, sizeof(WOLFSSL_RSA));
+    }
+}
 
 void wolfSSL_RSA_free(WOLFSSL_RSA* rsa)
 {
-    WOLFSSL_MSG("wolfSSL_RSA_free");
+    WOLFSSL_ENTER("wolfSSL_RSA_free");
 
     if (rsa) {
@@ -19250,14 +23900,19 @@
 #if !defined(HAVE_FIPS) && !defined(HAVE_USER_RSA) && \
     !defined(HAVE_FAST_RSA) && defined(WC_RSA_BLINDING)
-            WC_RNG* rng = ((RsaKey*)rsa->internal)->rng;
-            if (rng != NULL && rng != &globalRNG) {
-                wc_FreeRng(rng);
-                XFREE(rng, NULL, DYNAMIC_TYPE_RNG);
-            }
+            WC_RNG* rng;
+
+            /* check if RNG is owned before freeing it */
+            if (rsa->ownRng) {
+                rng = ((RsaKey*)rsa->internal)->rng;
+                if (rng != NULL && rng != &globalRNG) {
+                    wc_FreeRng(rng);
+                    XFREE(rng, NULL, DYNAMIC_TYPE_RNG);
+    }
+    }
 #endif /* WC_RSA_BLINDING */
             wc_FreeRsaKey((RsaKey*)rsa->internal);
             XFREE(rsa->internal, NULL, DYNAMIC_TYPE_RSA);
             rsa->internal = NULL;
-        }
+    }
         wolfSSL_BN_free(rsa->iqmp);
         wolfSSL_BN_free(rsa->dmq1);
@@ -19268,4 +23923,12 @@
         wolfSSL_BN_free(rsa->e);
         wolfSSL_BN_free(rsa->n);
+
+    #ifdef WC_RSA_BLINDING
+        if (wc_FreeRng(rsa->rng) != 0) {
+            WOLFSSL_MSG("Issue freeing rng");
+}
+        XFREE(rsa->rng, NULL, DYNAMIC_TYPE_RNG);
+    #endif
+
         InitwolfSSL_Rsa(rsa);  /* set back to NULLs for safety */
 
@@ -19274,6 +23937,68 @@
     }
 }
-#endif /* NO_RSA */
-
+
+WOLFSSL_RSA* wolfSSL_RSA_new(void)
+{
+    WOLFSSL_RSA* external;
+    RsaKey*     key;
+
+    WOLFSSL_ENTER("wolfSSL_RSA_new");
+
+    key = (RsaKey*) XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_RSA);
+    if (key == NULL) {
+        WOLFSSL_MSG("wolfSSL_RSA_new malloc RsaKey failure");
+        return NULL;
+    }
+
+    external = (WOLFSSL_RSA*) XMALLOC(sizeof(WOLFSSL_RSA), NULL,
+                                     DYNAMIC_TYPE_RSA);
+    if (external == NULL) {
+        WOLFSSL_MSG("wolfSSL_RSA_new malloc WOLFSSL_RSA failure");
+        XFREE(key, NULL, DYNAMIC_TYPE_RSA);
+        return NULL;
+    }
+
+    InitwolfSSL_Rsa(external);
+    if (wc_InitRsaKey(key, NULL) != 0) {
+        WOLFSSL_MSG("InitRsaKey WOLFSSL_RSA failure");
+        XFREE(external, NULL, DYNAMIC_TYPE_RSA);
+        XFREE(key, NULL, DYNAMIC_TYPE_RSA);
+        return NULL;
+    }
+
+#if !defined(HAVE_FIPS) && !defined(HAVE_USER_RSA) && \
+    !defined(HAVE_FAST_RSA) && defined(WC_RSA_BLINDING)
+{
+        WC_RNG* rng = NULL;
+
+        rng = (WC_RNG*) XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG);
+        if (rng != NULL && wc_InitRng(rng) != 0) {
+            WOLFSSL_MSG("InitRng failure, attempting to use global RNG");
+            XFREE(rng, NULL, DYNAMIC_TYPE_RNG);
+            rng = NULL;
+}
+
+        external->ownRng = 1;
+        if (rng == NULL && initGlobalRNG) {
+            external->ownRng = 0;
+            rng = &globalRNG;
+}
+
+        if (rng == NULL) {
+            WOLFSSL_MSG("wolfSSL_RSA_new no WC_RNG for blinding");
+            XFREE(external, NULL, DYNAMIC_TYPE_RSA);
+            XFREE(key, NULL, DYNAMIC_TYPE_RSA);
+            return NULL;
+        }
+
+        wc_RsaSetRNG(key, rng);
+    }
+#endif /* WC_RSA_BLINDING */
+
+    external->internal = key;
+    external->inSet = 0;
+    return external;
+}
+#endif /* !NO_RSA && OPENSSL_EXTRA_X509_SMALL */
 
 /* these defines are to make sure the functions SetIndividualExternal is not
@@ -19281,6 +24006,8 @@
 #if !defined(NO_ASN) || !defined(NO_DSA) || defined(HAVE_ECC) || \
     (!defined(NO_RSA) && !defined(HAVE_USER_RSA) && !defined(HAVE_FAST_RSA))
+
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
 /* when calling SetIndividualExternal, mpi should be cleared by caller if no
- * longer used. ie mp_clear(mpi). This is to free data when fastmath is
+ * longer used. ie mp_free(mpi). This is to free data when fastmath is
  * disabled since a copy of mpi is made by this function and placed into bn.
  */
@@ -19294,5 +24021,5 @@
         WOLFSSL_MSG("mpi NULL error");
         return WOLFSSL_FATAL_ERROR;
-    }
+}
 
     if (*bn == NULL) {
@@ -19311,9 +24038,15 @@
         }
         return WOLFSSL_FATAL_ERROR;
-    }
+}
 
     return WOLFSSL_SUCCESS;
 }
-
+#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
+
+#ifdef OPENSSL_EXTRA /* only without X509_SMALL */
+/* when calling SetIndividualInternal, mpi should be cleared by caller if no
+ * longer used. ie mp_free(mpi). This is to free data when fastmath is
+ * disabled since a copy of mpi is made by this function and placed into bn.
+ */
 static int SetIndividualInternal(WOLFSSL_BIGNUM* bn, mp_int* mpi)
 {
@@ -19323,5 +24056,5 @@
         WOLFSSL_MSG("bn NULL error");
         return WOLFSSL_FATAL_ERROR;
-    }
+}
 
     if (mpi == NULL || (mp_init(mpi) != MP_OKAY)) {
@@ -19333,9 +24066,8 @@
         WOLFSSL_MSG("mp_copy error");
         return WOLFSSL_FATAL_ERROR;
-    }
+}
 
     return WOLFSSL_SUCCESS;
 }
-
 
 #ifndef NO_ASN
@@ -19353,5 +24085,5 @@
     }
 
-    if ((ret = GetInt(&mpi, ai->data, &idx, sizeof(ai->data))) != 0) {
+    if ((ret = GetInt(&mpi, ai->data, &idx, ai->dataMax)) != 0) {
         /* expecting ASN1 format for INTEGER */
         WOLFSSL_LEAVE("wolfSSL_ASN1_INTEGER_to_BN", ret);
@@ -19368,5 +24100,5 @@
     }
     return bn;
-}
+    }
 #endif /* !NO_ASN */
 
@@ -19406,10 +24138,10 @@
         wolfSSL_DH_free(dh);
         return NULL;
-    }
+}
     if (SetIndividualExternal(&dh->g, &key->g) != WOLFSSL_SUCCESS) {
         WOLFSSL_MSG("dsa g key error");
         wolfSSL_DH_free(dh);
         return NULL;
-    }
+}
 
     return dh;
@@ -19417,6 +24149,8 @@
 #endif /* !defined(NO_DSA) && !defined(NO_DH) */
 
+#endif /* OPENSSL_EXTRA */
 #endif /* !NO_RSA && !NO_DSA */
 
+#ifdef OPENSSL_EXTRA
 
 #ifndef NO_DSA
@@ -19473,5 +24207,5 @@
         WOLFSSL_MSG("dsa key NULL error");
         return WOLFSSL_FATAL_ERROR;
-    }
+}
 
     key = (DsaKey*)dsa->internal;
@@ -19487,5 +24221,5 @@
         WOLFSSL_MSG("rsa q key error");
         return WOLFSSL_FATAL_ERROR;
-    }
+}
 
     if (dsa->g != NULL &&
@@ -19493,5 +24227,5 @@
         WOLFSSL_MSG("rsa g key error");
         return WOLFSSL_FATAL_ERROR;
-    }
+}
 
     if (dsa->pub_key != NULL) {
@@ -19499,9 +24233,9 @@
             WOLFSSL_MSG("rsa pub_key error");
             return WOLFSSL_FATAL_ERROR;
-        }
+}
 
         /* public key */
         key->type = DSA_PUBLIC;
-    }
+}
 
     if (dsa->priv_key != NULL) {
@@ -19509,9 +24243,9 @@
             WOLFSSL_MSG("rsa priv_key error");
             return WOLFSSL_FATAL_ERROR;
-        }
+}
 
         /* private key */
         key->type = DSA_PRIVATE;
-    }
+}
 
     dsa->inSet = 1;
@@ -19520,8 +24254,8 @@
 }
 #endif /* NO_DSA */
-
-
-#if !defined(NO_RSA)
-#if !defined(HAVE_USER_RSA) && !defined(HAVE_FAST_RSA)
+#endif /* OPENSSL_EXTRA */
+
+#if !defined(HAVE_USER_RSA) && !defined(HAVE_FAST_RSA) && \
+    !defined(NO_RSA) && (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL))
 /* WolfSSL -> OpenSSL */
 static int SetRsaExternal(WOLFSSL_RSA* rsa)
@@ -19533,5 +24267,5 @@
         WOLFSSL_MSG("rsa key NULL error");
         return WOLFSSL_FATAL_ERROR;
-    }
+}
 
     key = (RsaKey*)rsa->internal;
@@ -19540,46 +24274,53 @@
         WOLFSSL_MSG("rsa n key error");
         return WOLFSSL_FATAL_ERROR;
-    }
+}
 
     if (SetIndividualExternal(&rsa->e, &key->e) != WOLFSSL_SUCCESS) {
         WOLFSSL_MSG("rsa e key error");
         return WOLFSSL_FATAL_ERROR;
-    }
-
-    if (SetIndividualExternal(&rsa->d, &key->d) != WOLFSSL_SUCCESS) {
-        WOLFSSL_MSG("rsa d key error");
-        return WOLFSSL_FATAL_ERROR;
-    }
-
-    if (SetIndividualExternal(&rsa->p, &key->p) != WOLFSSL_SUCCESS) {
-        WOLFSSL_MSG("rsa p key error");
-        return WOLFSSL_FATAL_ERROR;
-    }
-
-    if (SetIndividualExternal(&rsa->q, &key->q) != WOLFSSL_SUCCESS) {
-        WOLFSSL_MSG("rsa q key error");
-        return WOLFSSL_FATAL_ERROR;
-    }
-
-    if (SetIndividualExternal(&rsa->dmp1, &key->dP) != WOLFSSL_SUCCESS) {
-        WOLFSSL_MSG("rsa dP key error");
-        return WOLFSSL_FATAL_ERROR;
-    }
-
-    if (SetIndividualExternal(&rsa->dmq1, &key->dQ) != WOLFSSL_SUCCESS) {
-        WOLFSSL_MSG("rsa dQ key error");
-        return WOLFSSL_FATAL_ERROR;
-    }
-
-    if (SetIndividualExternal(&rsa->iqmp, &key->u) != WOLFSSL_SUCCESS) {
-        WOLFSSL_MSG("rsa u key error");
-        return WOLFSSL_FATAL_ERROR;
-    }
-
+}
+
+    if (key->type == RSA_PRIVATE) {
+        if (SetIndividualExternal(&rsa->d, &key->d) != WOLFSSL_SUCCESS) {
+            WOLFSSL_MSG("rsa d key error");
+            return WOLFSSL_FATAL_ERROR;
+}
+
+        if (SetIndividualExternal(&rsa->p, &key->p) != WOLFSSL_SUCCESS) {
+            WOLFSSL_MSG("rsa p key error");
+            return WOLFSSL_FATAL_ERROR;
+}
+
+        if (SetIndividualExternal(&rsa->q, &key->q) != WOLFSSL_SUCCESS) {
+            WOLFSSL_MSG("rsa q key error");
+            return WOLFSSL_FATAL_ERROR;
+}
+
+    #ifndef RSA_LOW_MEM
+        if (SetIndividualExternal(&rsa->dmp1, &key->dP) != WOLFSSL_SUCCESS) {
+            WOLFSSL_MSG("rsa dP key error");
+            return WOLFSSL_FATAL_ERROR;
+}
+
+        if (SetIndividualExternal(&rsa->dmq1, &key->dQ) != WOLFSSL_SUCCESS) {
+            WOLFSSL_MSG("rsa dQ key error");
+            return WOLFSSL_FATAL_ERROR;
+}
+
+        if (SetIndividualExternal(&rsa->iqmp, &key->u) != WOLFSSL_SUCCESS) {
+            WOLFSSL_MSG("rsa u key error");
+            return WOLFSSL_FATAL_ERROR;
+}
+    #endif /* !RSA_LOW_MEM */
+    }
     rsa->exSet = 1;
 
     return WOLFSSL_SUCCESS;
 }
-
+#endif
+
+#ifdef OPENSSL_EXTRA
+#if !defined(NO_RSA)
+#if !defined(HAVE_USER_RSA) && !defined(HAVE_FAST_RSA)
 /* Openssl -> WolfSSL */
 static int SetRsaInternal(WOLFSSL_RSA* rsa)
@@ -19591,5 +24332,5 @@
         WOLFSSL_MSG("rsa key NULL error");
         return WOLFSSL_FATAL_ERROR;
-    }
+}
 
     key = (RsaKey*)rsa->internal;
@@ -19598,10 +24339,10 @@
         WOLFSSL_MSG("rsa n key error");
         return WOLFSSL_FATAL_ERROR;
-    }
+}
 
     if (SetIndividualInternal(rsa->e, &key->e) != WOLFSSL_SUCCESS) {
         WOLFSSL_MSG("rsa e key error");
         return WOLFSSL_FATAL_ERROR;
-    }
+}
 
     /* public key */
@@ -19612,9 +24353,9 @@
             WOLFSSL_MSG("rsa d key error");
             return WOLFSSL_FATAL_ERROR;
-        }
+}
 
         /* private key */
         key->type = RSA_PRIVATE;
-    }
+}
 
     if (rsa->p != NULL &&
@@ -19622,5 +24363,5 @@
         WOLFSSL_MSG("rsa p key error");
         return WOLFSSL_FATAL_ERROR;
-    }
+}
 
     if (rsa->q != NULL &&
@@ -19628,11 +24369,12 @@
         WOLFSSL_MSG("rsa q key error");
         return WOLFSSL_FATAL_ERROR;
-    }
-
+}
+
+#ifndef RSA_LOW_MEM
     if (rsa->dmp1 != NULL &&
         SetIndividualInternal(rsa->dmp1, &key->dP) != WOLFSSL_SUCCESS) {
         WOLFSSL_MSG("rsa dP key error");
         return WOLFSSL_FATAL_ERROR;
-    }
+}
 
     if (rsa->dmq1 != NULL &&
@@ -19640,5 +24382,5 @@
         WOLFSSL_MSG("rsa dQ key error");
         return WOLFSSL_FATAL_ERROR;
-    }
+}
 
     if (rsa->iqmp != NULL &&
@@ -19646,5 +24388,6 @@
         WOLFSSL_MSG("rsa u key error");
         return WOLFSSL_FATAL_ERROR;
-    }
+}
+#endif /* !RSA_LOW_MEM */
 
     rsa->inSet = 1;
@@ -19652,74 +24395,18 @@
     return WOLFSSL_SUCCESS;
 }
-#endif /* HAVE_USER_RSA */
-
-/* return compliant with OpenSSL
- *   1 if success, 0 if error
- */
-int wolfSSL_RSA_generate_key_ex(WOLFSSL_RSA* rsa, int bits, WOLFSSL_BIGNUM* bn,
-                                void* cb)
-{
-    int ret = WOLFSSL_FAILURE;
-
-    (void)cb;
-    (void)bn;
-    (void)bits;
-
-    WOLFSSL_ENTER("wolfSSL_RSA_generate_key_ex");
-
-    if (rsa == NULL || rsa->internal == NULL) {
-        /* bit size checked during make key call */
-        WOLFSSL_MSG("bad arguments");
-        return WOLFSSL_FAILURE;
-    }
-
-#ifdef WOLFSSL_KEY_GEN
-    {
-    #ifdef WOLFSSL_SMALL_STACK
-        WC_RNG* rng = NULL;
-    #else
-        WC_RNG  rng[1];
-    #endif
-
-    #ifdef WOLFSSL_SMALL_STACK
-        rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG);
-        if (rng == NULL)
-            return WOLFSSL_FAILURE;
-    #endif
-
-        if (wc_InitRng(rng) < 0)
-            WOLFSSL_MSG("RNG init failed");
-        else if (wc_MakeRsaKey((RsaKey*)rsa->internal,
-                               bits, 65537, rng) != MP_OKAY)
-            WOLFSSL_MSG("wc_MakeRsaKey failed");
-        else if (SetRsaExternal(rsa) != WOLFSSL_SUCCESS)
-            WOLFSSL_MSG("SetRsaExternal failed");
-        else {
-            rsa->inSet = 1;
-            ret = WOLFSSL_SUCCESS;
-        }
-
-        wc_FreeRng(rng);
-    #ifdef WOLFSSL_SMALL_STACK
-        XFREE(rng, NULL, DYNAMIC_TYPE_RNG);
-    #endif
-    }
-#else
-    WOLFSSL_MSG("No Key Gen built in");
-#endif
-    return ret;
-}
-
-
-/* WOLFSSL_SUCCESS on ok */
+
+
+/* SSL_SUCCESS on ok */
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_RSA_blinding_on(WOLFSSL_RSA* rsa, WOLFSSL_BN_CTX* bn)
 {
     (void)rsa;
     (void)bn;
-
+    WOLFSSL_STUB("RSA_blinding_on");
     WOLFSSL_MSG("wolfSSL_RSA_blinding_on");
 
     return WOLFSSL_SUCCESS;  /* on by default */
 }
+#endif
 
 /* return compliant with OpenSSL
@@ -19729,7 +24416,8 @@
                             unsigned char* to, WOLFSSL_RSA* rsa, int padding)
 {
-    int tlen = 0;
-    int     initTmpRng = 0;
-    WC_RNG* rng = NULL;
+    int initTmpRng = 0;
+    WC_RNG *rng = NULL;
+    int outLen;
+    int ret = 0;
 #ifdef WOLFSSL_SMALL_STACK
     WC_RNG* tmpRNG = NULL;
@@ -19738,14 +24426,9 @@
 #endif
 #if !defined(HAVE_FIPS) && !defined(HAVE_USER_RSA) && !defined(HAVE_FAST_RSA)
-    int mgf = WC_MGF1NONE;
+    int  mgf = WC_MGF1NONE;
     enum wc_HashType hash = WC_HASH_TYPE_NONE;
 #endif
 
     WOLFSSL_MSG("wolfSSL_RSA_public_encrypt");
-
-    if (rsa == NULL || rsa->internal == NULL || fr == NULL) {
-        WOLFSSL_MSG("Bad function arguments");
-        return 0;
-    }
 
     /* Check and remap the padding to internal values, if needed. */
@@ -19757,5 +24440,5 @@
         hash = WC_HASH_TYPE_SHA;
         mgf = WC_MGF1SHA1;
-    }
+}
 #else
     if (padding == RSA_PKCS1_PADDING)
@@ -19768,12 +24451,12 @@
 
     if (rsa->inSet == 0)
-    {
-        WOLFSSL_MSG("No RSA internal set, do it");
-
-        if (SetRsaInternal(rsa) != WOLFSSL_SUCCESS) {
+{
+        if (SetRsaInternal(rsa) != SSL_SUCCESS) {
             WOLFSSL_MSG("SetRsaInternal failed");
             return 0;
-        }
-    }
+    }
+}
+
+    outLen = wolfSSL_RSA_size(rsa);
 
 #if !defined(HAVE_FIPS) && !defined(HAVE_USER_RSA) && \
@@ -19783,7 +24466,7 @@
     if (rng == NULL) {
 #ifdef WOLFSSL_SMALL_STACK
-        tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG);
+        tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_TMP_BUFFER);
         if (tmpRNG == NULL)
-            return WOLFSSL_FATAL_ERROR;
+    return 0;
 #endif
 
@@ -19799,30 +24482,41 @@
                 rng = &globalRNG;
         }
-    }
-
-    /* size of 'to' buffer must be size of RSA key */
+}
+
+    if (outLen == 0) {
+        WOLFSSL_MSG("Bad RSA size");
+    }
+
     if (rng) {
 #if !defined(HAVE_FIPS) && !defined(HAVE_USER_RSA) && !defined(HAVE_FAST_RSA)
-        tlen = wc_RsaPublicEncrypt_ex(fr, len, to, wolfSSL_RSA_size(rsa),
+        ret = wc_RsaPublicEncrypt_ex(fr, len, to, outLen,
                              (RsaKey*)rsa->internal, rng, padding,
                              hash, mgf, NULL, 0);
 #else
-        tlen = wc_RsaPublicEncrypt(fr, len, to, wolfSSL_RSA_size(rsa),
+        ret = wc_RsaPublicEncrypt(fr, len, to, outLen,
                              (RsaKey*)rsa->internal, rng);
 #endif
-        if (tlen <= 0) {
-            WOLFSSL_MSG("wolfSSL_RSA_public_encrypt failed");
-        }
-        else {
-            WOLFSSL_MSG("wolfSSL_RSA_public_encrypt success");
-        }
-    }
+        if (ret <= 0) {
+            WOLFSSL_MSG("Bad Rsa Encrypt");
+        }
+        if (len <= 0) {
+            WOLFSSL_MSG("Bad Rsa Encrypt");
+        }
+}
+
     if (initTmpRng)
         wc_FreeRng(tmpRNG);
 
 #ifdef WOLFSSL_SMALL_STACK
-    XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG);
-#endif
-    return tlen;
+    XFREE(tmpRNG,     NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    if (ret >= 0)
+        WOLFSSL_MSG("wolfSSL_RSA_public_encrypt success");
+    else {
+        WOLFSSL_MSG("wolfSSL_RSA_public_encrypt failed");
+        ret = WOLFSSL_FATAL_ERROR; /* return -1 on error case */
+    }
+    return ret;
 }
 
@@ -19833,18 +24527,13 @@
                             unsigned char* to, WOLFSSL_RSA* rsa, int padding)
 {
-    int tlen = 0;
-#if !defined(HAVE_FIPS) && !defined(HAVE_USER_RSA) && !defined(HAVE_FAST_RSA)
+    int outLen;
+    int ret = 0;
+  #if !defined(HAVE_FIPS) && !defined(HAVE_USER_RSA) && !defined(HAVE_FAST_RSA)
     int mgf = WC_MGF1NONE;
     enum wc_HashType hash = WC_HASH_TYPE_NONE;
-#endif
+  #endif
 
     WOLFSSL_MSG("wolfSSL_RSA_private_decrypt");
 
-    if (rsa == NULL || rsa->internal == NULL || fr == NULL) {
-        WOLFSSL_MSG("Bad function arguments");
-        return 0;
-    }
-
-    /* Check and remap the padding to internal values, if needed. */
 #if !defined(HAVE_FIPS) && !defined(HAVE_USER_RSA) && !defined(HAVE_FAST_RSA)
     if (padding == RSA_PKCS1_PADDING)
@@ -19861,34 +24550,112 @@
     else {
         WOLFSSL_MSG("wolfSSL_RSA_private_decrypt unsupported padding");
-        return 0;
-    }
+    return 0;
+}
 
     if (rsa->inSet == 0)
-    {
-        WOLFSSL_MSG("No RSA internal set, do it");
-
-        if (SetRsaInternal(rsa) != WOLFSSL_SUCCESS) {
+{
+        if (SetRsaInternal(rsa) != SSL_SUCCESS) {
             WOLFSSL_MSG("SetRsaInternal failed");
-            return 0;
-        }
+    return 0;
+}
+    }
+
+    outLen = wolfSSL_RSA_size(rsa);
+    if (outLen == 0) {
+        WOLFSSL_MSG("Bad RSA size");
     }
 
     /* size of 'to' buffer must be size of RSA key */
 #if !defined(HAVE_FIPS) && !defined(HAVE_USER_RSA) && !defined(HAVE_FAST_RSA)
-    tlen = wc_RsaPrivateDecrypt_ex(fr, len, to, wolfSSL_RSA_size(rsa),
+    ret = wc_RsaPrivateDecrypt_ex(fr, len, to, outLen,
                             (RsaKey*)rsa->internal, padding,
                             hash, mgf, NULL, 0);
 #else
-    tlen = wc_RsaPrivateDecrypt(fr, len, to, wolfSSL_RSA_size(rsa),
+    ret = wc_RsaPrivateDecrypt(fr, len, to, outLen,
                             (RsaKey*)rsa->internal);
 #endif
-    if (tlen <= 0) {
+
+    if (len <= 0) {
+        WOLFSSL_MSG("Bad Rsa Decrypt");
+    }
+
+    if (ret > 0)
+        WOLFSSL_MSG("wolfSSL_RSA_private_decrypt success");
+    else {
         WOLFSSL_MSG("wolfSSL_RSA_private_decrypt failed");
-    }
-    else {
-        WOLFSSL_MSG("wolfSSL_RSA_private_decrypt success");
-    }
-    return tlen;
-}
+        ret = WOLFSSL_FATAL_ERROR;
+    }
+    return ret;
+}
+
+
+/* RSA private encrypt calls wc_RsaSSL_Sign. Similar function set up as RSA
+ * public decrypt.
+ *
+ * len  Length of input buffer
+ * in   Input buffer to sign
+ * out  Output buffer (expected to be greater than or equal to RSA key size)
+ * rsa     Key to use for encryption
+ * padding Type of RSA padding to use.
+ */
+int wolfSSL_RSA_private_encrypt(int len, unsigned char* in,
+                            unsigned char* out, WOLFSSL_RSA* rsa, int padding)
+{
+    int sz = 0;
+    WC_RNG* rng = NULL;
+    RsaKey* key;
+
+    WOLFSSL_MSG("wolfSSL_RSA_private_encrypt");
+
+    if (len < 0 || rsa == NULL || rsa->internal == NULL || in == NULL) {
+        WOLFSSL_MSG("Bad function arguments");
+    return 0;
+}
+
+    if (padding != RSA_PKCS1_PADDING) {
+        WOLFSSL_MSG("wolfSSL_RSA_private_encrypt unsupported padding");
+    return 0;
+}
+
+    if (rsa->inSet == 0)
+{
+        WOLFSSL_MSG("Setting internal RSA structure");
+
+        if (SetRsaInternal(rsa) != SSL_SUCCESS) {
+            WOLFSSL_MSG("SetRsaInternal failed");
+    return 0;
+}
+    }
+
+    key = (RsaKey*)rsa->internal;
+    #if defined(WC_RSA_BLINDING) && !defined(HAVE_USER_RSA)
+    rng = key->rng;
+    #else
+#ifndef HAVE_FIPS
+    if (wc_InitRng_ex(rng, key->heap, INVALID_DEVID) != 0) {
+#else
+    if (wc_InitRng(rng) != 0) {
+#endif
+        WOLFSSL_MSG("Error with random number");
+        return SSL_FATAL_ERROR;
+    }
+    #endif
+
+    /* size of output buffer must be size of RSA key */
+    sz = wc_RsaSSL_Sign(in, (word32)len, out, wolfSSL_RSA_size(rsa), key, rng);
+    #if !defined(WC_RSA_BLINDING) || defined(HAVE_USER_RSA)
+    if (wc_FreeRng(rng) != 0) {
+        WOLFSSL_MSG("Error freeing random number generator");
+        return SSL_FATAL_ERROR;
+    }
+    #endif
+    if (sz <= 0) {
+        WOLFSSL_LEAVE("wolfSSL_RSA_private_encrypt", sz);
+    return 0;
+}
+
+    return sz;
+}
+#endif /* HAVE_USER_RSA */
 
 /* return compliant with OpenSSL
@@ -19897,10 +24664,130 @@
 int wolfSSL_RSA_size(const WOLFSSL_RSA* rsa)
 {
-    WOLFSSL_MSG("wolfSSL_RSA_size");
+    WOLFSSL_ENTER("wolfSSL_RSA_size");
 
     if (rsa == NULL)
         return WOLFSSL_FATAL_ERROR;
-
-    return wolfSSL_BN_num_bytes(rsa->n);
+    if (rsa->inSet == 0)
+    {
+        if (SetRsaInternal((WOLFSSL_RSA*)rsa) != SSL_SUCCESS) {
+            WOLFSSL_MSG("SetRsaInternal failed");
+    return 0;
+}
+    }
+    return wc_RsaEncryptSize((RsaKey*)rsa->internal);
+}
+
+
+/* Generates a RSA key of length len
+ *
+ * len  length of RSA key i.e. 2048
+ * e    e to use when generating RSA key
+ * f    callback function for generation details
+ * data user callback argument
+ *
+ * Note: Because of wc_MakeRsaKey an RSA key size generated can be slightly
+ *       rounded down. For example generating a key of size 2999 with e =
+ *       65537 will make a key of size 374 instead of 375.
+ * Returns a new RSA key on success and NULL on failure
+ */
+WOLFSSL_RSA* wolfSSL_RSA_generate_key(int len, unsigned long e,
+                                      void(*f)(int, int, void*), void* data)
+{
+    WOLFSSL_RSA*    rsa = NULL;
+    WOLFSSL_BIGNUM* bn  = NULL;
+
+    WOLFSSL_ENTER("wolfSSL_RSA_generate_key");
+
+    (void)f;
+    (void)data;
+
+    if (len < 0) {
+        WOLFSSL_MSG("Bad argument: length was less than 0");
+        return NULL;
+    }
+
+    bn = wolfSSL_BN_new();
+    if (bn == NULL) {
+        WOLFSSL_MSG("Error creating big number");
+        return NULL;
+    }
+
+    if (wolfSSL_BN_set_word(bn, (WOLFSSL_BN_ULONG)e) != SSL_SUCCESS) {
+        WOLFSSL_MSG("Error using e value");
+        wolfSSL_BN_free(bn);
+        return NULL;
+        }
+
+    rsa = wolfSSL_RSA_new();
+    if (rsa == NULL) {
+        WOLFSSL_MSG("memory error");
+    }
+    else {
+        if (wolfSSL_RSA_generate_key_ex(rsa, len, bn, NULL) != SSL_SUCCESS){
+            wolfSSL_RSA_free(rsa);
+            rsa = NULL;
+        }
+        }
+    wolfSSL_BN_free(bn);
+
+    return rsa;
+        }
+
+
+/* return compliant with OpenSSL
+ *   1 if success, 0 if error
+ */
+int wolfSSL_RSA_generate_key_ex(WOLFSSL_RSA* rsa, int bits, WOLFSSL_BIGNUM* bn,
+                                void* cb)
+{
+    int ret = WOLFSSL_FAILURE;
+
+    (void)cb;
+    (void)bn;
+    (void)bits;
+
+    WOLFSSL_ENTER("wolfSSL_RSA_generate_key_ex");
+
+    if (rsa == NULL || rsa->internal == NULL) {
+        /* bit size checked during make key call */
+        WOLFSSL_MSG("bad arguments");
+            return WOLFSSL_FAILURE;
+        }
+
+#ifdef WOLFSSL_KEY_GEN
+    {
+    #ifdef WOLFSSL_SMALL_STACK
+        WC_RNG* rng = NULL;
+    #else
+        WC_RNG  rng[1];
+#endif
+
+    #ifdef WOLFSSL_SMALL_STACK
+        rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG);
+        if (rng == NULL)
+            return WOLFSSL_FAILURE;
+    #endif
+
+        if (wc_InitRng(rng) < 0)
+            WOLFSSL_MSG("RNG init failed");
+        else if (wc_MakeRsaKey((RsaKey*)rsa->internal, bits,
+                    wolfSSL_BN_get_word(bn), rng) != MP_OKAY)
+            WOLFSSL_MSG("wc_MakeRsaKey failed");
+        else if (SetRsaExternal(rsa) != WOLFSSL_SUCCESS)
+            WOLFSSL_MSG("SetRsaExternal failed");
+        else {
+            rsa->inSet = 1;
+            ret = WOLFSSL_SUCCESS;
+}
+
+        wc_FreeRng(rng);
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(rng, NULL, DYNAMIC_TYPE_RNG);
+    #endif
+    }
+#else
+    WOLFSSL_MSG("No Key Gen built in");
+#endif
+    return ret;
 }
 #endif /* NO_RSA */
@@ -19928,5 +24815,5 @@
             return ret;
         }
-    }
+}
 
 #ifdef WOLFSSL_KEY_GEN
@@ -19964,5 +24851,5 @@
             else
                 ret = WOLFSSL_SUCCESS;
-        }
+}
 
         if (initTmpRng)
@@ -19978,4 +24865,32 @@
     return ret;
 }
+
+
+/* Returns a pointer to a new WOLFSSL_DSA structure on success and NULL on fail
+ */
+WOLFSSL_DSA* wolfSSL_DSA_generate_parameters(int bits, unsigned char* seed,
+        int seedLen, int* counterRet, unsigned long* hRet,
+        WOLFSSL_BN_CB cb, void* CBArg)
+{
+    WOLFSSL_DSA* dsa;
+
+    WOLFSSL_ENTER("wolfSSL_DSA_generate_parameters()");
+
+    (void)cb;
+    (void)CBArg;
+    dsa = wolfSSL_DSA_new();
+    if (dsa == NULL) {
+        return NULL;
+}
+
+    if (wolfSSL_DSA_generate_parameters_ex(dsa, bits, seed, seedLen,
+                                  counterRet, hRet, NULL) != SSL_SUCCESS) {
+        wolfSSL_DSA_free(dsa);
+        return NULL;
+    }
+
+    return dsa;
+}
+
 
 /* return code compliant with OpenSSL :
@@ -20001,8 +24916,8 @@
         WOLFSSL_MSG("Bad arguments");
         return WOLFSSL_FAILURE;
-    }
+}
 
 #ifdef WOLFSSL_KEY_GEN
-    {
+{
         int initTmpRng = 0;
         WC_RNG *rng = NULL;
@@ -20021,6 +24936,6 @@
             rng = tmpRNG;
             initTmpRng = 1;
-        }
-        else {
+    }
+    else {
             WOLFSSL_MSG("Bad RNG Init, trying global");
             if (initGlobalRNG == 0)
@@ -20046,5 +24961,5 @@
         XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG);
 #endif
-    }
+        }
 #else /* WOLFSSL_KEY_GEN */
     WOLFSSL_MSG("No Key Gen built in");
@@ -20052,5 +24967,5 @@
 
     return ret;
-}
+        }
 
 /* return WOLFSSL_SUCCESS on success, < 0 otherwise */
@@ -20072,5 +24987,5 @@
         WOLFSSL_MSG("Bad function arguments");
         return ret;
-    }
+        }
 
     if (dsa->inSet == 0)
@@ -20082,5 +24997,5 @@
             return ret;
         }
-    }
+        }
 
 #ifdef WOLFSSL_SMALL_STACK
@@ -20100,5 +25015,5 @@
         else
             rng = &globalRNG;
-    }
+}
 
     if (rng) {
@@ -20107,5 +25022,5 @@
         else
             ret = WOLFSSL_SUCCESS;
-    }
+}
 
     if (initTmpRng)
@@ -20129,5 +25044,5 @@
         WOLFSSL_MSG("Bad function arguments");
         return WOLFSSL_FATAL_ERROR;
-    }
+        }
     if (dsa->inSet == 0)
     {
@@ -20137,6 +25052,6 @@
             WOLFSSL_MSG("SetDsaInternal failed");
             return WOLFSSL_FATAL_ERROR;
-        }
-    }
+    }
+}
 
     ret = DsaVerify(d, sig, (DsaKey*)dsa->internal, dsacheck);
@@ -20151,9 +25066,31 @@
 
 
-#ifndef NO_RSA
+#if !defined(NO_RSA) && !defined(HAVE_USER_RSA)
+
+#ifdef DEBUG_SIGN
+static void show(const char *title, const unsigned char *out, unsigned int outlen)
+{
+    const unsigned char *pt;
+    printf("%s[%d] = \n", title, (int)outlen);
+    outlen = outlen>100?100:outlen;
+    for (pt = out; pt < out + outlen;
+            printf("%c", ((*pt)&0x6f)>='A'?((*pt)&0x6f):'.'), pt++);
+    printf("\n");
+}
+#else
+#define show(a,b,c)
+#endif
+
 /* return SSL_SUCCES on ok, 0 otherwise */
 int wolfSSL_RSA_sign(int type, const unsigned char* m,
                            unsigned int mLen, unsigned char* sigRet,
                            unsigned int* sigLen, WOLFSSL_RSA* rsa)
+{
+    return wolfSSL_RSA_sign_ex(type, m, mLen, sigRet, sigLen, rsa, 1);
+}
+
+int wolfSSL_RSA_sign_ex(int type, const unsigned char* m,
+                           unsigned int mLen, unsigned char* sigRet,
+                           unsigned int* sigLen, WOLFSSL_RSA* rsa, int flag)
 {
     word32  outLen;
@@ -20170,5 +25107,5 @@
 #endif
 
-    WOLFSSL_MSG("wolfSSL_RSA_sign");
+    WOLFSSL_ENTER("wolfSSL_RSA_sign");
 
     if (m == NULL || sigRet == NULL || sigLen == NULL || rsa == NULL) {
@@ -20176,4 +25113,5 @@
         return 0;
     }
+    show("Message to Sign", m, mLen);
 
     switch (type) {
@@ -20198,15 +25136,15 @@
         default:
             WOLFSSL_MSG("This NID (md type) not configured or not implemented");
-            return 0;
-    }
+    return 0;
+}
 
     if (rsa->inSet == 0)
-    {
+{
         WOLFSSL_MSG("No RSA internal set, do it");
 
         if (SetRsaInternal(rsa) != WOLFSSL_SUCCESS) {
             WOLFSSL_MSG("SetRsaInternal failed");
-            return 0;
-        }
+    return 0;
+}
     }
 
@@ -20222,6 +25160,6 @@
     if (encodedSig == NULL) {
         XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG);
-        return 0;
-    }
+    return 0;
+}
 #endif
 
@@ -20239,5 +25177,5 @@
         else
             rng = &globalRNG;
-    }
+}
 
     if (rng) {
@@ -20248,17 +25186,25 @@
         }
         else {
-            ret = wc_RsaSSL_Sign(encodedSig, signSz, sigRet, outLen,
-                                  (RsaKey*)rsa->internal, rng);
-            if (ret <= 0) {
-                WOLFSSL_MSG("Bad Rsa Sign");
-                ret = 0;
-            }
-            else {
-                ret = WOLFSSL_SUCCESS;
-                *sigLen = ret;
-            }
-        }
-
-    }
+            show("Encoded Message", encodedSig, signSz);
+            if (flag != 0) {
+                ret = wc_RsaSSL_Sign(encodedSig, signSz, sigRet, outLen,
+                                (RsaKey*)rsa->internal, rng);
+                if (ret <= 0) {
+                    WOLFSSL_MSG("Bad Rsa Sign");
+                    ret = 0;
+                }
+                else {
+                    *sigLen = (unsigned int)ret;
+                    ret = SSL_SUCCESS;
+                    show("Signature", sigRet, *sigLen);
+                }
+            } else {
+                ret = SSL_SUCCESS;
+                XMEMCPY(sigRet, encodedSig, signSz);
+                *sigLen = signSz;
+            }
+}
+
+}
 
     if (initTmpRng)
@@ -20274,8 +25220,69 @@
     else {
         WOLFSSL_MSG("wolfSSL_RSA_sign failed");
-    }
+        }
     return ret;
 }
 
+
+/* returns WOLFSSL_SUCCESS on successful verify and WOLFSSL_FAILURE on fail */
+int wolfSSL_RSA_verify(int type, const unsigned char* m,
+                               unsigned int mLen, const unsigned char* sig,
+                               unsigned int sigLen, WOLFSSL_RSA* rsa)
+{
+    int     ret;
+    unsigned char *sigRet ;
+    unsigned char *sigDec ;
+    unsigned int   len;
+
+    WOLFSSL_ENTER("wolfSSL_RSA_verify");
+    if ((m == NULL) || (sig == NULL)) {
+        WOLFSSL_MSG("Bad function arguments");
+        return WOLFSSL_FAILURE;
+    }
+
+    sigRet = (unsigned char *)XMALLOC(sigLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (sigRet == NULL) {
+        WOLFSSL_MSG("Memory failure");
+        return WOLFSSL_FAILURE;
+    }
+    sigDec = (unsigned char *)XMALLOC(sigLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (sigDec == NULL) {
+        WOLFSSL_MSG("Memory failure");
+        XFREE(sigRet, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return WOLFSSL_FAILURE;
+    }
+    /* get non-encrypted signature to be compared with decrypted sugnature*/
+    ret = wolfSSL_RSA_sign_ex(type, m, mLen, sigRet, &len, rsa, 0);
+    if (ret <= 0) {
+        WOLFSSL_MSG("Message Digest Error");
+        XFREE(sigRet, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(sigDec, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return WOLFSSL_FAILURE;
+    }
+    show("Encoded Message", sigRet, len);
+    /* decrypt signature */
+    ret = wc_RsaSSL_Verify(sig, sigLen, (unsigned char *)sigDec, sigLen,
+        (RsaKey*)rsa->internal);
+    if (ret <= 0) {
+        WOLFSSL_MSG("RSA Decrypt error");
+        XFREE(sigRet, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(sigDec, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return WOLFSSL_FAILURE;
+    }
+    show("Decrypted Signature", sigDec, ret);
+
+    if ((int)len == ret && XMEMCMP(sigRet, sigDec, ret) == 0) {
+        WOLFSSL_MSG("wolfSSL_RSA_verify success");
+        XFREE(sigRet, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(sigDec, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return WOLFSSL_SUCCESS;
+    }
+    else {
+        WOLFSSL_MSG("wolfSSL_RSA_verify failed");
+        XFREE(sigRet, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(sigDec, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return WOLFSSL_FAILURE;
+    }
+}
 
 int wolfSSL_RSA_public_decrypt(int flen, const unsigned char* from,
@@ -20284,5 +25291,5 @@
     int tlen = 0;
 
-    WOLFSSL_MSG("wolfSSL_RSA_public_decrypt");
+    WOLFSSL_ENTER("wolfSSL_RSA_public_decrypt");
 
     if (rsa == NULL || rsa->internal == NULL || from == NULL) {
@@ -20347,10 +25354,10 @@
     if (err != MP_OKAY) {
         WOLFSSL_MSG("mp_mod error");
-    }
+        }
     else
         err = mp_sub_d((mp_int*)rsa->q->internal, 1, &tmp);
     if (err != MP_OKAY) {
         WOLFSSL_MSG("mp_sub_d error");
-    }
+        }
     else
         err = mp_mod((mp_int*)rsa->d->internal, &tmp,
@@ -20363,37 +25370,283 @@
     else
         return WOLFSSL_FATAL_ERROR;
-}
+    }
 #endif /* NO_RSA */
 
-
-void wolfSSL_HMAC_Init(WOLFSSL_HMAC_CTX* ctx, const void* key, int keylen,
+int wolfSSL_HMAC_CTX_Init(WOLFSSL_HMAC_CTX* ctx)
+{
+    WOLFSSL_MSG("wolfSSL_HMAC_CTX_Init");
+
+    if (ctx != NULL) {
+        /* wc_HmacSetKey sets up ctx->hmac */
+        XMEMSET(ctx, 0, sizeof(WOLFSSL_HMAC_CTX));
+    }
+
+    return WOLFSSL_SUCCESS;
+    }
+
+
+int wolfSSL_HMAC_Init_ex(WOLFSSL_HMAC_CTX* ctx, const void* key,
+                             int keylen, const EVP_MD* type, WOLFSSL_ENGINE* e)
+{
+    WOLFSSL_ENTER("wolfSSL_HMAC_Init_ex");
+
+    /* WOLFSSL_ENGINE not used, call wolfSSL_HMAC_Init */
+    (void)e;
+    return wolfSSL_HMAC_Init(ctx, key, keylen, type);
+    }
+
+
+/* helper function for Deep copy of internal wolfSSL hmac structure
+ * returns WOLFSSL_SUCCESS on success */
+int wolfSSL_HmacCopy(Hmac* des, Hmac* src)
+{
+    int ret    = 0;
+    void* heap = NULL;
+
+#ifndef HAVE_FIPS
+    heap = src->heap;
+#endif
+    if ((ret = wc_HmacInit(des, heap, 0)) != 0) {
+        return WOLFSSL_FAILURE;
+    }
+
+    /* requires that hash structures have no dynamic parts to them */
+    switch (src->macType) {
+    #ifndef NO_MD5
+        case WC_MD5:
+            wc_Md5Copy(&src->hash.md5, &des->hash.md5);
+            break;
+    #endif /* !NO_MD5 */
+
+    #ifndef NO_SHA
+        case WC_SHA:
+            wc_ShaCopy(&src->hash.sha, &des->hash.sha);
+            break;
+    #endif /* !NO_SHA */
+
+    #ifdef WOLFSSL_SHA224
+        case WC_SHA224:
+            wc_Sha224Copy(&src->hash.sha224, &des->hash.sha224);
+            break;
+    #endif /* WOLFSSL_SHA224 */
+
+    #ifndef NO_SHA256
+        case WC_SHA256:
+            wc_Sha256Copy(&src->hash.sha256, &des->hash.sha256);
+            break;
+    #endif /* !NO_SHA256 */
+
+    #ifdef WOLFSSL_SHA384
+        case WC_SHA384:
+            wc_Sha384Copy(&src->hash.sha384, &des->hash.sha384);
+            break;
+    #endif /* WOLFSSL_SHA384 */
+    #ifdef WOLFSSL_SHA512
+        case WC_SHA512:
+            wc_Sha512Copy(&src->hash.sha512, &des->hash.sha512);
+            break;
+    #endif /* WOLFSSL_SHA512 */
+
+        default:
+            return WOLFSSL_FAILURE;
+    }
+
+    XMEMCPY((byte*)des->ipad, (byte*)src->ipad, WC_HMAC_BLOCK_SIZE);
+    XMEMCPY((byte*)des->opad, (byte*)src->opad, WC_HMAC_BLOCK_SIZE);
+    XMEMCPY((byte*)des->innerHash, (byte*)src->innerHash, WC_MAX_DIGEST_SIZE);
+#ifndef HAVE_FIPS
+    des->heap    = heap;
+#endif
+    des->macType = src->macType;
+    des->innerHashKeyed = src->innerHashKeyed;
+
+#ifdef WOLFSSL_ASYNC_CRYPT
+    XMEMCPY(&des->asyncDev, &src->asyncDev, sizeof(WC_ASYNC_DEV));
+    des->keyLen = src->keyLen;
+    #ifdef HAVE_CAVIUM
+        des->data = (byte*)XMALLOC(src->dataLen, des->heap,
+                DYNAMIC_TYPE_HMAC);
+        if (des->data == NULL) {
+            return BUFFER_E;
+        }
+        XMEMCPY(des->data, src->data, src->dataLen);
+        des->dataLen = src->dataLen;
+    #endif /* HAVE_CAVIUM */
+#endif /* WOLFSSL_ASYNC_CRYPT */
+        return WOLFSSL_SUCCESS;
+}
+
+
+/* Deep copy of information from src to des structure
+ *
+ * des destination to copy information to
+ * src structure to get infromation from
+ *
+ * Returns WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on error
+ */
+int wolfSSL_HMAC_CTX_copy(WOLFSSL_HMAC_CTX* des, WOLFSSL_HMAC_CTX* src)
+{
+    WOLFSSL_ENTER("wolfSSL_HMAC_CTX_copy");
+
+    if (des == NULL || src == NULL) {
+        return WOLFSSL_FAILURE;
+}
+
+    des->type = src->type;
+    XMEMCPY((byte *)&des->save_ipad, (byte *)&src->hmac.ipad,
+                                        WC_HMAC_BLOCK_SIZE);
+    XMEMCPY((byte *)&des->save_opad, (byte *)&src->hmac.opad,
+                                        WC_HMAC_BLOCK_SIZE);
+
+    return wolfSSL_HmacCopy(&des->hmac, &src->hmac);
+}
+
+
+#if defined(HAVE_FIPS) && \
+    (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))
+
+static int _HMAC_Init(Hmac* hmac, int type, void* heap)
+{
+    int ret = 0;
+
+    switch (type) {
+    #ifndef NO_MD5
+        case WC_MD5:
+            ret = wc_InitMd5(&hmac->hash.md5);
+            break;
+    #endif /* !NO_MD5 */
+
+    #ifndef NO_SHA
+        case WC_SHA:
+            ret = wc_InitSha(&hmac->hash.sha);
+            break;
+    #endif /* !NO_SHA */
+
+    #ifdef WOLFSSL_SHA224
+        case WC_SHA224:
+            ret = wc_InitSha224(&hmac->hash.sha224);
+            break;
+    #endif /* WOLFSSL_SHA224 */
+
+    #ifndef NO_SHA256
+        case WC_SHA256:
+            ret = wc_InitSha256(&hmac->hash.sha256);
+            break;
+    #endif /* !NO_SHA256 */
+
+    #ifdef WOLFSSL_SHA384
+        case WC_SHA384:
+            ret = wc_InitSha384(&hmac->hash.sha384);
+            break;
+    #endif /* WOLFSSL_SHA384 */
+    #ifdef WOLFSSL_SHA512
+        case WC_SHA512:
+            ret = wc_InitSha512(&hmac->hash.sha512);
+            break;
+    #endif /* WOLFSSL_SHA512 */
+
+    #ifdef HAVE_BLAKE2
+        case BLAKE2B_ID:
+            ret = wc_InitBlake2b(&hmac->hash.blake2b, BLAKE2B_256);
+            break;
+    #endif /* HAVE_BLAKE2 */
+
+    #ifdef WOLFSSL_SHA3
+        case WC_SHA3_224:
+            ret = wc_InitSha3_224(&hmac->hash.sha3, heap, INVALID_DEVID);
+            break;
+        case WC_SHA3_256:
+            ret = wc_InitSha3_256(&hmac->hash.sha3, heap, INVALID_DEVID);
+            break;
+        case WC_SHA3_384:
+            ret = wc_InitSha3_384(&hmac->hash.sha3, heap, INVALID_DEVID);
+            break;
+        case WC_SHA3_512:
+            ret = wc_InitSha3_512(&hmac->hash.sha3, heap, INVALID_DEVID);
+            break;
+    #endif
+
+        default:
+            ret = BAD_FUNC_ARG;
+            break;
+}
+
+    (void)heap;
+
+    return ret;
+}
+
+    #else
+    #define _HMAC_Init _InitHmac
+    #endif
+
+
+int wolfSSL_HMAC_Init(WOLFSSL_HMAC_CTX* ctx, const void* key, int keylen,
                   const EVP_MD* type)
 {
+    int hmac_error = 0;
+    void* heap = NULL;
+
     WOLFSSL_MSG("wolfSSL_HMAC_Init");
 
     if (ctx == NULL) {
         WOLFSSL_MSG("no ctx on init");
-        return;
-    }
+        return WOLFSSL_FAILURE;
+        }
+
+#ifndef HAVE_FIPS
+    heap = ctx->hmac.heap;
+#endif
 
     if (type) {
         WOLFSSL_MSG("init has type");
 
+#ifndef NO_MD5
         if (XSTRNCMP(type, "MD5", 3) == 0) {
             WOLFSSL_MSG("md5 hmac");
             ctx->type = WC_MD5;
         }
-        else if (XSTRNCMP(type, "SHA256", 6) == 0) {
+        else
+#endif
+#ifdef WOLFSSL_SHA224
+        if (XSTRNCMP(type, "SHA224", 6) == 0) {
+            WOLFSSL_MSG("sha224 hmac");
+            ctx->type = WC_SHA224;
+        }
+        else
+#endif
+#ifndef NO_SHA256
+        if (XSTRNCMP(type, "SHA256", 6) == 0) {
             WOLFSSL_MSG("sha256 hmac");
             ctx->type = WC_SHA256;
         }
-
+        else
+#endif
+#ifdef WOLFSSL_SHA384
+        if (XSTRNCMP(type, "SHA384", 6) == 0) {
+            WOLFSSL_MSG("sha384 hmac");
+            ctx->type = WC_SHA384;
+        }
+        else
+#endif
+#ifdef WOLFSSL_SHA512
+        if (XSTRNCMP(type, "SHA512", 6) == 0) {
+            WOLFSSL_MSG("sha512 hmac");
+            ctx->type = WC_SHA512;
+        }
+        else
+#endif
+
+#ifndef NO_SHA
         /* has to be last since would pick or 256, 384, or 512 too */
-        else if (XSTRNCMP(type, "SHA", 3) == 0) {
+        if (XSTRNCMP(type, "SHA", 3) == 0) {
             WOLFSSL_MSG("sha hmac");
             ctx->type = WC_SHA;
         }
-        else {
+        else
+    #endif
+        {
             WOLFSSL_MSG("bad init type");
+            return WOLFSSL_FAILURE;
         }
     }
@@ -20403,67 +25656,134 @@
 
         if (wc_HmacInit(&ctx->hmac, NULL, INVALID_DEVID) == 0) {
-            wc_HmacSetKey(&ctx->hmac, ctx->type, (const byte*)key,
-                                                        (word32)keylen);
+            hmac_error = wc_HmacSetKey(&ctx->hmac, ctx->type, (const byte*)key,
+                                       (word32)keylen);
+            if (hmac_error < 0){
+                wc_HmacFree(&ctx->hmac);
+                return WOLFSSL_FAILURE;
+            }
+            XMEMCPY((byte *)&ctx->save_ipad, (byte *)&ctx->hmac.ipad,
+                                        WC_HMAC_BLOCK_SIZE);
+            XMEMCPY((byte *)&ctx->save_opad, (byte *)&ctx->hmac.opad,
+                                        WC_HMAC_BLOCK_SIZE);
         }
         /* OpenSSL compat, no error */
-    }
-}
-
-int wolfSSL_HMAC_Init_ex(WOLFSSL_HMAC_CTX* ctx, const void* key, int len,
-                         const EVP_MD* md, void* impl)
-{
-    (void)impl;
-    wolfSSL_HMAC_Init(ctx, key, len, md);
-    return 1;
-}
-
-
-void wolfSSL_HMAC_Update(WOLFSSL_HMAC_CTX* ctx, const unsigned char* data,
+    } else if(ctx->type >= 0) { /* MD5 == 0 */
+        WOLFSSL_MSG("recover hmac");
+        wc_HmacFree(&ctx->hmac);
+        if (wc_HmacInit(&ctx->hmac, NULL, INVALID_DEVID) == 0) {
+            ctx->hmac.macType = (byte)ctx->type;
+            ctx->hmac.innerHashKeyed = 0;
+            XMEMCPY((byte *)&ctx->hmac.ipad, (byte *)&ctx->save_ipad,
+                                       WC_HMAC_BLOCK_SIZE);
+            XMEMCPY((byte *)&ctx->hmac.opad, (byte *)&ctx->save_opad,
+                                       WC_HMAC_BLOCK_SIZE);
+            if ((hmac_error = _HMAC_Init(&ctx->hmac, ctx->hmac.macType, heap))
+                    !=0) {
+               return hmac_error;
+            }
+        }
+    }
+
+    (void)hmac_error;
+
+    return WOLFSSL_SUCCESS;
+}
+
+
+int wolfSSL_HMAC_Update(WOLFSSL_HMAC_CTX* ctx, const unsigned char* data,
                     int len)
-{
+            {
+    int hmac_error = 0;
+
     WOLFSSL_MSG("wolfSSL_HMAC_Update");
 
-    if (ctx && data) {
+    if (ctx == NULL) {
+        WOLFSSL_MSG("no ctx");
+        return WOLFSSL_FAILURE;
+            }
+
+    if (data) {
         WOLFSSL_MSG("updating hmac");
-        wc_HmacUpdate(&ctx->hmac, data, (word32)len);
-        /* OpenSSL compat, no error */
-    }
-}
-
-
-void wolfSSL_HMAC_Final(WOLFSSL_HMAC_CTX* ctx, unsigned char* hash,
+        hmac_error = wc_HmacUpdate(&ctx->hmac, data, (word32)len);
+        if (hmac_error < 0){
+            WOLFSSL_MSG("hmac update error");
+            return WOLFSSL_FAILURE;
+        }
+        }
+
+    return WOLFSSL_SUCCESS;
+}
+
+
+int wolfSSL_HMAC_Final(WOLFSSL_HMAC_CTX* ctx, unsigned char* hash,
                    unsigned int* len)
 {
+    int hmac_error;
+
     WOLFSSL_MSG("wolfSSL_HMAC_Final");
 
-    if (ctx && hash) {
-        WOLFSSL_MSG("final hmac");
-        wc_HmacFinal(&ctx->hmac, hash);
-        /* OpenSSL compat, no error */
-
-        if (len) {
-            WOLFSSL_MSG("setting output len");
-            switch (ctx->type) {
-                case WC_MD5:
-                    *len = WC_MD5_DIGEST_SIZE;
-                    break;
-
-                case WC_SHA:
-                    *len = WC_SHA_DIGEST_SIZE;
-                    break;
-
-                case WC_SHA256:
-                    *len = WC_SHA256_DIGEST_SIZE;
-                    break;
-
-                default:
-                    WOLFSSL_MSG("bad hmac type");
-            }
-        }
-    }
-}
-
-
-void wolfSSL_HMAC_cleanup(WOLFSSL_HMAC_CTX* ctx)
+    /* "len" parameter is optional. */
+    if (ctx == NULL || hash == NULL) {
+        WOLFSSL_MSG("invalid parameter");
+        return WOLFSSL_FAILURE;
+    }
+
+    WOLFSSL_MSG("final hmac");
+    hmac_error = wc_HmacFinal(&ctx->hmac, hash);
+    if (hmac_error < 0){
+        WOLFSSL_MSG("final hmac error");
+        return WOLFSSL_FAILURE;
+}
+
+    if (len) {
+        WOLFSSL_MSG("setting output len");
+        switch (ctx->type) {
+            #ifndef NO_MD5
+            case WC_MD5:
+                *len = WC_MD5_DIGEST_SIZE;
+                break;
+#endif
+
+            #ifndef NO_SHA
+            case WC_SHA:
+                *len = WC_SHA_DIGEST_SIZE;
+                break;
+            #endif
+
+            #ifdef WOLFSSL_SHA224
+            case WC_SHA224:
+                *len = WC_SHA224_DIGEST_SIZE;
+                break;
+            #endif
+
+            #ifndef NO_SHA256
+            case WC_SHA256:
+                *len = WC_SHA256_DIGEST_SIZE;
+                break;
+            #endif
+
+            #ifdef WOLFSSL_SHA384
+            case WC_SHA384:
+                *len = WC_SHA384_DIGEST_SIZE;
+                break;
+            #endif
+
+            #ifdef WOLFSSL_SHA512
+            case WC_SHA512:
+                *len = WC_SHA512_DIGEST_SIZE;
+                break;
+            #endif
+
+            default:
+                WOLFSSL_MSG("bad hmac type");
+                return WOLFSSL_FAILURE;
+        }
+    }
+
+    return WOLFSSL_SUCCESS;
+}
+
+
+int wolfSSL_HMAC_cleanup(WOLFSSL_HMAC_CTX* ctx)
 {
     WOLFSSL_MSG("wolfSSL_HMAC_cleanup");
@@ -20471,5 +25791,7 @@
     if (ctx)
         wc_HmacFree(&ctx->hmac);
-}
+
+    return SSL_SUCCESS;
+    }
 
 
@@ -20495,30 +25817,88 @@
 
 
+#ifndef NO_RSA
 WOLFSSL_RSA* wolfSSL_EVP_PKEY_get1_RSA(WOLFSSL_EVP_PKEY* key)
 {
-    (void)key;
-    WOLFSSL_MSG("wolfSSL_EVP_PKEY_get1_RSA not implemented");
-
-    return NULL;
-}
-
-
+    WOLFSSL_RSA* local;
+
+    WOLFSSL_MSG("wolfSSL_EVP_PKEY_get1_RSA");
+
+    if (key == NULL) {
+        return NULL;
+}
+
+    local = wolfSSL_RSA_new();
+    if (local == NULL) {
+        WOLFSSL_MSG("Error creating a new WOLFSSL_RSA structure");
+        return NULL;
+}
+
+    if (key->type == EVP_PKEY_RSA) {
+        if (wolfSSL_RSA_LoadDer(local, (const unsigned char*)key->pkey.ptr,
+                    key->pkey_sz) != SSL_SUCCESS) {
+            /* now try public key */
+            if (wolfSSL_RSA_LoadDer_ex(local,
+                        (const unsigned char*)key->pkey.ptr, key->pkey_sz,
+                        WOLFSSL_RSA_LOAD_PUBLIC) != SSL_SUCCESS) {
+                wolfSSL_RSA_free(local);
+                local = NULL;
+            }
+        }
+    }
+    else {
+        WOLFSSL_MSG("WOLFSSL_EVP_PKEY does not hold an RSA key");
+        wolfSSL_RSA_free(local);
+        local = NULL;
+    }
+    return local;
+}
+
+
+/* with set1 functions the pkey struct does not own the RSA structure
+ *
+ * returns WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on failure
+ */
+int wolfSSL_EVP_PKEY_set1_RSA(WOLFSSL_EVP_PKEY *pkey, WOLFSSL_RSA *key)
+{
+    if((pkey == NULL) || (key ==NULL))return WOLFSSL_FAILURE;
+    WOLFSSL_ENTER("wolfSSL_EVP_PKEY_set1_RSA");
+    if (pkey->rsa != NULL && pkey->ownRsa == 1) {
+        wolfSSL_RSA_free(pkey->rsa);
+    }
+    pkey->rsa    = key;
+    pkey->ownRsa = 0; /* pkey does not own RSA */
+    pkey->type = EVP_PKEY_RSA;
+#ifdef WC_RSA_BLINDING
+    if (key->ownRng == 0) {
+        if (wc_RsaSetRNG((RsaKey*)(pkey->rsa->internal), &(pkey->rng)) != 0) {
+            WOLFSSL_MSG("Error setting RSA rng");
+            return SSL_FAILURE;
+    }
+}
+#endif
+    return WOLFSSL_SUCCESS;
+}
+#endif /* NO_RSA */
+
+#ifndef NO_WOLFSSL_STUB
 WOLFSSL_DSA* wolfSSL_EVP_PKEY_get1_DSA(WOLFSSL_EVP_PKEY* key)
 {
     (void)key;
     WOLFSSL_MSG("wolfSSL_EVP_PKEY_get1_DSA not implemented");
-
-    return NULL;
-}
-
-
+    WOLFSSL_STUB("EVP_PKEY_get1_DSA");
+        return NULL;
+    }
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 WOLFSSL_EC_KEY* wolfSSL_EVP_PKEY_get1_EC_KEY(WOLFSSL_EVP_PKEY* key)
 {
     (void)key;
+    WOLFSSL_STUB("EVP_PKEY_get1_EC_KEY");
     WOLFSSL_MSG("wolfSSL_EVP_PKEY_get1_EC_KEY not implemented");
 
-    return NULL;
-}
-
+        return NULL;
+    }
+#endif
 
 void* wolfSSL_EVP_X_STATE(const WOLFSSL_EVP_CIPHER_CTX* ctx)
@@ -20600,5 +25980,5 @@
 
     if (doset)
-        wc_AesSetIV(&ctx->cipher.aes, iv);  /* OpenSSL compat, no ret */
+       (void)wc_AesSetIV(&ctx->cipher.aes, iv);  /* OpenSSL compat, no ret */
     else
         XMEMCPY(iv, &ctx->cipher.aes.reg, AES_BLOCK_SIZE);
@@ -20607,12 +25987,12 @@
 #endif /* NO_AES */
 
-
+#ifndef NO_WOLFSSL_STUB
 const WOLFSSL_EVP_MD* wolfSSL_EVP_ripemd160(void)
 {
     WOLFSSL_MSG("wolfSSL_ripemd160");
-
+    WOLFSSL_STUB("EVP_ripemd160");
     return NULL;
 }
-
+#endif
 
 int wolfSSL_EVP_MD_size(const WOLFSSL_EVP_MD* type)
@@ -20665,4 +26045,5 @@
     switch (ctx->cipherType) {
 
+#ifdef HAVE_AES_CBC
         case AES_128_CBC_TYPE :
         case AES_192_CBC_TYPE :
@@ -20670,5 +26051,5 @@
             WOLFSSL_MSG("AES CBC");
             return AES_BLOCK_SIZE;
-
+#endif
 #ifdef WOLFSSL_AES_COUNTER
         case AES_128_CTR_TYPE :
@@ -20678,5 +26059,5 @@
             return AES_BLOCK_SIZE;
 #endif
-
+#ifndef NO_DES3
         case DES_CBC_TYPE :
             WOLFSSL_MSG("DES CBC");
@@ -20686,4 +26067,5 @@
             WOLFSSL_MSG("DES EDE3 CBC");
             return DES_BLOCK_SIZE;
+#endif
 #ifdef HAVE_IDEA
         case IDEA_CBC_TYPE :
@@ -20691,7 +26073,9 @@
             return IDEA_BLOCK_SIZE;
 #endif
+#ifndef NO_RC4
         case ARC4_TYPE :
             WOLFSSL_MSG("ARC4");
             return 0;
+#endif
 
         case NULL_CIPHER_TYPE :
@@ -20712,15 +26096,31 @@
 
 #ifndef NO_AES
-    if ((XSTRNCMP(name, EVP_AES_128_CBC, XSTRLEN(EVP_AES_128_CBC)) == 0) ||
-           (XSTRNCMP(name, EVP_AES_192_CBC, XSTRLEN(EVP_AES_192_CBC)) == 0) ||
-           (XSTRNCMP(name, EVP_AES_256_CBC, XSTRLEN(EVP_AES_256_CBC)) == 0)) {
+#ifdef HAVE_AES_CBC
+    #ifdef WOLFSSL_AES_128
+    if (XSTRNCMP(name, EVP_AES_128_CBC, XSTRLEN(EVP_AES_128_CBC)) == 0)
         return AES_BLOCK_SIZE;
-    }
+    #endif
+    #ifdef WOLFSSL_AES_192
+    if (XSTRNCMP(name, EVP_AES_192_CBC, XSTRLEN(EVP_AES_192_CBC)) == 0)
+        return AES_BLOCK_SIZE;
+    #endif
+    #ifdef WOLFSSL_AES_256
+    if (XSTRNCMP(name, EVP_AES_256_CBC, XSTRLEN(EVP_AES_256_CBC)) == 0)
+        return AES_BLOCK_SIZE;
+    #endif
+#endif /* HAVE_AES_CBC */
 #ifdef WOLFSSL_AES_COUNTER
-    if ((XSTRNCMP(name, EVP_AES_128_CTR, XSTRLEN(EVP_AES_128_CTR)) == 0) ||
-           (XSTRNCMP(name, EVP_AES_192_CTR, XSTRLEN(EVP_AES_192_CTR)) == 0) ||
-           (XSTRNCMP(name, EVP_AES_256_CTR, XSTRLEN(EVP_AES_256_CTR)) == 0)) {
+    #ifdef WOLFSSL_AES_128
+    if (XSTRNCMP(name, EVP_AES_128_CTR, XSTRLEN(EVP_AES_128_CTR)) == 0)
         return AES_BLOCK_SIZE;
-    }
+    #endif
+    #ifdef WOLFSSL_AES_192
+    if (XSTRNCMP(name, EVP_AES_192_CTR, XSTRLEN(EVP_AES_192_CTR)) == 0)
+        return AES_BLOCK_SIZE;
+    #endif
+    #ifdef WOLFSSL_AES_256
+    if (XSTRNCMP(name, EVP_AES_256_CTR, XSTRLEN(EVP_AES_256_CTR)) == 0)
+        return AES_BLOCK_SIZE;
+    #endif
 #endif
 #endif
@@ -20730,5 +26130,5 @@
            (XSTRNCMP(name, EVP_DES_EDE3_CBC, XSTRLEN(EVP_DES_EDE3_CBC)) == 0)) {
         return DES_BLOCK_SIZE;
-    }
+}
 #endif
 
@@ -20754,5 +26154,10 @@
 }
 
-#if defined(WOLFSSL_KEY_GEN)
+void *wolfSSL_OPENSSL_malloc(size_t a)
+{
+  return XMALLOC(a, NULL, DYNAMIC_TYPE_OPENSSL);
+}
+
+#if defined(WOLFSSL_KEY_GEN) && defined(WOLFSSL_PEM_TO_DER)
 
 static int EncryptDerKey(byte *der, int *derSz, const EVP_CIPHER* cipher,
@@ -20778,27 +26183,22 @@
     if (info == NULL) {
         WOLFSSL_MSG("malloc failed");
+    return WOLFSSL_FAILURE;
+}
+#endif
+
+    XMEMSET(info, 0, sizeof(EncryptedInfo));
+
+    /* set the cipher name on info */
+    XSTRNCPY(info->name, cipher, NAME_SZ-1);
+    info->name[NAME_SZ-1] = '\0'; /* null term */
+
+    ret = wc_EncryptedInfoGet(info, info->name);
+    if (ret != 0) {
+        WOLFSSL_MSG("unsupported cipher");
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO);
+    #endif
         return WOLFSSL_FAILURE;
     }
-#endif
-    info->set      = 0;
-    info->ctx      = NULL;
-    info->consumed = 0;
-
-    /* set iv size */
-    if (XSTRNCMP(cipher, "DES", 3) == 0)
-        info->ivSz = DES_IV_SIZE;
-    else if (XSTRNCMP(cipher, "AES", 3) == 0)
-        info->ivSz = AES_IV_SIZE;
-    else {
-        WOLFSSL_MSG("unsupported cipher");
-#ifdef WOLFSSL_SMALL_STACK
-        XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO);
-#endif
-        return WOLFSSL_FAILURE;
-    }
-
-    /* set the cipher name on info */
-    XSTRNCPY(info->name, cipher, NAME_SZ);
-    info->name[NAME_SZ-1] = '\0'; /* null term */
 
     /* Generate a random salt */
@@ -20809,5 +26209,5 @@
 #endif
         return WOLFSSL_FAILURE;
-    }
+}
 
     /* add the padding before encryption */
@@ -20819,6 +26219,5 @@
 
     /* encrypt buffer */
-    if (wolfssl_encrypt_buffer_key(der, *derSz,
-                                   passwd, passwdSz, info) != WOLFSSL_SUCCESS) {
+    if (wc_BufferKeyEncrypt(info, der, *derSz, passwd, passwdSz, WC_MD5) != 0) {
         WOLFSSL_MSG("encrypt key failed");
 #ifdef WOLFSSL_SMALL_STACK
@@ -20840,5 +26239,5 @@
     }
     XSTRNCPY((char*)*cipherInfo, info->name, cipherInfoSz);
-    XSTRNCAT((char*)*cipherInfo, ",", 1);
+    XSTRNCAT((char*)*cipherInfo, ",", 2);
 
     idx = (word32)XSTRLEN((char*)*cipherInfo);
@@ -20853,11 +26252,91 @@
         XFREE(*cipherInfo, NULL, DYNAMIC_TYPE_STRING);
         return WOLFSSL_FAILURE;
-    }
+}
 
     return WOLFSSL_SUCCESS;
 }
-#endif /* defined(WOLFSSL_KEY_GEN) */
+#endif /* WOLFSSL_KEY_GEN || WOLFSSL_PEM_TO_DER */
 
 #if defined(WOLFSSL_KEY_GEN) || defined(WOLFSSL_CERT_GEN)
+/* Takes a WOLFSSL_RSA key and writes it out to a WOLFSSL_BIO
+ *
+ * bio    the WOLFSSL_BIO to write to
+ * key    the WOLFSSL_RSA key to write out
+ * cipher cipher used
+ * passwd password string if used
+ * len    length of password string
+ * cb     password callback to use
+ * arg    null terminated string for passphrase
+ */
+int wolfSSL_PEM_write_bio_RSAPrivateKey(WOLFSSL_BIO* bio, WOLFSSL_RSA* key,
+                                        const WOLFSSL_EVP_CIPHER* cipher,
+                                        unsigned char* passwd, int len,
+                                        pem_password_cb* cb, void* arg)
+{
+    int ret;
+    WOLFSSL_EVP_PKEY* pkey;
+
+    WOLFSSL_ENTER("wolfSSL_PEM_write_bio_RSAPrivateKey");
+
+
+    pkey = wolfSSL_PKEY_new_ex(bio->heap);
+    if (pkey == NULL) {
+        WOLFSSL_MSG("wolfSSL_PKEY_new_ex failed");
+        return SSL_FAILURE;
+}
+
+    pkey->type   = EVP_PKEY_RSA;
+    pkey->rsa    = key;
+    pkey->ownRsa = 0;
+#ifdef WOLFSSL_KEY_GEN
+    /* similar to how wolfSSL_PEM_write_mem_RSAPrivateKey finds DER of key */
+{
+        int derMax;
+        int derSz;
+        byte* derBuf;
+
+        /* 5 > size of n, d, p, q, d%(p-1), d(q-1), 1/q%p, e + ASN.1 additional
+         *  informations
+         */
+        derMax = 5 * wolfSSL_RSA_size(key) + AES_BLOCK_SIZE;
+
+        derBuf = (byte*)XMALLOC(derMax, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        if (derBuf == NULL) {
+            WOLFSSL_MSG("malloc failed");
+            wolfSSL_EVP_PKEY_free(pkey);
+            return SSL_FAILURE;
+}
+
+        /* Key to DER */
+        derSz = wc_RsaKeyToDer((RsaKey*)key->internal, derBuf, derMax);
+        if (derSz < 0) {
+            WOLFSSL_MSG("wc_RsaKeyToDer failed");
+            XFREE(derBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
+            wolfSSL_EVP_PKEY_free(pkey);
+            return SSL_FAILURE;
+        }
+
+        pkey->pkey.ptr = (char*)XMALLOC(derSz, bio->heap,
+                DYNAMIC_TYPE_TMP_BUFFER);
+        if (pkey->pkey.ptr == NULL) {
+            WOLFSSL_MSG("key malloc failed");
+            XFREE(derBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
+            wolfSSL_EVP_PKEY_free(pkey);
+            return SSL_FAILURE;
+        }
+        pkey->pkey_sz = derSz;
+        XMEMCPY(pkey->pkey.ptr, derBuf, derSz);
+        XFREE(derBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    }
+#endif
+
+    ret = wolfSSL_PEM_write_bio_PrivateKey(bio, pkey, cipher, passwd, len,
+                                        cb, arg);
+
+    wolfSSL_EVP_PKEY_free(pkey);
+
+        return ret;
+    }
+
 
 int wolfSSL_PEM_write_bio_PrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key,
@@ -20870,4 +26349,5 @@
     int type;
     int ret;
+    byte* tmp;
 
     (void)cipher;
@@ -20910,22 +26390,30 @@
         return WOLFSSL_FAILURE;
     }
-    if (bio->mem != NULL) {
-        XFREE(bio->mem, NULL, DYNAMIC_TYPE_OPENSSL);
-    }
-    bio->mem = (byte*)XMALLOC(pemSz, NULL, DYNAMIC_TYPE_OPENSSL);
-    bio->memLen = pemSz;
-
-    ret = wc_DerToPemEx(keyDer, key->pkey_sz, bio->mem, bio->memLen,
+    tmp = (byte*)XMALLOC(pemSz, bio->heap, DYNAMIC_TYPE_OPENSSL);
+    if (tmp == NULL) {
+        return MEMORY_E;
+}
+
+    ret = wc_DerToPemEx(keyDer, key->pkey_sz, tmp, pemSz,
                                 NULL, type);
     if (ret < 0) {
         WOLFSSL_LEAVE("wolfSSL_PEM_write_bio_PrivateKey", ret);
-        return WOLFSSL_FAILURE;
-    }
-
-    return WOLFSSL_SUCCESS;
+        XFREE(tmp, bio->heap, DYNAMIC_TYPE_OPENSSL);
+        return SSL_FAILURE;
+    }
+
+    ret = wolfSSL_BIO_write(bio, tmp, pemSz);
+    XFREE(tmp, bio->heap, DYNAMIC_TYPE_OPENSSL);
+    if (ret != pemSz) {
+        WOLFSSL_MSG("Unable to write full PEM to BIO");
+        return SSL_FAILURE;
+    }
+
+    return SSL_SUCCESS;
 }
 #endif /* defined(WOLFSSL_KEY_GEN) || defined(WOLFSSL_CERT_GEN) */
 
-#if defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA)
+#if defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA) && !defined(HAVE_USER_RSA) && \
+    (defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM))
 
 /* return code compliant with OpenSSL :
@@ -20938,4 +26426,7 @@
     byte *derBuf, *tmp, *cipherInfo = NULL;
     int  der_max_len = 0, derSz = 0;
+    const int type = PRIVATEKEY_TYPE;
+    const char* header = NULL;
+    const char* footer = NULL;
 
     WOLFSSL_ENTER("wolfSSL_PEM_write_mem_RSAPrivateKey");
@@ -20944,5 +26435,8 @@
         WOLFSSL_MSG("Bad function arguments");
         return WOLFSSL_FAILURE;
-    }
+}
+
+    if (wc_PemGetHeaderFooter(type, &header, &footer) != 0)
+        return WOLFSSL_FAILURE;
 
     if (rsa->inSet == 0) {
@@ -20983,13 +26477,16 @@
             WOLFSSL_MSG("EncryptDerKey failed");
             XFREE(derBuf, NULL, DYNAMIC_TYPE_DER);
-            return ret;
-        }
+    return ret;
+}
 
         /* tmp buffer with a max size */
-        *plen = (derSz * 2) + sizeof(BEGIN_RSA_PRIV) +
-                sizeof(END_RSA_PRIV) + HEADER_ENCRYPTED_KEY_SIZE;
-    }
-    else /* tmp buffer with a max size */
-        *plen = (derSz * 2) + sizeof(BEGIN_RSA_PRIV) + sizeof(END_RSA_PRIV);
+        *plen = (derSz * 2) + (int)XSTRLEN(header) + 1 +
+            (int)XSTRLEN(footer) + 1 + HEADER_ENCRYPTED_KEY_SIZE;
+    }
+    else {
+        /* tmp buffer with a max size */
+        *plen = (derSz * 2) + (int)XSTRLEN(header) + 1 +
+            (int)XSTRLEN(footer) + 1;
+    }
 
     tmp = (byte*)XMALLOC(*plen, NULL, DYNAMIC_TYPE_PEM);
@@ -21003,5 +26500,5 @@
 
     /* DER to PEM */
-    *plen = wc_DerToPemEx(derBuf, derSz, tmp, *plen, cipherInfo, PRIVATEKEY_TYPE);
+    *plen = wc_DerToPemEx(derBuf, derSz, tmp, *plen, cipherInfo, type);
     if (*plen <= 0) {
         WOLFSSL_MSG("wc_DerToPemEx failed");
@@ -21011,5 +26508,5 @@
             XFREE(cipherInfo, NULL, DYNAMIC_TYPE_STRING);
         return WOLFSSL_FAILURE;
-    }
+}
     XFREE(derBuf, NULL, DYNAMIC_TYPE_DER);
     if (cipherInfo != NULL)
@@ -21040,5 +26537,5 @@
  *   1 if success, 0 if error
  */
-int wolfSSL_PEM_write_RSAPrivateKey(FILE *fp, WOLFSSL_RSA *rsa,
+int wolfSSL_PEM_write_RSAPrivateKey(XFILE fp, WOLFSSL_RSA *rsa,
                                     const EVP_CIPHER *enc,
                                     unsigned char *kstr, int klen,
@@ -21053,8 +26550,9 @@
     WOLFSSL_MSG("wolfSSL_PEM_write_RSAPrivateKey");
 
-    if (fp == NULL || rsa == NULL || rsa->internal == NULL) {
+    if (fp == XBADFILE || rsa == NULL || rsa->internal == NULL)
+    {
         WOLFSSL_MSG("Bad function arguments");
-        return WOLFSSL_FAILURE;
-    }
+    return WOLFSSL_FAILURE;
+}
 
     ret = wolfSSL_PEM_write_mem_RSAPrivateKey(rsa, enc, kstr, klen, &pem, &plen);
@@ -21074,25 +26572,32 @@
 }
 #endif /* NO_FILESYSTEM */
-
-int wolfSSL_PEM_write_bio_RSAPrivateKey(WOLFSSL_BIO* bio, RSA* rsa,
-                                        const EVP_CIPHER* cipher,
-                                        unsigned char* passwd, int len,
-                                        pem_password_cb* cb, void* arg)
-{
-    (void)bio;
-    (void)rsa;
-    (void)cipher;
-    (void)passwd;
-    (void)len;
-    (void)cb;
-    (void)arg;
-
-    WOLFSSL_MSG("wolfSSL_PEM_write_bio_RSAPrivateKey not implemented");
-
-    return WOLFSSL_FAILURE;
-}
-#endif /* defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA) */
+#endif /* WOLFSSL_KEY_GEN && !NO_RSA && !HAVE_USER_RSA && WOLFSSL_PEM_TO_DER */
+
 
 #ifdef HAVE_ECC
+
+#ifdef ALT_ECC_SIZE
+static int SetIndividualInternalEcc(WOLFSSL_BIGNUM* bn, mp_int* mpi)
+{
+    WOLFSSL_MSG("Entering SetIndividualInternal");
+
+    if (bn == NULL || bn->internal == NULL) {
+        WOLFSSL_MSG("bn NULL error");
+        return WOLFSSL_FATAL_ERROR;
+    }
+
+    if (mpi == NULL) {
+        WOLFSSL_MSG("mpi NULL error");
+        return WOLFSSL_FATAL_ERROR;
+    }
+
+    if (mp_copy((mp_int*)bn->internal, mpi) != MP_OKAY) {
+        WOLFSSL_MSG("mp_copy error");
+        return WOLFSSL_FATAL_ERROR;
+    }
+
+    return WOLFSSL_SUCCESS;
+    }
+#endif /* ALT_ECC_SIZE */
 
 /* EC_POINT Openssl -> WolfSSL */
@@ -21105,8 +26610,9 @@
         WOLFSSL_MSG("ECPoint NULL error");
         return WOLFSSL_FATAL_ERROR;
-    }
+}
 
     point = (ecc_point*)p->internal;
 
+#ifndef ALT_ECC_SIZE
     if (p->X != NULL && SetIndividualInternal(p->X, point->x) != WOLFSSL_SUCCESS) {
         WOLFSSL_MSG("ecc point X error");
@@ -21123,4 +26629,20 @@
         return WOLFSSL_FATAL_ERROR;
     }
+#else
+    if (p->X != NULL && SetIndividualInternalEcc(p->X, point->x) != WOLFSSL_SUCCESS) {
+        WOLFSSL_MSG("ecc point X error");
+        return WOLFSSL_FATAL_ERROR;
+}
+
+    if (p->Y != NULL && SetIndividualInternalEcc(p->Y, point->y) != WOLFSSL_SUCCESS) {
+        WOLFSSL_MSG("ecc point Y error");
+        return WOLFSSL_FATAL_ERROR;
+    }
+
+    if (p->Z != NULL && SetIndividualInternalEcc(p->Z, point->z) != WOLFSSL_SUCCESS) {
+        WOLFSSL_MSG("ecc point Z error");
+        return WOLFSSL_FATAL_ERROR;
+    }
+#endif
 
     p->inSet = 1;
@@ -21128,4 +26650,8 @@
     return WOLFSSL_SUCCESS;
 }
+#endif /* HAVE_ECC */
+#endif /* OPENSSL_EXTRA */
+
+#if defined(HAVE_ECC) && defined(OPENSSL_EXTRA_X509_SMALL)
 
 /* EC_POINT WolfSSL -> OpenSSL */
@@ -21162,4 +26688,5 @@
     return WOLFSSL_SUCCESS;
 }
+
 
 /* EC_KEY wolfSSL -> OpenSSL */
@@ -21187,12 +26714,12 @@
                              (ecc_point*)eckey->pub_key->internal) != MP_OKAY) {
             WOLFSSL_MSG("SetECKeyExternal ecc_copy_point failed");
-            return WOLFSSL_FATAL_ERROR;
-        }
+        return WOLFSSL_FATAL_ERROR;
+    }
 
         /* set the external pubkey (point) */
         if (SetECPointExternal(eckey->pub_key) != WOLFSSL_SUCCESS) {
             WOLFSSL_MSG("SetECKeyExternal SetECPointExternal failed");
-            return WOLFSSL_FATAL_ERROR;
-        }
+        return WOLFSSL_FATAL_ERROR;
+    }
     }
 
@@ -21209,5 +26736,8 @@
     return WOLFSSL_SUCCESS;
 }
-
+#endif /* HAVE_ECC && OPENSSL_EXTRA_X509_SMALL */
+
+#ifdef OPENSSL_EXTRA
+#ifdef HAVE_ECC
 /* EC_KEY Openssl -> WolfSSL */
 static int SetECKeyInternal(WOLFSSL_EC_KEY* eckey)
@@ -21240,5 +26770,5 @@
             WOLFSSL_MSG("ec key pub error");
             return WOLFSSL_FATAL_ERROR;
-        }
+}
 
         /* public key */
@@ -21260,5 +26790,5 @@
 
     return WOLFSSL_SUCCESS;
-}
+    }
 
 WOLFSSL_EC_POINT *wolfSSL_EC_KEY_get0_public_key(const WOLFSSL_EC_KEY *key)
@@ -21272,5 +26802,5 @@
 
     return key->pub_key;
-}
+    }
 
 const WOLFSSL_EC_GROUP *wolfSSL_EC_KEY_get0_group(const WOLFSSL_EC_KEY *key)
@@ -21343,5 +26873,5 @@
         WOLFSSL_MSG("wolfSSL_EC_KEY_new failure");
         return NULL;
-    }
+}
 
     /* set the nid of the curve */
@@ -21359,4 +26889,8 @@
 }
 
+#endif /* HAVE_ECC */
+#endif /* OPENSSL_EXTRA */
+
+#if defined(HAVE_ECC) && (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL))
 static void InitwolfSSL_ECKey(WOLFSSL_EC_KEY* key)
 {
@@ -21383,5 +26917,5 @@
         WOLFSSL_MSG("wolfSSL_EC_KEY_new malloc WOLFSSL_EC_KEY failure");
         return NULL;
-    }
+}
     XMEMSET(external, 0, sizeof(WOLFSSL_EC_KEY));
 
@@ -21394,5 +26928,5 @@
         wolfSSL_EC_KEY_free(external);
         return NULL;
-    }
+}
     XMEMSET(external->internal, 0, sizeof(ecc_key));
 
@@ -21410,5 +26944,11 @@
 
     key = (ecc_key*)external->internal;
-    external->pub_key->internal = (ecc_point*)&key->pubkey;
+    external->pub_key->internal = wc_ecc_new_point();
+    if (wc_ecc_copy_point((ecc_point*)&key->pubkey,
+                (ecc_point*)external->pub_key->internal) != MP_OKAY) {
+        WOLFSSL_MSG("wc_ecc_copy_point failure");
+        wolfSSL_EC_KEY_free(external);
+        return NULL;
+    }
 
     /* curve group */
@@ -21451,5 +26991,10 @@
     }
 }
-
+#endif /* HAVE_ECC && (OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL) */
+
+#ifdef OPENSSL_EXTRA
+#ifdef HAVE_ECC
+
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_EC_KEY_set_group(WOLFSSL_EC_KEY *key, WOLFSSL_EC_GROUP *group)
 {
@@ -21458,8 +27003,9 @@
 
     WOLFSSL_ENTER("wolfSSL_EC_KEY_set_group");
-    WOLFSSL_MSG("wolfSSL_EC_KEY_set_group TBD");
+    WOLFSSL_STUB("EC_KEY_set_group");
 
     return -1;
 }
+#endif
 
 int wolfSSL_EC_KEY_generate_key(WOLFSSL_EC_KEY *key)
@@ -21481,5 +27027,5 @@
     }
 
-#ifdef WOLFSSL_SMALL_STACK
+    #ifdef WOLFSSL_SMALL_STACK
     tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG);
     if (tmpRNG == NULL)
@@ -21497,5 +27043,5 @@
         else
             rng = &globalRNG;
-    }
+        }
 
     if (rng == NULL) {
@@ -21514,11 +27060,11 @@
 #endif
         return 0;
-    }
+        }
 
     if (initTmpRng)
         wc_FreeRng(tmpRNG);
-#ifdef WOLFSSL_SMALL_STACK
+    #ifdef WOLFSSL_SMALL_STACK
     XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG);
-#endif
+    #endif
 
     if (SetECKeyExternal(key) != WOLFSSL_SUCCESS) {
@@ -21530,4 +27076,5 @@
 }
 
+#ifndef NO_WOLFSSL_STUB
 void wolfSSL_EC_KEY_set_asn1_flag(WOLFSSL_EC_KEY *key, int asn1_flag)
 {
@@ -21536,6 +27083,7 @@
 
     WOLFSSL_ENTER("wolfSSL_EC_KEY_set_asn1_flag");
-    WOLFSSL_MSG("wolfSSL_EC_KEY_set_asn1_flag TBD");
-}
+    WOLFSSL_STUB("EC_KEY_set_asn1_flag");
+}
+#endif
 
 /* return code compliant with OpenSSL :
@@ -21553,5 +27101,5 @@
         WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order Bad arguments");
         return WOLFSSL_FAILURE;
-    }
+}
 
     if (key->inSet == 0) {
@@ -21591,33 +27139,101 @@
     }
 
-#if defined(DEBUG_WOLFSSL) && !defined(NO_FILESYSTEM)
-    wolfssl_EC_POINT_dump("pub", pub);
-    wolfssl_EC_POINT_dump("key->pub_key", key->pub_key);
-#endif
+    wolfSSL_EC_POINT_dump("pub", pub);
+    wolfSSL_EC_POINT_dump("key->pub_key", key->pub_key);
+
     return WOLFSSL_SUCCESS;
 }
 /* End EC_KEY */
 
-#if defined(DEBUG_WOLFSSL) && !defined(NO_FILESYSTEM)
-void wolfssl_EC_POINT_dump(const char *msg, const WOLFSSL_EC_POINT *p)
-{
+
+#ifndef HAVE_SELFTEST
+/* ECC point compression types were not included in selftest ecc.h */
+
+char* wolfSSL_EC_POINT_point2hex(const WOLFSSL_EC_GROUP* group,
+                                 const WOLFSSL_EC_POINT* point, int form,
+                                 WOLFSSL_BN_CTX* ctx)
+{
+    static const char* hexDigit = "0123456789ABCDEF";
+    char* hex = NULL;
+    int id = wc_ecc_get_curve_id(group->curve_idx);
+    int i, sz, len;
+
+    (void)ctx;
+
+    if (group == NULL || point == NULL)
+        return NULL;
+
+    if ((sz = wc_ecc_get_curve_size_from_id(id)) < 0)
+        return NULL;
+
+    len = sz + 1;
+    if (form == POINT_CONVERSION_UNCOMPRESSED)
+        len += sz;
+
+    hex = (char*)XMALLOC(2 * len + 1, NULL, DYNAMIC_TYPE_ECC);
+    if (hex == NULL)
+        return NULL;
+    XMEMSET(hex, 0, 2 * len + 1);
+
+    /* Put in x-ordinate after format byte. */
+    i = sz - mp_unsigned_bin_size((mp_int*)point->X->internal) + 1;
+    if (mp_to_unsigned_bin((mp_int*)point->X->internal, (byte*)(hex + i)) < 0) {
+        XFREE(hex,  NULL, DYNAMIC_TYPE_ECC);
+        return NULL;
+    }
+
+    if (form == POINT_CONVERSION_COMPRESSED) {
+        hex[0] = mp_isodd((mp_int*)point->Y->internal) ? ECC_POINT_COMP_ODD :
+                                                         ECC_POINT_COMP_EVEN;
+    }
+    else {
+        hex[0] = ECC_POINT_UNCOMP;
+        /* Put in y-ordinate after x-ordinate */
+        i = 1 + 2 * sz - mp_unsigned_bin_size((mp_int*)point->Y->internal);
+        if (mp_to_unsigned_bin((mp_int*)point->Y->internal,
+                                                        (byte*)(hex + i)) < 0) {
+            XFREE(hex,  NULL, DYNAMIC_TYPE_ECC);
+            return NULL;
+        }
+    }
+
+    for (i = len-1; i >= 0; i--) {
+        byte b = hex[i];
+        hex[i * 2 + 1] = hexDigit[b  & 0xf];
+        hex[i * 2    ] = hexDigit[b >>   4];
+    }
+
+    return hex;
+            }
+
+#endif /* HAVE_SELFTEST */
+
+void wolfSSL_EC_POINT_dump(const char *msg, const WOLFSSL_EC_POINT *p)
+{
+#if defined(DEBUG_WOLFSSL)
     char *num;
 
-    WOLFSSL_ENTER("wolfssl_EC_POINT_dump");
+    WOLFSSL_ENTER("wolfSSL_EC_POINT_dump");
 
     if (p == NULL) {
-        fprintf(stderr, "%s = NULL", msg);
+        printf("%s = NULL", msg);
         return;
     }
 
-    fprintf(stderr, "%s:\n\tinSet=%d, exSet=%d\n", msg, p->inSet, p->exSet);
+    printf("%s:\n\tinSet=%d, exSet=%d\n", msg, p->inSet, p->exSet);
     num = wolfSSL_BN_bn2hex(p->X);
-    fprintf(stderr, "\tX = %s\n", num);
+    printf("\tX = %s\n", num);
     XFREE(num, NULL, DYNAMIC_TYPE_ECC);
     num = wolfSSL_BN_bn2hex(p->Y);
-    fprintf(stderr, "\tY = %s\n", num);
+    printf("\tY = %s\n", num);
     XFREE(num, NULL, DYNAMIC_TYPE_ECC);
-}
-#endif
+    num = wolfSSL_BN_bn2hex(p->Z);
+    printf("\tZ = %s\n", num);
+    XFREE(num, NULL, DYNAMIC_TYPE_ECC);
+#else
+    (void)msg;
+    (void)p;
+#endif
+}
 
 /* Start EC_GROUP */
@@ -21644,6 +27260,10 @@
     /* ko */
     return 1;
-}
-
+    }
+
+#endif /* HAVE_ECC */
+#endif /* OPENSSL_EXTRA */
+
+#if defined(HAVE_ECC) && (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL))
 void wolfSSL_EC_GROUP_free(WOLFSSL_EC_GROUP *group)
 {
@@ -21653,5 +27273,9 @@
     group = NULL;
 }
-
+#endif
+
+#ifdef OPENSSL_EXTRA
+#ifdef HAVE_ECC
+#ifndef NO_WOLFSSL_STUB
 void wolfSSL_EC_GROUP_set_asn1_flag(WOLFSSL_EC_GROUP *group, int flag)
 {
@@ -21660,6 +27284,7 @@
 
     WOLFSSL_ENTER("wolfSSL_EC_GROUP_set_asn1_flag");
-    WOLFSSL_MSG("wolfSSL_EC_GROUP_set_asn1_flag TBD");
-}
+    WOLFSSL_STUB("EC_GROUP_set_asn1_flag");
+}
+#endif
 
 WOLFSSL_EC_GROUP *wolfSSL_EC_GROUP_new_by_curve_name(int nid)
@@ -21688,5 +27313,5 @@
             g->curve_oid = ecc_sets[x].oidSum;
             break;
-        }
+    }
 
     return g;
@@ -21703,5 +27328,5 @@
         WOLFSSL_MSG("wolfSSL_EC_GROUP_get_curve_name Bad arguments");
         return WOLFSSL_FAILURE;
-    }
+        }
 
     return group->curve_nid;
@@ -21776,5 +27401,5 @@
 
     if (mp_read_radix((mp_int*)order->internal,
-                      ecc_sets[group->curve_idx].order, 16) != MP_OKAY) {
+                  ecc_sets[group->curve_idx].order, MP_RADIX_HEX) != MP_OKAY) {
         WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order mp_read order failure");
         mp_clear((mp_int*)order->internal);
@@ -21783,5 +27408,5 @@
 
     return WOLFSSL_SUCCESS;
-}
+        }
 /* End EC_GROUP */
 
@@ -21802,5 +27427,5 @@
         WOLFSSL_MSG("wolfSSL_ECPoint_i2d NULL error");
         return WOLFSSL_FAILURE;
-    }
+}
 
     if (p->inSet == 0) {
@@ -21810,12 +27435,11 @@
             WOLFSSL_MSG("SetECPointInternal SetECPointInternal failed");
             return WOLFSSL_FAILURE;
-        }
-    }
-
-#if defined(DEBUG_WOLFSSL) && !defined(NO_FILESYSTEM)
+            }
+        }
+
     if (out != NULL) {
-        wolfssl_EC_POINT_dump("i2d p", p);
-    }
-#endif
+        wolfSSL_EC_POINT_dump("i2d p", p);
+    }
+
     err = wc_ecc_export_point_der(group->curve_idx, (ecc_point*)p->internal,
                                   out, len);
@@ -21823,5 +27447,5 @@
         WOLFSSL_MSG("wolfSSL_ECPoint_i2d wc_ecc_export_point_der failed");
         return WOLFSSL_FAILURE;
-    }
+}
 
     return WOLFSSL_SUCCESS;
@@ -21856,7 +27480,6 @@
     }
 
-#if defined(DEBUG_WOLFSSL) && !defined(NO_FILESYSTEM)
-    wolfssl_EC_POINT_dump("d2i p", p);
-#endif
+    wolfSSL_EC_POINT_dump("d2i p", p);
+
     return WOLFSSL_SUCCESS;
 }
@@ -21886,5 +27509,5 @@
         XFREE(p, NULL, DYNAMIC_TYPE_ECC);
         return NULL;
-    }
+}
 
     return p;
@@ -21925,4 +27548,5 @@
 }
 
+#ifndef WOLFSSL_ATECC508A
 /* return code compliant with OpenSSL :
  *   1 if success, 0 if error
@@ -21952,5 +27576,5 @@
             WOLFSSL_MSG("SetECPointInternal q failed");
             return WOLFSSL_FAILURE;
-        }
+    }
     }
 
@@ -21960,12 +27584,14 @@
     }
 
-    ret = mp_read_radix(&prime, ecc_sets[group->curve_idx].prime, 16);
-    if (ret == MP_OKAY)
-        ret = mp_read_radix(&a, ecc_sets[group->curve_idx].Af, 16);
+    ret = mp_read_radix(&prime, ecc_sets[group->curve_idx].prime, MP_RADIX_HEX);
+    if (ret == MP_OKAY) {
+        ret = mp_read_radix(&a, ecc_sets[group->curve_idx].Af, MP_RADIX_HEX);
+    }
 
     /* r = q * m % prime */
-    if (ret == MP_OKAY)
+    if (ret == MP_OKAY) {
         ret = wc_ecc_mulmod((mp_int*)m->internal, (ecc_point*)q->internal,
                       (ecc_point*)r->internal, &a, &prime, 1);
+}
 
     mp_clear(&a);
@@ -21973,6 +27599,8 @@
 
     if (ret == MP_OKAY) {
+        r->inSet = 1; /* mark internal set */
+
         /* set the external value for the computed point */
-        ret = SetECPointInternal(r);
+        ret = SetECPointExternal(r);
         if (ret != WOLFSSL_SUCCESS) {
             WOLFSSL_MSG("SetECPointInternal r failed");
@@ -21984,5 +27612,6 @@
 
     return ret;
-}
+    }
+#endif
 
 void wolfSSL_EC_POINT_clear_free(WOLFSSL_EC_POINT *p)
@@ -21991,5 +27620,5 @@
 
     wolfSSL_EC_POINT_free(p);
-}
+    }
 
 /* return code compliant with OpenSSL :
@@ -22002,5 +27631,5 @@
     int ret;
 
-	(void)ctx;
+    (void)ctx;
 
     WOLFSSL_ENTER("wolfSSL_EC_POINT_cmp");
@@ -22020,5 +27649,8 @@
     return WOLFSSL_FATAL_ERROR;
 }
-
+#endif /* HAVE_ECC */
+#endif /* OPENSSL_EXTRA */
+
+#if defined(HAVE_ECC) && (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL))
 void wolfSSL_EC_POINT_free(WOLFSSL_EC_POINT *p)
 {
@@ -22026,9 +27658,8 @@
 
     if (p != NULL) {
-        if (p->internal == NULL) {
+        if (p->internal != NULL) {
             wc_ecc_del_point((ecc_point*)p->internal);
-            XFREE(p->internal, NULL, DYNAMIC_TYPE_ECC);
             p->internal = NULL;
-        }
+    }
 
         wolfSSL_BN_free(p->X);
@@ -22043,6 +27674,9 @@
         p = NULL;
     }
-}
-
+    }
+#endif
+
+#ifdef OPENSSL_EXTRA
+#ifdef HAVE_ECC
 /* return code compliant with OpenSSL :
  *   1 if point at infinity, 0 else
@@ -22090,5 +27724,5 @@
         XFREE(sig, NULL, DYNAMIC_TYPE_ECC);
     }
-}
+    }
 
 WOLFSSL_ECDSA_SIG *wolfSSL_ECDSA_SIG_new(void)
@@ -22151,5 +27785,5 @@
             WOLFSSL_MSG("wolfSSL_ECDSA_do_sign SetECKeyInternal failed");
             return NULL;
-        }
+    }
     }
 
@@ -22163,5 +27797,5 @@
         rng = tmpRNG;
         initTmpRng = 1;
-    }
+        }
     else {
         WOLFSSL_MSG("wolfSSL_ECDSA_do_sign Bad RNG Init, trying global");
@@ -22179,5 +27813,5 @@
                                     &sig_r, &sig_s) != MP_OKAY) {
                 WOLFSSL_MSG("wc_ecc_sign_hash_ex failed");
-            }
+    }
             else {
                 /* put signature blob in ECDSA structure */
@@ -22189,10 +27823,10 @@
                     wolfSSL_ECDSA_SIG_free(sig);
                     sig = NULL;
-                }
+    }
                 else if (SetIndividualExternal(&(sig->s), &sig_s)!=WOLFSSL_SUCCESS){
                     WOLFSSL_MSG("ecdsa s key error");
                     wolfSSL_ECDSA_SIG_free(sig);
                     sig = NULL;
-                }
+    }
 
             }
@@ -22235,5 +27869,5 @@
             return WOLFSSL_FATAL_ERROR;
         }
-    }
+        }
 
     if (wc_ecc_verify_hash_ex((mp_int*)sig->r->internal,
@@ -22246,7 +27880,71 @@
         WOLFSSL_MSG("wc_ecc_verify_hash incorrect signature detected");
         return WOLFSSL_FAILURE;
-    }
+}
 
     return WOLFSSL_SUCCESS;
+}
+
+WOLFSSL_ECDSA_SIG *wolfSSL_d2i_ECDSA_SIG(WOLFSSL_ECDSA_SIG **sig,
+                                         const unsigned char **pp, long len)
+{
+    WOLFSSL_ECDSA_SIG *s = NULL;
+
+    if (pp == NULL)
+        return NULL;
+
+    if (sig != NULL)
+        s = *sig;
+    if (s == NULL) {
+        s = wolfSSL_ECDSA_SIG_new();
+        if (s == NULL)
+            return NULL;
+    }
+
+    /* DecodeECC_DSA_Sig calls mp_init, so free these */
+    mp_free((mp_int*)s->r->internal);
+    mp_free((mp_int*)s->s->internal);
+
+    if (DecodeECC_DSA_Sig(*pp, (word32)len, (mp_int*)s->r->internal,
+                                          (mp_int*)s->s->internal) != MP_OKAY) {
+        if (sig == NULL || *sig == NULL)
+            wolfSSL_ECDSA_SIG_free(s);
+        return NULL;
+    }
+
+    *pp += len;
+    if (sig != NULL)
+        *sig = s;
+    return s;
+}
+
+int wolfSSL_i2d_ECDSA_SIG(const WOLFSSL_ECDSA_SIG *sig, unsigned char **pp)
+    {
+    word32 len;
+
+    if (sig == NULL)
+            return 0;
+
+    /* ASN.1: SEQ + INT + INT
+     *   ASN.1 Integer must be a positive value - prepend zero if number has
+     *   top bit set.
+     */
+    len = 2 + mp_leading_bit((mp_int*)sig->r->internal) +
+              mp_unsigned_bin_size((mp_int*)sig->r->internal) +
+          2 + mp_leading_bit((mp_int*)sig->s->internal) +
+              mp_unsigned_bin_size((mp_int*)sig->s->internal);
+    /* Two bytes required for length if ASN.1 SEQ data greater than 127 bytes
+     * and less than 256 bytes.
+     */
+    len = 1 + ((len > 127) ? 2 : 1) + len;
+    if (pp != NULL && *pp != NULL) {
+        if (StoreECC_DSA_Sig(*pp, &len, (mp_int*)sig->r->internal,
+                                        (mp_int*)sig->s->internal) != MP_OKAY) {
+            len = 0;
+        }
+        else
+            *pp += len;
+    }
+
+    return (int)len;
 }
 /* End ECDSA_SIG */
@@ -22267,5 +27965,5 @@
     (void)KDF;
 
-	WOLFSSL_ENTER("wolfSSL_ECDH_compute_key");
+    WOLFSSL_ENTER("wolfSSL_ECDH_compute_key");
 
     if (out == NULL || pub_key == NULL || pub_key->internal == NULL ||
@@ -22273,5 +27971,5 @@
         WOLFSSL_MSG("Bad function arguments");
         return WOLFSSL_FATAL_ERROR;
-    }
+        }
 
     /* set internal key if not done */
@@ -22293,8 +27991,8 @@
         WOLFSSL_MSG("wc_ecc_shared_secret failed");
         return WOLFSSL_FATAL_ERROR;
-    }
+        }
 
     return len;
-}
+    }
 /* End ECDH */
 
@@ -22303,13 +28001,16 @@
  *   1 if success, 0 if error
  */
-int wolfSSL_PEM_write_EC_PUBKEY(FILE *fp, WOLFSSL_EC_KEY *x)
+#ifndef NO_WOLFSSL_STUB
+int wolfSSL_PEM_write_EC_PUBKEY(XFILE fp, WOLFSSL_EC_KEY *x)
 {
     (void)fp;
     (void)x;
-
+    WOLFSSL_STUB("PEM_write_EC_PUBKEY");
     WOLFSSL_MSG("wolfSSL_PEM_write_EC_PUBKEY not implemented");
 
     return WOLFSSL_FAILURE;
 }
+#endif
+
 #endif /* NO_FILESYSTEM */
 
@@ -22319,4 +28020,5 @@
  *   1 if success, 0 if error
  */
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_PEM_write_bio_ECPrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EC_KEY* ecc,
                                        const EVP_CIPHER* cipher,
@@ -22331,9 +28033,10 @@
     (void)cb;
     (void)arg;
-
+    WOLFSSL_STUB("PEM_write_bio_ECPrivateKey");
     WOLFSSL_MSG("wolfSSL_PEM_write_bio_ECPrivateKey not implemented");
 
     return WOLFSSL_FAILURE;
 }
+#endif
 
 /* return code compliant with OpenSSL :
@@ -22345,6 +28048,10 @@
                                        unsigned char **pem, int *plen)
 {
+#if defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM)
     byte *derBuf, *tmp, *cipherInfo = NULL;
     int  der_max_len = 0, derSz = 0;
+    const int type = ECC_PRIVATEKEY_TYPE;
+    const char* header = NULL;
+    const char* footer = NULL;
 
     WOLFSSL_MSG("wolfSSL_PEM_write_mem_ECPrivateKey");
@@ -22355,4 +28062,7 @@
     }
 
+    if (wc_PemGetHeaderFooter(type, &header, &footer) != 0)
+        return WOLFSSL_FAILURE;
+
     if (ecc->inSet == 0) {
         WOLFSSL_MSG("No ECC internal set, do it");
@@ -22361,5 +28071,5 @@
             WOLFSSL_MSG("SetDsaInternal failed");
             return WOLFSSL_FAILURE;
-        }
+    }
     }
 
@@ -22380,5 +28090,5 @@
         XFREE(derBuf, NULL, DYNAMIC_TYPE_DER);
         return WOLFSSL_FAILURE;
-    }
+        }
 
     /* encrypt DER buffer if required */
@@ -22392,12 +28102,14 @@
             XFREE(derBuf, NULL, DYNAMIC_TYPE_DER);
             return ret;
-        }
+    }
 
         /* tmp buffer with a max size */
-        *plen = (derSz * 2) + sizeof(BEGIN_EC_PRIV) +
-        sizeof(END_EC_PRIV) + HEADER_ENCRYPTED_KEY_SIZE;
-    }
-    else /* tmp buffer with a max size */
-        *plen = (derSz * 2) + sizeof(BEGIN_EC_PRIV) + sizeof(END_EC_PRIV);
+        *plen = (derSz * 2) + (int)XSTRLEN(header) + 1 +
+            (int)XSTRLEN(footer) + 1 + HEADER_ENCRYPTED_KEY_SIZE;
+    }
+    else { /* tmp buffer with a max size */
+        *plen = (derSz * 2) + (int)XSTRLEN(header) + 1 +
+            (int)XSTRLEN(footer) + 1;
+    }
 
     tmp = (byte*)XMALLOC(*plen, NULL, DYNAMIC_TYPE_PEM);
@@ -22408,8 +28120,8 @@
             XFREE(cipherInfo, NULL, DYNAMIC_TYPE_STRING);
         return WOLFSSL_FAILURE;
-    }
+}
 
     /* DER to PEM */
-    *plen = wc_DerToPemEx(derBuf, derSz, tmp, *plen, cipherInfo, ECC_PRIVATEKEY_TYPE);
+    *plen = wc_DerToPemEx(derBuf, derSz, tmp, *plen, cipherInfo, type);
     if (*plen <= 0) {
         WOLFSSL_MSG("wc_DerToPemEx failed");
@@ -22441,4 +28153,13 @@
 
     return WOLFSSL_SUCCESS;
+#else
+    (void)ecc;
+    (void)cipher;
+    (void)passwd;
+    (void)passwdSz;
+    (void)pem;
+    (void)plen;
+    return WOLFSSL_FAILURE;
+#endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */
 }
 
@@ -22447,5 +28168,5 @@
  *   1 if success, 0 if error
  */
-int wolfSSL_PEM_write_ECPrivateKey(FILE *fp, WOLFSSL_EC_KEY *ecc,
+int wolfSSL_PEM_write_ECPrivateKey(XFILE fp, WOLFSSL_EC_KEY *ecc,
                                    const EVP_CIPHER *enc,
                                    unsigned char *kstr, int klen,
@@ -22460,5 +28181,5 @@
     WOLFSSL_MSG("wolfSSL_PEM_write_ECPrivateKey");
 
-    if (fp == NULL || ecc == NULL || ecc->internal == NULL) {
+    if (fp == XBADFILE || ecc == NULL || ecc->internal == NULL) {
         WOLFSSL_MSG("Bad function arguments");
         return WOLFSSL_FAILURE;
@@ -22475,9 +28196,9 @@
         WOLFSSL_MSG("ECC private key file write failed");
         return WOLFSSL_FAILURE;
-    }
+        }
 
     XFREE(pem, NULL, DYNAMIC_TYPE_KEY);
     return WOLFSSL_SUCCESS;
-}
+    }
 
 #endif /* NO_FILESYSTEM */
@@ -22509,6 +28230,6 @@
     WOLFSSL_MSG("wolfSSL_PEM_write_bio_DSAPrivateKey not implemented");
 
-    return WOLFSSL_FAILURE;
-}
+        return WOLFSSL_FAILURE;
+    }
 
 /* return code compliant with OpenSSL :
@@ -22519,7 +28240,11 @@
                                         unsigned char* passwd, int passwdSz,
                                         unsigned char **pem, int *plen)
-{
+    {
+#if defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM)
     byte *derBuf, *tmp, *cipherInfo = NULL;
     int  der_max_len = 0, derSz = 0;
+    const int type = DSA_PRIVATEKEY_TYPE;
+    const char* header = NULL;
+    const char* footer = NULL;
 
     WOLFSSL_MSG("wolfSSL_PEM_write_mem_DSAPrivateKey");
@@ -22528,5 +28253,8 @@
         WOLFSSL_MSG("Bad function arguments");
         return WOLFSSL_FAILURE;
-    }
+        }
+
+    if (wc_PemGetHeaderFooter(type, &header, &footer) != 0)
+        return WOLFSSL_FAILURE;
 
     if (dsa->inSet == 0) {
@@ -22537,5 +28265,5 @@
             return WOLFSSL_FAILURE;
         }
-    }
+}
 
     /* 4 > size of pub, priv, p, q, g + ASN.1 additional informations
@@ -22570,9 +28298,11 @@
 
         /* tmp buffer with a max size */
-        *plen = (derSz * 2) + sizeof(BEGIN_DSA_PRIV) +
-        sizeof(END_DSA_PRIV) + HEADER_ENCRYPTED_KEY_SIZE;
-    }
-    else /* tmp buffer with a max size */
-        *plen = (derSz * 2) + sizeof(BEGIN_DSA_PRIV) + sizeof(END_DSA_PRIV);
+        *plen = (derSz * 2) + (int)XSTRLEN(header) + 1 +
+            (int)XSTRLEN(footer) + 1 + HEADER_ENCRYPTED_KEY_SIZE;
+    }
+    else { /* tmp buffer with a max size */
+        *plen = (derSz * 2) + (int)XSTRLEN(header) + 1 +
+            (int)XSTRLEN(footer) + 1;
+    }
 
     tmp = (byte*)XMALLOC(*plen, NULL, DYNAMIC_TYPE_PEM);
@@ -22586,5 +28316,5 @@
 
     /* DER to PEM */
-    *plen = wc_DerToPemEx(derBuf, derSz, tmp, *plen, cipherInfo, DSA_PRIVATEKEY_TYPE);
+    *plen = wc_DerToPemEx(derBuf, derSz, tmp, *plen, cipherInfo, type);
     if (*plen <= 0) {
         WOLFSSL_MSG("wc_DerToPemEx failed");
@@ -22612,8 +28342,17 @@
         XFREE(tmp, NULL, DYNAMIC_TYPE_PEM);
         return WOLFSSL_FAILURE;
-    }
+}
     XFREE(tmp, NULL, DYNAMIC_TYPE_PEM);
 
     return WOLFSSL_SUCCESS;
+#else
+    (void)dsa;
+    (void)cipher;
+    (void)passwd;
+    (void)passwdSz;
+    (void)pem;
+    (void)plen;
+    return WOLFSSL_FAILURE;
+#endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */
 }
 
@@ -22622,5 +28361,5 @@
  *   1 if success, 0 if error
  */
-int wolfSSL_PEM_write_DSAPrivateKey(FILE *fp, WOLFSSL_DSA *dsa,
+int wolfSSL_PEM_write_DSAPrivateKey(XFILE fp, WOLFSSL_DSA *dsa,
                                     const EVP_CIPHER *enc,
                                     unsigned char *kstr, int klen,
@@ -22635,5 +28374,5 @@
     WOLFSSL_MSG("wolfSSL_PEM_write_DSAPrivateKey");
 
-    if (fp == NULL || dsa == NULL || dsa->internal == NULL) {
+    if (fp == XBADFILE || dsa == NULL || dsa->internal == NULL) {
         WOLFSSL_MSG("Bad function arguments");
         return WOLFSSL_FAILURE;
@@ -22663,46 +28402,295 @@
  *   1 if success, 0 if error
  */
-int wolfSSL_PEM_write_DSA_PUBKEY(FILE *fp, WOLFSSL_DSA *x)
+#ifndef NO_WOLFSSL_STUB
+int wolfSSL_PEM_write_DSA_PUBKEY(XFILE fp, WOLFSSL_DSA *x)
 {
     (void)fp;
     (void)x;
-
+    WOLFSSL_STUB("PEM_write_DSA_PUBKEY");
     WOLFSSL_MSG("wolfSSL_PEM_write_DSA_PUBKEY not implemented");
 
     return WOLFSSL_FAILURE;
-}
+    }
+    #endif
 #endif /* NO_FILESYSTEM */
 
 #endif /* #ifndef NO_DSA */
 
+static int pem_read_bio_key(WOLFSSL_BIO* bio, pem_password_cb* cb, void* pass,
+                            int keyType, int* eccFlag, DerBuffer** der)
+    {
+#ifdef WOLFSSL_SMALL_STACK
+    EncryptedInfo* info = NULL;
+#else
+    EncryptedInfo info[1];
+#endif /* WOLFSSL_SMALL_STACK */
+    pem_password_cb* localCb = cb;
+
+    char* mem = NULL;
+    int memSz;
+    int ret;
+
+    if ((ret = wolfSSL_BIO_pending(bio)) > 0) {
+        memSz = ret;
+        mem = (char*)XMALLOC(memSz, bio->heap, DYNAMIC_TYPE_OPENSSL);
+        if (mem == NULL) {
+            WOLFSSL_MSG("Memory error");
+            ret = MEMORY_E;
+        }
+        if (ret >= 0) {
+            if ((ret = wolfSSL_BIO_read(bio, mem, memSz)) <= 0) {
+                XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL);
+                ret = MEMORY_E;
+    }
+    }
+    }
+    else if (bio->type == WOLFSSL_BIO_FILE) {
+        int sz  = 100; /* read from file by 100 byte chuncks */
+        int idx = 0;
+        char* tmp = (char*)XMALLOC(sz, bio->heap, DYNAMIC_TYPE_OPENSSL);
+
+        memSz = 0;
+        if (tmp == NULL) {
+            WOLFSSL_MSG("Memory error");
+            ret = MEMORY_E;
+    }
+
+        while (ret >= 0 && (sz = wolfSSL_BIO_read(bio, tmp, sz)) > 0) {
+            if (memSz + sz < 0) {
+                /* sanity check */
+                break;
+        }
+            mem = (char*)XREALLOC(mem, memSz + sz, bio->heap,
+                    DYNAMIC_TYPE_OPENSSL);
+            if (mem == NULL) {
+                WOLFSSL_MSG("Memory error");
+                XFREE(tmp, bio->heap, DYNAMIC_TYPE_OPENSSL);
+                tmp = NULL;
+                ret = MEMORY_E;
+                break;
+            }
+            XMEMCPY(mem + idx, tmp, sz);
+            memSz += sz;
+            idx   += sz;
+            sz = 100; /* read another 100 byte chunck from file */
+            }
+        XFREE(tmp, bio->heap, DYNAMIC_TYPE_OPENSSL);
+        if (memSz <= 0) {
+            WOLFSSL_MSG("No data to read from bio");
+            if (mem != NULL) {
+                XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL);
+                mem = NULL;
+        }
+            ret = BUFFER_E;
+    }
+    }
+    else {
+        WOLFSSL_MSG("No data to read from bio");
+        ret = NOT_COMPILED_IN;
+}
+
+#ifdef WOLFSSL_SMALL_STACK
+    if (ret >= 0) {
+        info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), NULL,
+                                       DYNAMIC_TYPE_TMP_BUFFER);
+        if (info == NULL) {
+            WOLFSSL_MSG("Error getting memory for EncryptedInfo structure");
+            XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL);
+            mem = NULL;
+            ret = MEMORY_E;
+    }
+    }
+#endif
+
+    if (ret >= 0) {
+        XMEMSET(info, 0, sizeof(EncryptedInfo));
+        info->passwd_cb       = localCb;
+        info->passwd_userdata = pass;
+        ret = PemToDer((const unsigned char*)mem, memSz, keyType, der,
+            NULL, info, eccFlag);
+
+        if (ret < 0) {
+            WOLFSSL_MSG("Bad Pem To Der");
+        }
+    else {
+            /* write left over data back to bio */
+            if ((memSz - (int)info->consumed) > 0 &&
+                    bio->type != WOLFSSL_BIO_FILE) {
+                if (wolfSSL_BIO_write(bio, mem + (int)info->consumed,
+                                       memSz - (int)info->consumed) <= 0) {
+                    WOLFSSL_MSG("Unable to advance bio read pointer");
+                }
+    }
+}
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+    XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL);
+
+    return ret;
+}
+
 WOLFSSL_EVP_PKEY* wolfSSL_PEM_read_bio_PrivateKey(WOLFSSL_BIO* bio,
-                    WOLFSSL_EVP_PKEY** key, pem_password_cb* cb, void* arg)
-{
-    (void)bio;
-    (void)key;
-    (void)cb;
-    (void)arg;
-
-    WOLFSSL_MSG("wolfSSL_PEM_read_bio_PrivateKey not implemented");
-
-    return NULL;
-}
-
-
+                                                  WOLFSSL_EVP_PKEY** key,
+                                                  pem_password_cb* cb,
+                                                  void* pass)
+{
+    WOLFSSL_EVP_PKEY* pkey = NULL;
+    DerBuffer*        der = NULL;
+    int               eccFlag = 0;
+
+    WOLFSSL_ENTER("wolfSSL_PEM_read_bio_PrivateKey");
+
+    if (bio == NULL)
+        return pkey;
+
+    if (pem_read_bio_key(bio, cb, pass, PRIVATEKEY_TYPE, &eccFlag, &der) >= 0) {
+        int type;
+        const unsigned char* ptr = der->buffer;
+
+        if (eccFlag)
+            type = EVP_PKEY_EC;
+    else
+            type = EVP_PKEY_RSA;
+
+        /* handle case where reuse is attempted */
+        if (key != NULL && *key != NULL)
+            pkey = *key;
+
+        wolfSSL_d2i_PrivateKey(type, &pkey, &ptr, der->length);
+        if (pkey == NULL) {
+            WOLFSSL_MSG("Error loading DER buffer into WOLFSSL_EVP_PKEY");
+    }
+    }
+
+    FreeDer(&der);
+
+    if (key != NULL && pkey != NULL)
+        *key = pkey;
+
+    WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_PrivateKey", 0);
+
+    return pkey;
+    }
+
+WOLFSSL_EVP_PKEY *wolfSSL_PEM_read_bio_PUBKEY(WOLFSSL_BIO* bio,
+                                              WOLFSSL_EVP_PKEY **key,
+                                              pem_password_cb *cb, void *pass)
+{
+    WOLFSSL_EVP_PKEY* pkey = NULL;
+    DerBuffer*        der = NULL;
+    int               eccFlag = 0;
+
+    WOLFSSL_ENTER("wolfSSL_PEM_read_bio_PUBKEY");
+
+    if (bio == NULL)
+        return pkey;
+
+    if (pem_read_bio_key(bio, cb, pass, PUBLICKEY_TYPE, &eccFlag, &der) >= 0) {
+        unsigned char* ptr = der->buffer;
+
+        /* handle case where reuse is attempted */
+        if (key != NULL && *key != NULL)
+            pkey = *key;
+
+        wolfSSL_d2i_PUBKEY(&pkey, &ptr, der->length);
+        if (pkey == NULL) {
+            WOLFSSL_MSG("Error loading DER buffer into WOLFSSL_EVP_PKEY");
+    }
+}
+
+    FreeDer(&der);
+
+    if (key != NULL && pkey != NULL)
+        *key = pkey;
+
+    WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_PrivateKey", 0);
+
+    return pkey;
+}
+
+
+#ifndef NO_RSA
+/* Uses the same format of input as wolfSSL_PEM_read_bio_PrivateKey but expects
+ * the results to be an RSA key.
+ *
+ * bio  structure to read RSA private key from
+ * rsa  if not null is then set to the result
+ * cb   password callback for reading PEM
+ * pass password string
+ *
+ * returns a pointer to a new WOLFSSL_RSA structure on success and NULL on fail
+ */
+WOLFSSL_RSA* wolfSSL_PEM_read_bio_RSAPrivateKey(WOLFSSL_BIO* bio,
+        WOLFSSL_RSA** rsa, pem_password_cb* cb, void* pass)
+{
+    WOLFSSL_EVP_PKEY* pkey;
+    WOLFSSL_RSA* local;
+
+    pkey = wolfSSL_PEM_read_bio_PrivateKey(bio, NULL, cb, pass);
+    if (pkey == NULL) {
+        return NULL;
+    }
+
+    /* Since the WOLFSSL_RSA structure is being taken from WOLFSSL_EVP_PEKY the
+     * flag indicating that the WOLFSSL_RSA structure is owned should be FALSE
+     * to avoid having it free'd */
+    pkey->ownRsa = 0;
+    local = pkey->rsa;
+    if (rsa != NULL) {
+        *rsa = local;
+    }
+
+    wolfSSL_EVP_PKEY_free(pkey);
+    return local;
+}
+#endif /* !NO_RSA */
+
+
+/* return of pkey->type which will be EVP_PKEY_RSA for example.
+ *
+ * type  type of EVP_PKEY
+ *
+ * returns type or if type is not found then NID_undef
+ */
 int wolfSSL_EVP_PKEY_type(int type)
 {
-    (void) type;
-    WOLFSSL_MSG("wolfSSL_EVP_PKEY_type always returns EVP_PKEY_RSA");
-    return EVP_PKEY_RSA;
-}
+    WOLFSSL_MSG("wolfSSL_EVP_PKEY_type");
+
+    switch (type) {
+    #ifdef OPENSSL_EXTRA
+        case EVP_PKEY_RSA:
+            return EVP_PKEY_RSA;
+        case EVP_PKEY_DSA:
+            return EVP_PKEY_DSA;
+        case EVP_PKEY_EC:
+            return EVP_PKEY_EC;
+    #endif
+                default:
+            return NID_undef;
+            }
+        }
+
+
+int wolfSSL_EVP_PKEY_id(const EVP_PKEY *pkey)
+{
+    if (pkey != NULL)
+        return pkey->type;
+    return 0;
+    }
+
 
 int wolfSSL_EVP_PKEY_base_id(const EVP_PKEY *pkey)
 {
-    return EVP_PKEY_type(pkey->type);
+    if (pkey == NULL)
+        return NID_undef;
+    return wolfSSL_EVP_PKEY_type(pkey->type);
 }
 
 
 #if !defined(NO_FILESYSTEM)
-WOLFSSL_EVP_PKEY *wolfSSL_PEM_read_PUBKEY(FILE *fp, EVP_PKEY **x,
+WOLFSSL_EVP_PKEY *wolfSSL_PEM_read_PUBKEY(XFILE fp, EVP_PKEY **x,
                                           pem_password_cb *cb, void *u)
 {
@@ -22721,5 +28709,6 @@
 
 #if !defined(NO_FILESYSTEM)
-WOLFSSL_RSA *wolfSSL_PEM_read_RSAPublicKey(FILE *fp, WOLFSSL_RSA **x,
+#ifndef NO_WOLFSSL_STUB
+WOLFSSL_RSA *wolfSSL_PEM_read_RSAPublicKey(XFILE fp, WOLFSSL_RSA **x,
                                            pem_password_cb *cb, void *u)
 {
@@ -22728,40 +28717,215 @@
     (void)cb;
     (void)u;
-
+    WOLFSSL_STUB("PEM_read_RSAPublicKey");
     WOLFSSL_MSG("wolfSSL_PEM_read_RSAPublicKey not implemented");
 
     return NULL;
 }
-
+#endif
 /* return code compliant with OpenSSL :
  *   1 if success, 0 if error
  */
-int wolfSSL_PEM_write_RSAPublicKey(FILE *fp, WOLFSSL_RSA *x)
+#ifndef NO_WOLFSSL_STUB
+int wolfSSL_PEM_write_RSAPublicKey(XFILE fp, WOLFSSL_RSA *x)
 {
     (void)fp;
     (void)x;
-
+    WOLFSSL_STUB("PEM_write_RSAPublicKey");
     WOLFSSL_MSG("wolfSSL_PEM_write_RSAPublicKey not implemented");
 
     return WOLFSSL_FAILURE;
-}
+    }
+#endif
 
 /* return code compliant with OpenSSL :
  *   1 if success, 0 if error
  */
-int wolfSSL_PEM_write_RSA_PUBKEY(FILE *fp, WOLFSSL_RSA *x)
+#ifndef NO_WOLFSSL_STUB
+int wolfSSL_PEM_write_RSA_PUBKEY(XFILE fp, WOLFSSL_RSA *x)
 {
     (void)fp;
     (void)x;
-
+    WOLFSSL_STUB("PEM_write_RSA_PUBKEY");
     WOLFSSL_MSG("wolfSSL_PEM_write_RSA_PUBKEY not implemented");
 
     return WOLFSSL_FAILURE;
 }
+#endif
+
 #endif /* NO_FILESYSTEM */
 
+WOLFSSL_RSA *wolfSSL_d2i_RSAPublicKey(WOLFSSL_RSA **r, const unsigned char **pp,
+    long len)
+{
+    WOLFSSL_RSA *rsa = NULL;
+
+    WOLFSSL_ENTER("d2i_RSAPublicKey");
+
+    if (pp == NULL) {
+        WOLFSSL_MSG("Bad argument");
+        return NULL;
+    }
+    if ((rsa = wolfSSL_RSA_new()) == NULL) {
+        WOLFSSL_MSG("RSA_new failed");
+    return NULL;
+}
+
+    if (wolfSSL_RSA_LoadDer_ex(rsa, *pp, (int)len, WOLFSSL_RSA_LOAD_PUBLIC)
+                                                         != WOLFSSL_SUCCESS) {
+        WOLFSSL_MSG("RSA_LoadDer failed");
+        wolfSSL_RSA_free(rsa);
+        rsa = NULL;
+    }
+    if (r != NULL)
+        *r = rsa;
+
+    return rsa;
+}
+
+/* Converts an RSA private key from DER format to an RSA structure.
+Returns pointer to the RSA structure on success and NULL if error. */
+WOLFSSL_RSA *wolfSSL_d2i_RSAPrivateKey(WOLFSSL_RSA **r,
+                                       const unsigned char **derBuf, long derSz)
+{
+    WOLFSSL_RSA *rsa = NULL;
+
+    WOLFSSL_ENTER("wolfSSL_d2i_RSAPrivateKey");
+
+    /* check for bad functions arguments */
+    if (derBuf == NULL) {
+        WOLFSSL_MSG("Bad argument");
+        return NULL;
+    }
+    if ((rsa = wolfSSL_RSA_new()) == NULL) {
+        WOLFSSL_MSG("RSA_new failed");
+    return NULL;
+}
+
+    if (wolfSSL_RSA_LoadDer_ex(rsa, *derBuf, (int)derSz,
+                                 WOLFSSL_RSA_LOAD_PRIVATE) != WOLFSSL_SUCCESS) {
+        WOLFSSL_MSG("RSA_LoadDer failed");
+        wolfSSL_RSA_free(rsa);
+        rsa = NULL;
+    }
+    if (r != NULL)
+        *r = rsa;
+
+    return rsa;
+}
+
+#if !defined(HAVE_FAST_RSA)
+/* Converts an internal RSA structure to DER format.
+Returns size of DER on success and WOLFSSL_FAILURE if error */
+int wolfSSL_i2d_RSAPrivateKey(WOLFSSL_RSA *rsa, unsigned char **pp)
+{
+#if defined(WOLFSSL_KEY_GEN)
+    byte* der = NULL;
+    int derMax;
+    int ret;
+    int i;
+
+    WOLFSSL_ENTER("wolfSSL_i2d_RSAPrivateKey");
+
+    /* check for bad functions arguments */
+    if ((rsa == NULL) || (pp == NULL)) {
+        WOLFSSL_MSG("Bad Function Arguments");
+        return BAD_FUNC_ARG;
+}
+
+    if (rsa->inSet == 0) {
+        if ((ret = SetRsaInternal(rsa)) != WOLFSSL_SUCCESS) {
+            WOLFSSL_MSG("SetRsaInternal() Failed");
+            return ret;
+        }
+    }
+
+    /* 5 > size of n, d, p, q, d%(p-1), d(q-1), 1/q%p, e + ASN.1 additional
+     *  informations
+     */
+    derMax = 5 * wolfSSL_RSA_size(rsa) + AES_BLOCK_SIZE;
+
+    der = (byte*)XMALLOC(derMax, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (der == NULL) {
+        WOLFSSL_MSG("Malloc failed");
+        return WOLFSSL_FAILURE;
+    }
+
+    /* RSA key to DER */
+    if ((ret = wc_RsaKeyToDer((RsaKey *)rsa->internal, der, derMax)) < 0) {
+        WOLFSSL_MSG("wc_RsaKeyToDer() failed");
+        XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        der = NULL;
+        return ret;
+        }
+
+    /* ret is the size of the DER buffer */
+    for (i = 0; i < ret; i++) {
+        *(*pp + i) = *(der + i);
+    }
+    *pp += ret;
+
+    XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    return ret; /* returns size of DER if successful */
+#else
+    (void)rsa;
+    (void)pp;
+    WOLFSSL_MSG("Error, WOLFSSL_KEY_GEN not defined");
+    return WOLFSSL_FAILURE;
+#endif /* WOLFSSL_KEY_GEN */
+}
+
+
+int wolfSSL_i2d_RSAPublicKey(WOLFSSL_RSA *rsa, const unsigned char **pp)
+{
+    byte *der;
+    int derLen;
+    int ret;
+
+    WOLFSSL_ENTER("i2d_RSAPublicKey");
+    if (rsa == NULL)
+        return WOLFSSL_FATAL_ERROR;
+
+    if (rsa->inSet == 0) {
+        if ((ret = SetRsaInternal(rsa)) != WOLFSSL_SUCCESS) {
+            WOLFSSL_MSG("SetRsaInternal Failed");
+            return ret;
+        }
+        }
+    if ((derLen = RsaPublicKeyDerSize((RsaKey *)rsa->internal, 1)) < 0)
+        return WOLFSSL_FATAL_ERROR;
+    der = (byte*)XMALLOC(derLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (der == NULL) {
+        return WOLFSSL_FATAL_ERROR;
+    }
+    if ((ret = wc_RsaKeyToPublicDer((RsaKey *)rsa->internal, der, derLen)) < 0){
+        WOLFSSL_MSG("RsaKeyToPublicDer failed");
+        if(der != NULL)
+            XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return ret;
+    }
+    if ((pp != NULL) && (ret >= 0))
+        *pp = der;
+    else
+        XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+    return ret;
+}
+#endif /* #if !defined(HAVE_FAST_RSA) */
+
+#endif /* !NO_RSA */
+#endif /* OPENSSL_EXTRA */
+
+#if !defined(NO_RSA) && (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL))
 /* return WOLFSSL_SUCCESS if success, WOLFSSL_FATAL_ERROR if error */
 int wolfSSL_RSA_LoadDer(WOLFSSL_RSA* rsa, const unsigned char* derBuf, int derSz)
 {
+  return wolfSSL_RSA_LoadDer_ex(rsa, derBuf, derSz, WOLFSSL_RSA_LOAD_PRIVATE);
+}
+
+
+int wolfSSL_RSA_LoadDer_ex(WOLFSSL_RSA* rsa, const unsigned char* derBuf,
+                                                     int derSz, int opt)
+{
+
     word32 idx = 0;
     int    ret;
@@ -22774,8 +28938,19 @@
     }
 
-    ret = wc_RsaPrivateKeyDecode(derBuf, &idx, (RsaKey*)rsa->internal, derSz);
+    if (opt == WOLFSSL_RSA_LOAD_PRIVATE) {
+        ret = wc_RsaPrivateKeyDecode(derBuf, &idx, (RsaKey*)rsa->internal, derSz);
+    }
+    else {
+        ret = wc_RsaPublicKeyDecode(derBuf, &idx, (RsaKey*)rsa->internal, derSz);
+}
+
     if (ret < 0) {
-        WOLFSSL_MSG("RsaPrivateKeyDecode failed");
-        return WOLFSSL_FATAL_ERROR;
+        if (opt == WOLFSSL_RSA_LOAD_PRIVATE) {
+             WOLFSSL_MSG("RsaPrivateKeyDecode failed");
+        }
+        else {
+             WOLFSSL_MSG("RsaPublicKeyDecode failed");
+        }
+        return SSL_FATAL_ERROR;
     }
 
@@ -22791,5 +28966,5 @@
 #endif /* NO_RSA */
 
-
+#ifdef OPENSSL_EXTRA
 #ifndef NO_DSA
 /* return WOLFSSL_SUCCESS if success, WOLFSSL_FATAL_ERROR if error */
@@ -22810,5 +28985,5 @@
         WOLFSSL_MSG("DsaPrivateKeyDecode failed");
         return WOLFSSL_FATAL_ERROR;
-    }
+}
 
     if (SetDsaExternal(dsa) != WOLFSSL_SUCCESS) {
@@ -22825,6 +29000,13 @@
 #ifdef HAVE_ECC
 /* return WOLFSSL_SUCCESS if success, WOLFSSL_FATAL_ERROR if error */
-int wolfSSL_EC_KEY_LoadDer(WOLFSSL_EC_KEY* key,
-                           const unsigned char* derBuf,  int derSz)
+int wolfSSL_EC_KEY_LoadDer(WOLFSSL_EC_KEY* key, const unsigned char* derBuf,
+                           int derSz)
+{
+    return wolfSSL_EC_KEY_LoadDer_ex(key, derBuf, derSz,
+                                     WOLFSSL_EC_KEY_LOAD_PRIVATE);
+}
+
+int wolfSSL_EC_KEY_LoadDer_ex(WOLFSSL_EC_KEY* key, const unsigned char* derBuf,
+                              int derSz, int opt)
 {
     word32 idx = 0;
@@ -22838,7 +29020,19 @@
     }
 
-    ret = wc_EccPrivateKeyDecode(derBuf, &idx, (ecc_key*)key->internal, derSz);
+    if (opt == WOLFSSL_EC_KEY_LOAD_PRIVATE) {
+        ret = wc_EccPrivateKeyDecode(derBuf, &idx, (ecc_key*)key->internal,
+                                     derSz);
+    }
+    else {
+        ret = wc_EccPublicKeyDecode(derBuf, &idx, (ecc_key*)key->internal,
+                                    derSz);
+    }
     if (ret < 0) {
-        WOLFSSL_MSG("wc_EccPrivateKeyDecode failed");
+        if (opt == WOLFSSL_RSA_LOAD_PRIVATE) {
+            WOLFSSL_MSG("wc_EccPrivateKeyDecode failed");
+    }
+        else {
+            WOLFSSL_MSG("wc_EccPublicKeyDecode failed");
+    }
         return WOLFSSL_FATAL_ERROR;
     }
@@ -22847,5 +29041,5 @@
         WOLFSSL_MSG("SetECKeyExternal failed");
         return WOLFSSL_FATAL_ERROR;
-    }
+}
 
     key->inSet = 1;
@@ -22854,4 +29048,5 @@
 }
 #endif /* HAVE_ECC */
+
 
 #endif /* OPENSSL_EXTRA */
@@ -22892,5 +29087,5 @@
 
     return 0;
-}
+    }
 
 
@@ -22903,5 +29098,5 @@
 
     return 0;
-}
+    }
 
 
@@ -22941,9 +29136,9 @@
     WOLFSSL_ENTER("wolfSSL_get_chain_X509");
     if (chain != NULL) {
-    #ifdef WOLFSSL_SMALL_STACK
+#ifdef WOLFSSL_SMALL_STACK
         cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
                                                        DYNAMIC_TYPE_DCERT);
         if (cert != NULL)
-    #endif
+#endif
         {
             InitDecodedCert(cert, chain->certs[idx].buffer,
@@ -22953,10 +29148,10 @@
                 WOLFSSL_MSG("Failed to parse cert");
             }
-            else {
+    else {
                 x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL,
                                                              DYNAMIC_TYPE_X509);
                 if (x509 == NULL) {
                     WOLFSSL_MSG("Failed alloc X509");
-                }
+    }
                 else {
                     InitX509(x509, 1, NULL);
@@ -22964,15 +29159,15 @@
                     if ((ret = CopyDecodedToX509(x509, cert)) != 0) {
                         WOLFSSL_MSG("Failed to copy decoded");
-                        XFREE(x509, NULL, DYNAMIC_TYPE_X509);
+                        wolfSSL_X509_free(x509);
                         x509 = NULL;
-                    }
-                }
-            }
+    }
+    }
+    }
 
             FreeDecodedCert(cert);
-        #ifdef WOLFSSL_SMALL_STACK
+#ifdef WOLFSSL_SMALL_STACK
             XFREE(cert, NULL, DYNAMIC_TYPE_DCERT);
-        #endif
-        }
+#endif
+    }
     }
     (void)ret;
@@ -22988,9 +29183,9 @@
                                unsigned char* buf, int inLen, int* outLen)
 {
-    const char header[] = "-----BEGIN CERTIFICATE-----\n";
-    const char footer[] = "-----END CERTIFICATE-----\n";
-
-    int headerLen = sizeof(header) - 1;
-    int footerLen = sizeof(footer) - 1;
+#if defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM)
+    const char* header = NULL;
+    const char* footer = NULL;
+    int headerLen;
+    int footerLen;
     int i;
     int err;
@@ -23000,4 +29195,11 @@
     if (!chain || !outLen || idx < 0 || idx >= wolfSSL_get_chain_count(chain))
         return BAD_FUNC_ARG;
+
+    err = wc_PemGetHeaderFooter(CERT_TYPE, &header, &footer);
+    if (err != 0)
+        return err;
+
+    headerLen = (int)XSTRLEN(header);
+    footerLen = (int)XSTRLEN(footer);
 
     /* Null output buffer return size needed in outLen */
@@ -23005,5 +29207,5 @@
         if(Base64_Encode(chain->certs[idx].buffer, chain->certs[idx].length,
                     NULL, &szNeeded) != LENGTH_ONLY_E)
-            return WOLFSSL_FAILURE;
+        return WOLFSSL_FAILURE;
         *outLen = szNeeded + headerLen + footerLen;
         return LENGTH_ONLY_E;
@@ -23035,4 +29237,12 @@
 
     return WOLFSSL_SUCCESS;
+#else
+    (void)chain;
+    (void)idx;
+    (void)buf;
+    (void)inLen;
+    (void)outLen;
+    return WOLFSSL_FAILURE;
+#endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */
 }
 
@@ -23046,5 +29256,5 @@
 
     return NULL;
-}
+    }
 
 
@@ -23057,6 +29267,6 @@
         ssl->fuzzerCb  = cbf;
         ssl->fuzzerCtx = fCtx;
-    }
-}
+        }
+    }
 #endif
 
@@ -23065,4 +29275,21 @@
 
 #ifdef HAVE_ECC
+void  wolfSSL_CTX_SetEccKeyGenCb(WOLFSSL_CTX* ctx, CallbackEccKeyGen cb)
+{
+    if (ctx)
+        ctx->EccKeyGenCb = cb;
+    }
+void  wolfSSL_SetEccKeyGenCtx(WOLFSSL* ssl, void *ctx)
+{
+    if (ssl)
+        ssl->EccKeyGenCtx = ctx;
+    }
+void* wolfSSL_GetEccKeyGenCtx(WOLFSSL* ssl)
+{
+    if (ssl)
+        return ssl->EccKeyGenCtx;
+
+    return NULL;
+        }
 
 void  wolfSSL_CTX_SetEccSignCb(WOLFSSL_CTX* ctx, CallbackEccSign cb)
@@ -23070,14 +29297,10 @@
     if (ctx)
         ctx->EccSignCb = cb;
-}
-
-
+    }
 void  wolfSSL_SetEccSignCtx(WOLFSSL* ssl, void *ctx)
 {
     if (ssl)
         ssl->EccSignCtx = ctx;
-}
-
-
+    }
 void* wolfSSL_GetEccSignCtx(WOLFSSL* ssl)
 {
@@ -23086,6 +29309,5 @@
 
     return NULL;
-}
-
+    }
 
 void  wolfSSL_CTX_SetEccVerifyCb(WOLFSSL_CTX* ctx, CallbackEccVerify cb)
@@ -23093,14 +29315,10 @@
     if (ctx)
         ctx->EccVerifyCb = cb;
-}
-
-
+    }
 void  wolfSSL_SetEccVerifyCtx(WOLFSSL* ssl, void *ctx)
 {
     if (ssl)
         ssl->EccVerifyCtx = ctx;
-}
-
-
+    }
 void* wolfSSL_GetEccVerifyCtx(WOLFSSL* ssl)
 {
@@ -23115,13 +29333,10 @@
     if (ctx)
         ctx->EccSharedSecretCb = cb;
-}
-
+    }
 void  wolfSSL_SetEccSharedSecretCtx(WOLFSSL* ssl, void *ctx)
 {
     if (ssl)
         ssl->EccSharedSecretCtx = ctx;
-}
-
-
+    }
 void* wolfSSL_GetEccSharedSecretCtx(WOLFSSL* ssl)
 {
@@ -23130,5 +29345,5 @@
 
     return NULL;
-}
+    }
 #endif /* HAVE_ECC */
 
@@ -23139,6 +29354,4 @@
         ctx->Ed25519SignCb = cb;
 }
-
-
 void  wolfSSL_SetEd25519SignCtx(WOLFSSL* ssl, void *ctx)
 {
@@ -23146,6 +29359,4 @@
         ssl->Ed25519SignCtx = ctx;
 }
-
-
 void* wolfSSL_GetEd25519SignCtx(WOLFSSL* ssl)
 {
@@ -23154,6 +29365,5 @@
 
     return NULL;
-}
-
+    }
 
 void  wolfSSL_CTX_SetEd25519VerifyCb(WOLFSSL_CTX* ctx, CallbackEd25519Verify cb)
@@ -23161,14 +29371,10 @@
     if (ctx)
         ctx->Ed25519VerifyCb = cb;
-}
-
-
+    }
 void  wolfSSL_SetEd25519VerifyCtx(WOLFSSL* ssl, void *ctx)
 {
     if (ssl)
         ssl->Ed25519VerifyCtx = ctx;
-}
-
-
+    }
 void* wolfSSL_GetEd25519VerifyCtx(WOLFSSL* ssl)
 {
@@ -23177,8 +29383,27 @@
 
     return NULL;
-}
-#endif
+    }
+#endif /* HAVE_ED25519 */
 
 #ifdef HAVE_CURVE25519
+void wolfSSL_CTX_SetX25519KeyGenCb(WOLFSSL_CTX* ctx,
+        CallbackX25519KeyGen cb)
+{
+    if (ctx)
+        ctx->X25519KeyGenCb = cb;
+}
+void  wolfSSL_SetX25519KeyGenCtx(WOLFSSL* ssl, void *ctx)
+{
+    if (ssl)
+        ssl->X25519KeyGenCtx = ctx;
+}
+void* wolfSSL_GetX25519KeyGenCtx(WOLFSSL* ssl)
+{
+    if (ssl)
+        return ssl->X25519KeyGenCtx;
+
+    return NULL;
+    }
+
 void wolfSSL_CTX_SetX25519SharedSecretCb(WOLFSSL_CTX* ctx,
         CallbackX25519SharedSecret cb)
@@ -23187,5 +29412,4 @@
         ctx->X25519SharedSecretCb = cb;
 }
-
 void  wolfSSL_SetX25519SharedSecretCtx(WOLFSSL* ssl, void *ctx)
 {
@@ -23193,6 +29417,4 @@
         ssl->X25519SharedSecretCtx = ctx;
 }
-
-
 void* wolfSSL_GetX25519SharedSecretCtx(WOLFSSL* ssl)
 {
@@ -23201,9 +29423,8 @@
 
     return NULL;
-}
-#endif
+    }
+#endif /* HAVE_CURVE25519 */
 
 #ifndef NO_RSA
-
 void  wolfSSL_CTX_SetRsaSignCb(WOLFSSL_CTX* ctx, CallbackRsaSign cb)
 {
@@ -23211,13 +29432,14 @@
         ctx->RsaSignCb = cb;
 }
-
-
+void  wolfSSL_CTX_SetRsaSignCheckCb(WOLFSSL_CTX* ctx, CallbackRsaVerify cb)
+{
+    if (ctx)
+        ctx->RsaSignCheckCb = cb;
+}
 void  wolfSSL_SetRsaSignCtx(WOLFSSL* ssl, void *ctx)
 {
     if (ssl)
         ssl->RsaSignCtx = ctx;
-}
-
-
+    }
 void* wolfSSL_GetRsaSignCtx(WOLFSSL* ssl)
 {
@@ -23226,5 +29448,5 @@
 
     return NULL;
-}
+    }
 
 
@@ -23234,13 +29456,9 @@
         ctx->RsaVerifyCb = cb;
 }
-
-
 void  wolfSSL_SetRsaVerifyCtx(WOLFSSL* ssl, void *ctx)
 {
     if (ssl)
         ssl->RsaVerifyCtx = ctx;
-}
-
-
+    }
 void* wolfSSL_GetRsaVerifyCtx(WOLFSSL* ssl)
 {
@@ -23249,5 +29467,5 @@
 
     return NULL;
-}
+        }
 
 #ifdef WC_RSA_PSS
@@ -23256,14 +29474,15 @@
     if (ctx)
         ctx->RsaPssSignCb = cb;
-}
-
-
+    }
+void  wolfSSL_CTX_SetRsaPssSignCheckCb(WOLFSSL_CTX* ctx, CallbackRsaPssVerify cb)
+{
+    if (ctx)
+        ctx->RsaPssSignCheckCb = cb;
+        }
 void  wolfSSL_SetRsaPssSignCtx(WOLFSSL* ssl, void *ctx)
 {
     if (ssl)
         ssl->RsaPssSignCtx = ctx;
-}
-
-
+    }
 void* wolfSSL_GetRsaPssSignCtx(WOLFSSL* ssl)
 {
@@ -23274,19 +29493,14 @@
 }
 
-
 void  wolfSSL_CTX_SetRsaPssVerifyCb(WOLFSSL_CTX* ctx, CallbackRsaPssVerify cb)
 {
     if (ctx)
         ctx->RsaPssVerifyCb = cb;
-}
-
-
+    }
 void  wolfSSL_SetRsaPssVerifyCtx(WOLFSSL* ssl, void *ctx)
 {
     if (ssl)
         ssl->RsaPssVerifyCtx = ctx;
-}
-
-
+    }
 void* wolfSSL_GetRsaPssVerifyCtx(WOLFSSL* ssl)
 {
@@ -23295,6 +29509,6 @@
 
     return NULL;
-}
-#endif
+        }
+#endif /* WC_RSA_PSS */
 
 void  wolfSSL_CTX_SetRsaEncCb(WOLFSSL_CTX* ctx, CallbackRsaEnc cb)
@@ -23302,14 +29516,10 @@
     if (ctx)
         ctx->RsaEncCb = cb;
-}
-
-
+    }
 void  wolfSSL_SetRsaEncCtx(WOLFSSL* ssl, void *ctx)
 {
     if (ssl)
         ssl->RsaEncCtx = ctx;
-}
-
-
+        }
 void* wolfSSL_GetRsaEncCtx(WOLFSSL* ssl)
 {
@@ -23318,5 +29528,5 @@
 
     return NULL;
-}
+    }
 
 void  wolfSSL_CTX_SetRsaDecCb(WOLFSSL_CTX* ctx, CallbackRsaDec cb)
@@ -23325,6 +29535,4 @@
         ctx->RsaDecCb = cb;
 }
-
-
 void  wolfSSL_SetRsaDecCtx(WOLFSSL* ssl, void *ctx)
 {
@@ -23332,6 +29540,4 @@
         ssl->RsaDecCtx = ctx;
 }
-
-
 void* wolfSSL_GetRsaDecCtx(WOLFSSL* ssl)
 {
@@ -23339,12 +29545,30 @@
         return ssl->RsaDecCtx;
 
-    return NULL;
-}
-
-
+        return NULL;
+    }
 #endif /* NO_RSA */
 
 #endif /* HAVE_PK_CALLBACKS */
 #endif /* NO_CERTS */
+
+#if defined(HAVE_PK_CALLBACKS) && !defined(NO_DH)
+void wolfSSL_CTX_SetDhAgreeCb(WOLFSSL_CTX* ctx, CallbackDhAgree cb)
+{
+    if (ctx)
+        ctx->DhAgreeCb = cb;
+    }
+void wolfSSL_SetDhAgreeCtx(WOLFSSL* ssl, void *ctx)
+{
+    if (ssl)
+        ssl->DhAgreeCtx = ctx;
+}
+void* wolfSSL_GetDhAgreeCtx(WOLFSSL* ssl)
+{
+    if (ssl)
+        return ssl->DhAgreeCtx;
+
+    return NULL;
+    }
+#endif /* HAVE_PK_CALLBACKS && !NO_DH */
 
 
@@ -23364,11 +29588,277 @@
 
     #ifndef NO_CERTS
+    void wolfSSL_X509_NAME_free(WOLFSSL_X509_NAME *name){
+        WOLFSSL_ENTER("wolfSSL_X509_NAME_free");
+        FreeX509Name(name, NULL);
+        XFREE(name, NULL, DYNAMIC_TYPE_X509);
+    }
+
+
+    /* Malloc's a new WOLFSSL_X509_NAME structure
+     *
+     * returns NULL on failure, otherwise returns a new structure.
+     */
+    WOLFSSL_X509_NAME* wolfSSL_X509_NAME_new(void)
+{
+        WOLFSSL_X509_NAME* name;
+
+        WOLFSSL_ENTER("wolfSSL_X509_NAME_new");
+
+        name = (WOLFSSL_X509_NAME*)XMALLOC(sizeof(WOLFSSL_X509_NAME), NULL,
+                DYNAMIC_TYPE_X509);
+        if (name != NULL) {
+            InitX509Name(name, 1);
+    }
+        return name;
+        }
+
+
+#if defined(WOLFSSL_CERT_GEN) && !defined(NO_RSA)
+/* needed SetName function from asn.c is wrapped by NO_RSA */
+    /* helper function for CopyX509NameToCertName()
+     *
+     * returns WOLFSSL_SUCCESS on success
+     */
+    static int CopyX509NameEntry(char* out, int mx, char* in, int inLen)
+{
+        if (inLen > mx) {
+            WOLFSSL_MSG("Name too long");
+            XMEMCPY(out, in, mx);
+        }
+        else {
+            XMEMCPY(out, in, inLen);
+            out[inLen] = '\0';
+    }
+
+        /* make sure is null terminated */
+        out[mx-1] = '\0';
+
+        return WOLFSSL_SUCCESS;
+}
+
+
+    /* Helper function to copy cert name from a WOLFSSL_X509_NAME structure to
+     * a CertName structure.
+     *
+     * returns WOLFSSL_SUCCESS on success and a negative error value on failure
+     */
+    static int CopyX509NameToCertName(WOLFSSL_X509_NAME* n, CertName* cName)
+{
+        DecodedName* dn = NULL;
+
+        if (n == NULL || cName == NULL) {
+            return BAD_FUNC_ARG;
+        }
+
+        dn = &(n->fullName);
+
+        /* initialize cert name */
+        cName->country[0] = '\0';
+        cName->countryEnc = CTC_PRINTABLE;
+        cName->state[0] = '\0';
+        cName->stateEnc = CTC_UTF8;
+        cName->locality[0] = '\0';
+        cName->localityEnc = CTC_UTF8;
+        cName->sur[0] = '\0';
+        cName->surEnc = CTC_UTF8;
+        cName->org[0] = '\0';
+        cName->orgEnc = CTC_UTF8;
+        cName->unit[0] = '\0';
+        cName->unitEnc = CTC_UTF8;
+        cName->commonName[0] = '\0';
+        cName->commonNameEnc = CTC_UTF8;
+        cName->serialDev[0] = '\0';
+        cName->serialDevEnc = CTC_PRINTABLE;
+    #ifdef WOLFSSL_CERT_EXT
+        cName->busCat[0] = '\0';
+        cName->busCatEnc = CTC_UTF8;
+        cName->serialDev[0] = '\0';
+        cName->serialDevEnc = CTC_PRINTABLE;
+        cName->joiC[0] = '\0';
+        cName->joiCEnc = CTC_PRINTABLE;
+        cName->joiSt[0] = '\0';
+        cName->joiStEnc = CTC_PRINTABLE;
+    #endif
+        cName->email[0] = '\0';
+
+
+        /* ASN_COUNTRY_NAME */
+        WOLFSSL_MSG("Copy Country Name");
+        if (CopyX509NameEntry(cName->country, CTC_NAME_SIZE, dn->fullName + dn->cIdx,
+                    dn->cLen) != SSL_SUCCESS) {
+            return BUFFER_E;
+    }
+
+        /* ASN_ORGUNIT_NAME */
+        WOLFSSL_MSG("Copy Org Unit Name");
+        if (CopyX509NameEntry(cName->unit, CTC_NAME_SIZE, dn->fullName + dn->ouIdx,
+                    dn->ouLen) != SSL_SUCCESS) {
+            return BUFFER_E;
+        }
+
+        /* ASN_ORG_NAME */
+        WOLFSSL_MSG("Copy Org Name");
+        if (CopyX509NameEntry(cName->org, CTC_NAME_SIZE, dn->fullName + dn->oIdx,
+                    dn->oLen) != SSL_SUCCESS) {
+            return BUFFER_E;
+    }
+
+        /* ASN_STATE_NAME */
+        WOLFSSL_MSG("Copy State Name");
+        if (CopyX509NameEntry(cName->state, CTC_NAME_SIZE, dn->fullName + dn->stIdx,
+                    dn->stLen) != SSL_SUCCESS) {
+            return BUFFER_E;
+        }
+
+        /* ASN_LOCALITY_NAME */
+        WOLFSSL_MSG("Copy Locality Name");
+        if (CopyX509NameEntry(cName->locality, CTC_NAME_SIZE,
+                    dn->fullName + dn->lIdx, dn->lLen)
+                    != SSL_SUCCESS) {
+            return BUFFER_E;
+    }
+
+        /* ASN_SUR_NAME */
+        WOLFSSL_MSG("Copy Sur Name");
+        if (CopyX509NameEntry(cName->sur, CTC_NAME_SIZE, dn->fullName + dn->snIdx,
+                    dn->snLen) != SSL_SUCCESS) {
+            return BUFFER_E;
+        }
+
+        /* ASN_COMMON_NAME */
+        WOLFSSL_MSG("Copy Common Name");
+        if (CopyX509NameEntry(cName->commonName, CTC_NAME_SIZE,
+                    dn->fullName + dn->cnIdx, dn->cnLen)
+                    != SSL_SUCCESS) {
+            return BUFFER_E;
+    }
+
+        /* ASN_SERIAL_NUMBER */
+        WOLFSSL_MSG("Copy Serial Number of Device");
+        if (CopyX509NameEntry(cName->serialDev, CTC_NAME_SIZE,
+                    dn->fullName + dn->serialIdx, dn->serialLen)
+                    != SSL_SUCCESS) {
+            return BUFFER_E;
+    }
+
+    #ifdef WOLFSSL_CERT_EXT
+        /* ASN_BUS_CAT */
+        WOLFSSL_MSG("Copy Business Category");
+        if (CopyX509NameEntry(cName->busCat, CTC_NAME_SIZE,
+                    dn->fullName + dn->bcIdx, dn->bcLen)
+                    != SSL_SUCCESS) {
+            return BUFFER_E;
+}
+
+        /* JoI Country */
+        WOLFSSL_MSG("Copy Jurisdiction of Incorporation Country");
+        if (CopyX509NameEntry(cName->joiC, CTC_NAME_SIZE,
+                    dn->fullName + dn->jcIdx, dn->jcLen)
+                    != SSL_SUCCESS) {
+            return BUFFER_E;
+        }
+
+        /* JoI State */
+        WOLFSSL_MSG("Copy Jurisdiction of Incorporation State");
+        if (CopyX509NameEntry(cName->joiSt, CTC_NAME_SIZE,
+                    dn->fullName + dn->jsIdx, dn->jsLen)
+                    != SSL_SUCCESS) {
+            return BUFFER_E;
+        }
+    #endif
+
+        WOLFSSL_MSG("Copy Email");
+        if (CopyX509NameEntry(cName->email, CTC_NAME_SIZE,
+                    dn->fullName + dn->emailIdx, dn->emailLen)
+                    != SSL_SUCCESS) {
+            return BUFFER_E;
+    }
+
+        return WOLFSSL_SUCCESS;
+}
+
+
+    /* Converts the x509 name structure into DER format.
+     *
+     * out  pointer to either a pre setup buffer or a pointer to null for
+     *      creating a dynamic buffer. In the case that a pre-existing buffer is
+     *      used out will be incremented the size of the DER buffer on success.
+     *
+     * returns the size of the buffer on success, or negative value with failure
+     */
+    int wolfSSL_i2d_X509_NAME(WOLFSSL_X509_NAME* name, unsigned char** out)
+{
+        CertName cName;
+        unsigned char buf[256]; /* ASN_MAX_NAME */
+        int sz;
+
+        if (out == NULL || name == NULL) {
+            return BAD_FUNC_ARG;
+        }
+
+        if (CopyX509NameToCertName(name, &cName) != SSL_SUCCESS) {
+            WOLFSSL_MSG("Error converting x509 name to internal CertName");
+            return SSL_FATAL_ERROR;
+}
+
+        sz = SetName(buf, sizeof(buf), &cName);
+        if (sz < 0) {
+            return sz;
+        }
+
+        /* using buffer passed in */
+        if (*out != NULL) {
+            XMEMCPY(*out, buf, sz);
+            *out += sz;
+        }
+        else {
+            *out = (unsigned char*)XMALLOC(sz, NULL, DYNAMIC_TYPE_OPENSSL);
+            if (*out == NULL) {
+                return MEMORY_E;
+            }
+            XMEMCPY(*out, buf, sz);
+        }
+
+        return sz;
+    }
+#endif /* WOLFSSL_CERT_GEN */
+
+
+    /* Compares the two X509 names. If the size of x is larger then y then a
+     * positive value is returned if x is smaller a negative value is returned.
+     * In the case that the sizes are equal a the value of memcmp between the
+     * two names is returned.
+     *
+     * x First name for comparison
+     * y Second name to compare with x
+     */
+    int wolfSSL_X509_NAME_cmp(const WOLFSSL_X509_NAME* x,
+            const WOLFSSL_X509_NAME* y)
+    {
+        WOLFSSL_STUB("wolfSSL_X509_NAME_cmp");
+
+        if (x == NULL || y == NULL) {
+            WOLFSSL_MSG("Bad argument passed in");
+            return -2;
+        }
+
+        if ((x->sz - y->sz) != 0) {
+            return x->sz - y->sz;
+    }
+    else {
+            return XMEMCMP(x->name, y->name, x->sz); /* y sz is the same */
+    }
+    }
+
+
     WOLFSSL_X509 *wolfSSL_PEM_read_bio_X509(WOLFSSL_BIO *bp, WOLFSSL_X509 **x,
                                                  pem_password_cb *cb, void *u)
     {
         WOLFSSL_X509* x509 = NULL;
+#if defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM)
         unsigned char* pem = NULL;
         int pemSz;
         long  i = 0, l;
+        const char* footer = NULL;
 
         WOLFSSL_ENTER("wolfSSL_PEM_read_bio_X509");
@@ -23377,7 +29867,7 @@
             WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_X509", BAD_FUNC_ARG);
             return NULL;
-        }
-
-        if (bp->type == BIO_MEMORY) {
+    }
+
+        if (bp->type == WOLFSSL_BIO_MEMORY) {
             l = (long)wolfSSL_BIO_ctrl_pending(bp);
             if (l <= 0) {
@@ -23385,6 +29875,6 @@
                 return NULL;
             }
-        }
-        else if (bp->type == BIO_FILE) {
+}
+        else if (bp->type == WOLFSSL_BIO_FILE) {
 #ifndef NO_FILESYSTEM
             /* Read in next certificate from file but no more. */
@@ -23392,42 +29882,52 @@
             if (i < 0)
                 return NULL;
-            XFSEEK(bp->file, 0, SEEK_END);
+            if (XFSEEK(bp->file, 0, XSEEK_END) != 0)
+                return NULL;
             l = XFTELL(bp->file);
             if (l < 0)
                 return NULL;
-            XFSEEK(bp->file, i, SEEK_SET);
+            if (XFSEEK(bp->file, i, SEEK_SET) != 0)
+                return NULL;
+
+            /* check calculated length */
+            if (l - i < 0)
+                return NULL;
+
+            l -= i;
 #else
             WOLFSSL_MSG("Unable to read file with NO_FILESYSTEM defined");
             return NULL;
-#endif
-        }
+#endif /* !NO_FILESYSTEM */
+}
         else
             return NULL;
 
-        /* check calulated length */
-        if (l - i < 0)
-            return NULL;
-        pem = (unsigned char*)XMALLOC(l - i, 0, DYNAMIC_TYPE_PEM);
+        pem = (unsigned char*)XMALLOC(l, 0, DYNAMIC_TYPE_PEM);
         if (pem == NULL)
             return NULL;
 
         i = 0;
+        if (wc_PemGetHeaderFooter(CERT_TYPE, NULL, &footer) != 0) {
+            XFREE(pem, 0, DYNAMIC_TYPE_PEM);
+            return NULL;
+        }
+
         /* TODO: Inefficient
-         * reading in one byte at a time until see END_CERT
+         * reading in one byte at a time until see "END CERTIFICATE"
          */
         while ((l = wolfSSL_BIO_read(bp, (char *)&pem[i], 1)) == 1) {
             i++;
-            if (i > 26 && XMEMCMP((char *)&pem[i-26], END_CERT, 25) == 0) {
+            if (i > 26 && XMEMCMP((char *)&pem[i-26], footer, 25) == 0) {
                 if (pem[i-1] == '\r') {
                     /* found \r , Windows line ending is \r\n so try to read one
-                     * more byte for \n */
-                    wolfSSL_BIO_read(bp, (char *)&pem[i++], 1);
+                     * more byte for \n, ignoring return value */
+                    (void)wolfSSL_BIO_read(bp, (char *)&pem[i++], 1);
                 }
                 break;
             }
-        }
-    #ifdef WOLFSSL_NGINX
+    }
+    #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX)
         if (l == 0)
-            WOLFSSL_ERROR(SSL_NO_PEM_HEADER);
+            WOLFSSL_ERROR(ASN_NO_PEM_HEADER);
     #endif
         pemSz = (int)i;
@@ -23441,4 +29941,7 @@
         XFREE(pem, NULL, DYNAMIC_TYPE_PEM);
 
+#endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */
+        (void)bp;
+        (void)x;
         (void)cb;
         (void)u;
@@ -23447,4 +29950,456 @@
     }
 
+#if defined(HAVE_CRL) && !defined(NO_FILESYSTEM)
+    static void* wolfSSL_PEM_read_X509_ex(XFILE fp, void **x,
+                                                    pem_password_cb *cb, void *u, int type)
+    {
+        unsigned char* pem = NULL;
+        int pemSz;
+        long  i = 0, l;
+        void *newx509;
+
+        WOLFSSL_ENTER("wolfSSL_PEM_read_X509");
+
+        if (fp == XBADFILE) {
+            WOLFSSL_LEAVE("wolfSSL_PEM_read_X509", BAD_FUNC_ARG);
+            return NULL;
+        }
+        /* Read cert from file */
+        i = XFTELL(fp);
+        if (i < 0) {
+            WOLFSSL_LEAVE("wolfSSL_PEM_read_X509", BAD_FUNC_ARG);
+            return NULL;
+    }
+
+        if (XFSEEK(fp, 0, XSEEK_END) != 0)
+            return NULL;
+        l = XFTELL(fp);
+        if (l < 0)
+            return NULL;
+        if (XFSEEK(fp, i, SEEK_SET) != 0)
+            return NULL;
+        pemSz = (int)(l - i);
+        /* check calculated length */
+        if (pemSz  < 0)
+            return NULL;
+        if((pem = (unsigned char*)XMALLOC(pemSz, 0, DYNAMIC_TYPE_PEM)) == NULL)
+            return NULL;
+
+        if((int)XFREAD((char *)pem, 1, pemSz, fp) != pemSz)
+            goto err_exit;
+
+        switch(type){
+        case CERT_TYPE:
+            newx509 = (void *)wolfSSL_X509_load_certificate_buffer(pem, pemSz,
+                                                              WOLFSSL_FILETYPE_PEM);
+            break;
+        #ifdef HAVE_CRL
+        case CRL_TYPE:
+            {
+                int derSz;
+                DerBuffer* der = NULL;
+                if((PemToDer(pem, pemSz, CRL_TYPE, &der, NULL, NULL, NULL)) < 0)
+                    goto err_exit;
+                derSz = der->length;
+                if((newx509 = (void *)wolfSSL_d2i_X509_CRL(
+                    (WOLFSSL_X509_CRL **)x, (const unsigned char *)der->buffer, derSz)) == NULL)
+                    goto err_exit;
+                FreeDer(&der);
+                break;
+    }
+        #endif
+
+        default:
+            goto err_exit;
+    }
+        if (x != NULL) {
+            *x = newx509;
+    }
+        XFREE(pem, 0, DYNAMIC_TYPE_PEM);
+        return newx509;
+
+    err_exit:
+        if(pem != NULL)
+            XFREE(pem, 0, DYNAMIC_TYPE_PEM);
+        return NULL;
+
+        (void)cb;
+        (void)u;
+
+    }
+
+    WOLFSSL_API WOLFSSL_X509* wolfSSL_PEM_read_X509(XFILE fp, WOLFSSL_X509 **x,
+                                                    pem_password_cb *cb, void *u)
+    {
+        return (WOLFSSL_X509* )wolfSSL_PEM_read_X509_ex(fp, (void **)x, cb, u, CERT_TYPE);
+    }
+
+#if defined(HAVE_CRL)
+    WOLFSSL_API WOLFSSL_X509_CRL* wolfSSL_PEM_read_X509_CRL(XFILE fp, WOLFSSL_X509_CRL **crl,
+                                                    pem_password_cb *cb, void *u)
+    {
+        return (WOLFSSL_X509_CRL* )wolfSSL_PEM_read_X509_ex(fp, (void **)crl, cb, u, CRL_TYPE);
+}
+#endif
+
+    int wolfSSL_PEM_write_X509(XFILE fp, WOLFSSL_X509* x)
+{
+        int ret;
+        WOLFSSL_BIO* bio;
+
+        if (x == NULL)
+            return 0;
+
+        bio = wolfSSL_BIO_new(wolfSSL_BIO_s_file());
+        if (bio == NULL)
+        return 0;
+
+        if (wolfSSL_BIO_set_fp(bio, fp, BIO_NOCLOSE) != WOLFSSL_SUCCESS) {
+            wolfSSL_BIO_free(bio);
+            bio = NULL;
+}
+
+        ret = wolfSSL_PEM_write_bio_X509(bio, x);
+
+        if (bio != NULL)
+            wolfSSL_BIO_free(bio);
+
+        return ret;
+}
+#endif
+
+    #define PEM_BEGIN              "-----BEGIN "
+    #define PEM_BEGIN_SZ           11
+    #define PEM_END                "-----END "
+    #define PEM_END_SZ             9
+    #define PEM_HDR_FIN            "-----"
+    #define PEM_HDR_FIN_SZ         5
+    #define PEM_HDR_FIN_EOL        "-----\n"
+    #define PEM_HDR_FIN_EOL_SZ     6
+
+    int wolfSSL_PEM_read_bio(WOLFSSL_BIO* bio, char **name, char **header,
+                             unsigned char **data, long *len)
+{
+        int ret = WOLFSSL_SUCCESS;
+        char pem[256];
+        int pemLen;
+        char* p;
+        char* nameStr = NULL;
+        int nameLen = 0;
+        char* headerStr = NULL;
+        int headerLen;
+        int headerFound = 0;
+        unsigned char* der = NULL;
+        word32 derLen;
+
+        if (bio == NULL || name == NULL || header == NULL || data == NULL ||
+                                                                  len == NULL) {
+            return WOLFSSL_FAILURE;
+        }
+
+        /* Find header line. */
+        pem[sizeof(pem) - 1] = '\0';
+        while ((pemLen = wolfSSL_BIO_gets(bio, pem, sizeof(pem) - 1)) > 0) {
+            if (XSTRNCMP(pem, PEM_BEGIN, PEM_BEGIN_SZ) == 0)
+                break;
+        }
+        if (pemLen <= 0)
+            ret = WOLFSSL_FAILURE;
+        /* Have a header line. */
+        if (ret == WOLFSSL_SUCCESS) {
+            while (pem[pemLen - 1] == '\r' || pem[pemLen - 1] == '\n')
+                pemLen--;
+            pem[pemLen] = '\0';
+            if (XSTRNCMP(pem + pemLen - PEM_HDR_FIN_SZ, PEM_HDR_FIN,
+                                                         PEM_HDR_FIN_SZ) != 0) {
+                ret = WOLFSSL_FAILURE;
+            }
+    }
+
+        /* Get out name. */
+        if (ret == WOLFSSL_SUCCESS) {
+            nameLen = pemLen - PEM_BEGIN_SZ - PEM_HDR_FIN_SZ;
+            nameStr = (char*)XMALLOC(nameLen + 1, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+            if (nameStr == NULL)
+                ret = WOLFSSL_FAILURE;
+        }
+        if (ret == WOLFSSL_SUCCESS) {
+            XSTRNCPY(nameStr, pem + PEM_BEGIN_SZ, nameLen);
+            nameStr[nameLen] = '\0';
+        }
+
+        /* Get header of PEM - encryption header. */
+        if (ret == WOLFSSL_SUCCESS) {
+            headerLen = 0;
+            while ((pemLen = wolfSSL_BIO_gets(bio, pem, sizeof(pem) - 1)) > 0) {
+                while (pemLen > 0 && (pem[pemLen - 1] == '\r' ||
+                                                     pem[pemLen - 1] == '\n')) {
+                    pemLen--;
+                }
+                pem[pemLen++] = '\n';
+                pem[pemLen] = '\0';
+
+                /* Header separator is a blank line. */
+                if (pem[0] == '\n') {
+                    headerFound = 1;
+            break;
+        }
+
+                /* Didn't find a blank line - no header. */
+                if (XSTRNCMP(pem, PEM_END, PEM_END_SZ) == 0) {
+                    der = (unsigned char*)headerStr;
+                    derLen = headerLen;
+                    /* Empty header - empty string. */
+                    headerStr = (char*)XMALLOC(1, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+                    if (headerStr == NULL)
+                        ret = WOLFSSL_FAILURE;
+                    else
+                        headerStr[0] = '\0';
+                    break;
+}
+
+                p = (char*)XREALLOC(headerStr, headerLen + pemLen + 1, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+                if (p == NULL) {
+                    ret = WOLFSSL_FAILURE;
+                    break;
+                }
+
+                headerStr = p;
+                XMEMCPY(headerStr + headerLen, pem, pemLen + 1);
+                headerLen += pemLen;
+            }
+            if (pemLen <= 0)
+                ret = WOLFSSL_FAILURE;
+    }
+
+        /* Get body of PEM - if there was a header */
+        if (ret == WOLFSSL_SUCCESS && headerFound) {
+            derLen = 0;
+            while ((pemLen = wolfSSL_BIO_gets(bio, pem, sizeof(pem) - 1)) > 0) {
+                while (pemLen > 0 && (pem[pemLen - 1] == '\r' ||
+                                                     pem[pemLen - 1] == '\n')) {
+                    pemLen--;
+}
+                pem[pemLen++] = '\n';
+                pem[pemLen] = '\0';
+
+                if (XSTRNCMP(pem, PEM_END, PEM_END_SZ) == 0)
+                    break;
+
+                p = (char*)XREALLOC(der, derLen + pemLen + 1, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+                if (p == NULL) {
+                    ret = WOLFSSL_FAILURE;
+                    break;
+    }
+
+                der = (unsigned char*)p;
+                XMEMCPY(der + derLen, pem, pemLen + 1);
+                derLen += pemLen;
+    }
+            if (pemLen <= 0)
+                ret = WOLFSSL_FAILURE;
+}
+
+        /* Check trailer. */
+        if (ret == WOLFSSL_SUCCESS) {
+            if (XSTRNCMP(pem + PEM_END_SZ, nameStr, nameLen) != 0)
+                ret = WOLFSSL_FAILURE;
+        }
+        if (ret == WOLFSSL_SUCCESS) {
+            if (XSTRNCMP(pem + PEM_END_SZ + nameLen, PEM_HDR_FIN_EOL,
+                                                     PEM_HDR_FIN_EOL_SZ) != 0) {
+                ret = WOLFSSL_FAILURE;
+    }
+    }
+
+        /* Base64 decode body. */
+        if (ret == WOLFSSL_SUCCESS) {
+            if (Base64_Decode(der, derLen, der, &derLen) != 0)
+                ret = WOLFSSL_FAILURE;
+    }
+
+        if (ret == WOLFSSL_SUCCESS) {
+            *name = nameStr;
+            *header = headerStr;
+            *data = der;
+            *len = derLen;
+            nameStr = NULL;
+            headerStr = NULL;
+            der = NULL;
+}
+
+        if (nameStr != NULL)
+            XFREE(nameStr, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (headerStr != NULL)
+            XFREE(headerStr, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (der != NULL)
+            XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+        return ret;
+    }
+
+    int wolfSSL_PEM_write_bio(WOLFSSL_BIO* bio, const char *name,
+                              const char *header, const unsigned char *data,
+                              long len)
+    {
+        int err = 0;
+        int outSz = 0;
+        int nameLen;
+        int headerLen;
+        byte* pem = NULL;
+        word32 pemLen;
+        word32 derLen = (word32)len;
+
+        if (bio == NULL || name == NULL || header == NULL || data == NULL)
+            return 0;
+
+        nameLen = (int)XSTRLEN(name);
+        headerLen = (int)XSTRLEN(header);
+
+        pemLen = (derLen + 2) / 3 * 4;
+        pemLen += (pemLen + 63) / 64;
+
+        pem = (byte*)XMALLOC(pemLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        err = pem == NULL;
+        if (!err)
+            err = Base64_Encode(data, derLen, pem, &pemLen) != 0;
+
+        if (!err) {
+            err = wolfSSL_BIO_write(bio, PEM_BEGIN, PEM_BEGIN_SZ) !=
+                                                              (int)PEM_BEGIN_SZ;
+        }
+        if (!err)
+            err = wolfSSL_BIO_write(bio, name, nameLen) != nameLen;
+        if (!err) {
+            err = wolfSSL_BIO_write(bio, PEM_HDR_FIN_EOL, PEM_HDR_FIN_EOL_SZ) !=
+                                                        (int)PEM_HDR_FIN_EOL_SZ;
+        }
+        if (!err && headerLen > 0) {
+            err = wolfSSL_BIO_write(bio, header, headerLen) != headerLen;
+            /* Blank line after a header and before body. */
+            if (!err)
+                err = wolfSSL_BIO_write(bio, "\n", 1) != 1;
+            headerLen++;
+        }
+        if (!err)
+            err = wolfSSL_BIO_write(bio, pem, pemLen) != (int)pemLen;
+        if (!err)
+            err = wolfSSL_BIO_write(bio, PEM_END, PEM_END_SZ) !=
+                                                                (int)PEM_END_SZ;
+        if (!err)
+            err = wolfSSL_BIO_write(bio, name, nameLen) != nameLen;
+        if (!err) {
+            err = wolfSSL_BIO_write(bio, PEM_HDR_FIN_EOL, PEM_HDR_FIN_EOL_SZ) !=
+                                                        (int)PEM_HDR_FIN_EOL_SZ;
+        }
+
+        if (!err) {
+            outSz = PEM_BEGIN_SZ + nameLen + PEM_HDR_FIN_EOL_SZ + headerLen +
+                             pemLen + PEM_END_SZ + nameLen + PEM_HDR_FIN_EOL_SZ;
+    }
+
+        if (pem != NULL)
+            XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+        return outSz;
+}
+
+#if !defined(NO_FILESYSTEM)
+    int wolfSSL_PEM_read(XFILE fp, char **name, char **header,
+                         unsigned char **data, long *len)
+{
+        int ret;
+        WOLFSSL_BIO* bio;
+
+        if (name == NULL || header == NULL || data == NULL || len == NULL)
+        return WOLFSSL_FAILURE;
+
+        bio = wolfSSL_BIO_new(wolfSSL_BIO_s_file());
+        if (bio == NULL)
+            return 0;
+
+        if (wolfSSL_BIO_set_fp(bio, fp, BIO_NOCLOSE) != WOLFSSL_SUCCESS) {
+            wolfSSL_BIO_free(bio);
+            bio = NULL;
+    }
+
+        ret = wolfSSL_PEM_read_bio(bio, name, header, data, len);
+
+        if (bio != NULL)
+            wolfSSL_BIO_free(bio);
+
+        return ret;
+}
+
+    int wolfSSL_PEM_write(XFILE fp, const char *name, const char *header,
+                          const unsigned char *data, long len)
+{
+        int ret;
+        WOLFSSL_BIO* bio;
+
+        if (name == NULL || header == NULL || data == NULL)
+            return 0;
+
+        bio = wolfSSL_BIO_new(wolfSSL_BIO_s_file());
+        if (bio == NULL)
+            return 0;
+
+        if (wolfSSL_BIO_set_fp(bio, fp, BIO_NOCLOSE) != WOLFSSL_SUCCESS) {
+            wolfSSL_BIO_free(bio);
+            bio = NULL;
+    }
+
+        ret = wolfSSL_PEM_write_bio(bio, name, header, data, len);
+
+        if (bio != NULL)
+            wolfSSL_BIO_free(bio);
+
+        return ret;
+}
+#endif
+
+    int wolfSSL_PEM_get_EVP_CIPHER_INFO(char* header, EncryptedInfo* cipher)
+{
+        if (header == NULL || cipher == NULL)
+            return WOLFSSL_FAILURE;
+
+        XMEMSET(cipher, 0, sizeof(*cipher));
+
+        if (wc_EncryptedInfoParse(cipher, &header, XSTRLEN(header)) != 0)
+        return WOLFSSL_FAILURE;
+
+        return WOLFSSL_SUCCESS;
+    }
+
+    int wolfSSL_PEM_do_header(EncryptedInfo* cipher, unsigned char* data,
+                              long* len, pem_password_cb* callback, void* ctx)
+    {
+        int ret = WOLFSSL_SUCCESS;
+        char password[NAME_SZ];
+        int passwordSz;
+
+        if (cipher == NULL || data == NULL || len == NULL || callback == NULL)
+            return WOLFSSL_FAILURE;
+
+        passwordSz = callback(password, sizeof(password), PEM_PASS_READ, ctx);
+        if (passwordSz < 0)
+            ret = WOLFSSL_FAILURE;
+
+        if (ret == WOLFSSL_SUCCESS) {
+            if (wc_BufferKeyDecrypt(cipher, data, (word32)*len, (byte*)password,
+                                                     passwordSz, WC_MD5) != 0) {
+                ret = WOLFSSL_FAILURE;
+        }
+    }
+
+        if (passwordSz > 0)
+            XMEMSET(password, 0, passwordSz);
+
+        return ret;
+}
 
     /*
@@ -23454,5 +30409,5 @@
      * u  : password
      * _AUX is for working with a trusted X509 certificate
-     */
+ */
     WOLFSSL_X509 *wolfSSL_PEM_read_bio_X509_AUX(WOLFSSL_BIO *bp,
                                WOLFSSL_X509 **x, pem_password_cb *cb, void *u) {
@@ -23466,28 +30421,969 @@
         return wolfSSL_PEM_read_bio_X509(bp, x, cb, u);
     }
+
+    void wolfSSL_X509_NAME_ENTRY_free(WOLFSSL_X509_NAME_ENTRY* ne)
+    {
+        if (ne != NULL) {
+            if (ne->value != NULL && ne->value != &(ne->data)) {
+                wolfSSL_ASN1_STRING_free(ne->value);
+            }
+            XFREE(ne, NULL, DYNAMIC_TYPE_NAME_ENTRY);
+        }
+    }
+
+
+    WOLFSSL_X509_NAME_ENTRY* wolfSSL_X509_NAME_ENTRY_new(void)
+    {
+        WOLFSSL_X509_NAME_ENTRY* ne = NULL;
+
+        ne = (WOLFSSL_X509_NAME_ENTRY*)XMALLOC(sizeof(WOLFSSL_X509_NAME_ENTRY),
+                NULL, DYNAMIC_TYPE_NAME_ENTRY);
+        if (ne != NULL) {
+            XMEMSET(ne, 0, sizeof(WOLFSSL_X509_NAME_ENTRY));
+            ne->value = &(ne->data);
+    }
+
+        return ne;
+    }
+
+
+    WOLFSSL_X509_NAME_ENTRY* wolfSSL_X509_NAME_ENTRY_create_by_NID(
+            WOLFSSL_X509_NAME_ENTRY** out, int nid, int type,
+            unsigned char* data, int dataSz)
+    {
+        WOLFSSL_X509_NAME_ENTRY* ne = NULL;
+
+        WOLFSSL_ENTER("wolfSSL_X509_NAME_ENTRY_create_by_NID()");
+
+        ne = wolfSSL_X509_NAME_ENTRY_new();
+        if (ne == NULL) {
+            return NULL;
+    }
+
+        ne->nid = nid;
+        ne->value = wolfSSL_ASN1_STRING_type_new(type);
+        wolfSSL_ASN1_STRING_set(ne->value, (const void*)data, dataSz);
+        ne->set = 1;
+
+        if (out != NULL) {
+            *out = ne;
+        }
+
+        return ne;
+}
+
+    static int RebuildFullNameAdd(DecodedName* dName, char* data)
+{
+        int totalLen = 0;
+        int i;
+        char* fullName;
+        int idx;
+
+        if (dName->cnLen != 0)
+            totalLen += dName->cnLen + 4;
+        if (dName->snLen != 0)
+            totalLen += dName->snLen + 4;
+        if (dName->cLen != 0)
+            totalLen += dName->cLen + 3;
+        if (dName->lLen != 0)
+            totalLen += dName->lLen + 3;
+        if (dName->stLen != 0)
+            totalLen += dName->stLen + 4;
+        if (dName->oLen != 0)
+            totalLen += dName->oLen + 3;
+        if (dName->ouLen != 0)
+            totalLen += dName->ouLen + 4;
+        if (dName->emailLen != 0)
+            totalLen += dName->emailLen + 14;
+        if (dName->uidLen != 0)
+            totalLen += dName->uidLen + 5;
+        if (dName->serialLen != 0)
+            totalLen += dName->serialLen + 14;
+        if (dName->dcNum != 0) {
+            for (i = 0; i < dName->dcNum; i++)
+                totalLen += dName->dcLen[i] + 4;
+        }
+
+        fullName = (char*)XMALLOC(totalLen + 1, NULL, DYNAMIC_TYPE_X509);
+        if (fullName == NULL)
+            return MEMORY_E;
+
+        idx = 0;
+        dName->entryCount = 0;
+        if (dName->cnLen != 0) {
+            dName->entryCount++;
+            XMEMCPY(fullName + idx, WOLFSSL_COMMON_NAME, 4);
+            idx += 4;
+            if (dName->cnIdx == -1)
+                XMEMCPY(fullName + idx, data, dName->cnLen);
+            else {
+                XMEMCPY(fullName + idx, dName->fullName + dName->cnIdx,
+                                                                  dName->cnLen);
+            }
+            dName->cnIdx = idx;
+            idx += dName->cnLen;
+        }
+        if (dName->snLen != 0) {
+            dName->entryCount++;
+            XMEMCPY(fullName + idx, WOLFSSL_SUR_NAME, 4);
+            idx += 4;
+            if (dName->snIdx == -1)
+                XMEMCPY(fullName + idx, data, dName->snLen);
+            else {
+                XMEMCPY(fullName + idx, dName->fullName + dName->snIdx,
+                                                                  dName->snLen);
+            }
+            dName->snIdx = idx;
+            idx += dName->snLen;
+        }
+        if (dName->cLen != 0) {
+            dName->entryCount++;
+            XMEMCPY(fullName + idx, WOLFSSL_COUNTRY_NAME, 3);
+            idx += 3;
+            if (dName->cIdx == -1)
+                XMEMCPY(fullName + idx, data, dName->cLen);
+            else {
+                XMEMCPY(fullName + idx, dName->fullName + dName->cIdx,
+                                                                   dName->cLen);
+            }
+            dName->cIdx = idx;
+            idx += dName->cLen;
+        }
+        if (dName->lLen != 0) {
+            dName->entryCount++;
+            XMEMCPY(fullName + idx, WOLFSSL_LOCALITY_NAME, 3);
+            idx += 3;
+            if (dName->lIdx == -1)
+                XMEMCPY(fullName + idx, data, dName->lLen);
+            else {
+                XMEMCPY(fullName + idx, dName->fullName + dName->lIdx,
+                                                                   dName->lLen);
+            }
+            dName->lIdx = idx;
+            idx += dName->lLen;
+        }
+        if (dName->stLen != 0) {
+            dName->entryCount++;
+            XMEMCPY(fullName + idx, WOLFSSL_STATE_NAME, 4);
+            idx += 4;
+            if (dName->stIdx == -1)
+                XMEMCPY(fullName + idx, data, dName->stLen);
+            else {
+                XMEMCPY(fullName + idx, dName->fullName + dName->stIdx,
+                                                                  dName->stLen);
+            }
+            dName->stIdx = idx;
+            idx += dName->stLen;
+        }
+        if (dName->oLen != 0) {
+            dName->entryCount++;
+            XMEMCPY(fullName + idx, WOLFSSL_ORG_NAME, 3);
+            idx += 3;
+            if (dName->oIdx == -1)
+                XMEMCPY(fullName + idx, data, dName->oLen);
+            else {
+                XMEMCPY(fullName + idx, dName->fullName + dName->oIdx,
+                                                                   dName->oLen);
+            }
+            dName->oIdx = idx;
+            idx += dName->oLen;
+        }
+        if (dName->ouLen != 0) {
+            dName->entryCount++;
+            XMEMCPY(fullName + idx, WOLFSSL_ORGUNIT_NAME, 4);
+            idx += 4;
+            if (dName->ouIdx == -1)
+                XMEMCPY(fullName + idx, data, dName->ouLen);
+            else {
+                XMEMCPY(fullName + idx, dName->fullName + dName->ouIdx,
+                                                                  dName->ouLen);
+            }
+            dName->ouIdx = idx;
+            idx += dName->ouLen;
+        }
+        if (dName->emailLen != 0) {
+            dName->entryCount++;
+            XMEMCPY(fullName + idx, "/emailAddress=", 14);
+            idx += 14;
+            if (dName->emailIdx == -1)
+                XMEMCPY(fullName + idx, data, dName->emailLen);
+            else {
+                XMEMCPY(fullName + idx, dName->fullName + dName->emailIdx,
+                                                               dName->emailLen);
+            }
+            dName->emailIdx = idx;
+            idx += dName->emailLen;
+        }
+        if (dName->dcNum != 0) {
+            for (i = 0; i < dName->dcNum; i++) {
+                dName->entryCount++;
+                XMEMCPY(fullName + idx, WOLFSSL_DOMAIN_COMPONENT, 4);
+                idx += 4;
+                XMEMCPY(fullName + idx, dName->fullName + dName->dcIdx[i],
+                                                               dName->dcLen[i]);
+                dName->dcIdx[i] = idx;
+                idx += dName->dcLen[i];
+            }
+        }
+        if (dName->uidLen != 0) {
+            dName->entryCount++;
+            XMEMCPY(fullName + idx, "/UID=", 5);
+            idx += 5;
+            if (dName->uidIdx == -1)
+                XMEMCPY(fullName + idx, data, dName->uidLen);
+            else {
+                XMEMCPY(fullName + idx, dName->fullName + dName->uidIdx,
+                                                                 dName->uidLen);
+            }
+            dName->uidIdx = idx;
+            idx += dName->uidLen;
+        }
+        if (dName->serialLen != 0) {
+            dName->entryCount++;
+            XMEMCPY(fullName + idx, WOLFSSL_SERIAL_NUMBER, 14);
+            idx += 14;
+            if (dName->serialIdx == -1)
+                XMEMCPY(fullName + idx, data, dName->serialLen);
+            else {
+                XMEMCPY(fullName + idx, dName->fullName + dName->serialIdx,
+                                                              dName->serialLen);
+            }
+            dName->serialIdx = idx;
+            idx += dName->serialLen;
+    }
+
+        if (dName->fullName != NULL)
+            XFREE(dName->fullName, NULL, DYNAMIC_TYPE_X509);
+        dName->fullName = fullName;
+        dName->fullNameLen = idx;
+
+        return 0;
+}
+
+    /* Copies entry into name. With it being copied freeing entry becomes the
+     * callers responsibility.
+     * returns 1 for success and 0 for error */
+    int wolfSSL_X509_NAME_add_entry(WOLFSSL_X509_NAME* name,
+            WOLFSSL_X509_NAME_ENTRY* entry, int idx, int set)
+{
+        int i;
+        int fullName = 1;
+
+        WOLFSSL_ENTER("wolfSSL_X509_NAME_add_entry()");
+
+        switch (entry->nid) {
+            case ASN_COMMON_NAME:
+                name->fullName.cnIdx = -1;
+                name->fullName.cnLen = entry->value->length;
+                name->fullName.cnNid = entry->nid;
+                break;
+            case ASN_SUR_NAME:
+                name->fullName.snIdx = -1;
+                name->fullName.snLen = entry->value->length;
+                name->fullName.snNid = entry->nid;
+                break;
+            case ASN_SERIAL_NUMBER:
+                name->fullName.serialIdx = -1;
+                name->fullName.serialLen = entry->value->length;
+                name->fullName.serialNid = entry->nid;
+                break;
+            case ASN_COUNTRY_NAME:
+                name->fullName.cIdx = -1;
+                name->fullName.cLen = entry->value->length;
+                name->fullName.cNid = entry->nid;
+                break;
+            case ASN_LOCALITY_NAME:
+                name->fullName.lIdx = -1;
+                name->fullName.lLen = entry->value->length;
+                name->fullName.lNid = entry->nid;
+                break;
+            case ASN_STATE_NAME:
+                name->fullName.stIdx = -1;
+                name->fullName.stLen = entry->value->length;
+                name->fullName.stNid = entry->nid;
+                break;
+            case ASN_ORG_NAME:
+                name->fullName.oIdx = -1;
+                name->fullName.oLen = entry->value->length;
+                name->fullName.oNid = entry->nid;
+                break;
+            case ASN_ORGUNIT_NAME:
+                name->fullName.ouIdx = -1;
+                name->fullName.ouLen = entry->value->length;
+                name->fullName.ouNid = entry->nid;
+                break;
+            case NID_emailAddress:
+                name->fullName.emailIdx = -1;
+                name->fullName.emailLen = entry->value->length;
+                name->fullName.emailNid = entry->nid;
+                break;
+            case ASN_USER_ID:
+                name->fullName.uidIdx = -1;
+                name->fullName.uidLen = entry->value->length;
+                name->fullName.uidNid = entry->nid;
+                break;
+            case ASN_DOMAIN_COMPONENT:
+                name->fullName.dcIdx[0] = -1;
+                name->fullName.dcLen[0] = entry->value->length;
+                break;
+            default:
+                fullName = 0;
+                break;
+        }
+
+        if (fullName) {
+            if (RebuildFullNameAdd(&name->fullName, entry->value->data) != 0)
+                return WOLFSSL_FAILURE;
+}
+        else {
+            for (i = 0; i < MAX_NAME_ENTRIES; i++) {
+                if (name->extra[i].set != 1) { /* not set so overwrited */
+                    WOLFSSL_X509_NAME_ENTRY* current = &(name->extra[i]);
+                    WOLFSSL_ASN1_STRING*     str;
+
+                    WOLFSSL_MSG("Found place for name entry");
+
+                    XMEMCPY(current, entry, sizeof(WOLFSSL_X509_NAME_ENTRY));
+                    str = entry->value;
+                    XMEMCPY(&(current->data), str, sizeof(WOLFSSL_ASN1_STRING));
+                    current->value = &(current->data);
+                    current->data.data = (char*)XMALLOC(str->length,
+                           name->x509->heap, DYNAMIC_TYPE_OPENSSL);
+
+                    if (current->data.data == NULL) {
+                        return SSL_FAILURE;
+    }
+                    XMEMCPY(current->data.data, str->data, str->length);
+
+                    /* make sure is null terminated */
+                    current->data.data[str->length - 1] = '\0';
+
+                    current->set = 1; /* make sure now listed as set */
+                    break;
+        }
+    }
+
+            if (i == MAX_NAME_ENTRIES) {
+                WOLFSSL_MSG("No spot found for name entry");
+                return SSL_FAILURE;
+            }
+    }
+
+        (void)idx;
+        (void)set;
+        return SSL_SUCCESS;
+}
+
+    typedef struct WOLFSSL_ObjectInfo {
+        int nid;
+        int id;
+        word32 type;
+        const char* sName;
+    } WOLFSSL_ObjectInfo;
+
+    static WOLFSSL_ObjectInfo wolfssl_object_info[] = {
+        /* oidHashType */
+    #ifdef WOLFSSL_MD2
+        { NID_md2, MD2h, oidHashType, "md2" },
+    #endif
+    #ifdef WOLFSSL_MD5
+        { NID_md5, MD5h, oidHashType, "md5" },
+    #endif
+    #ifndef NO_SHA
+        { NID_sha1, SHAh, oidHashType, "sha" },
+    #endif
+    #ifdef WOLFSSL_SHA224
+        { NID_sha224, SHA224h, oidHashType, "sha224" },
+    #endif
+    #ifndef NO_SHA256
+        { NID_sha256, SHA256h, oidHashType, "sha256" },
+    #endif
+    #ifdef WOLFSSL_SHA384
+        { NID_sha384, SHA384h, oidHashType, "sha384" },
+    #endif
+    #ifdef WOLFSSL_SHA512
+        { NID_sha512, SHA512h, oidHashType, "sha512" },
+    #endif
+
+        /* oidSigType */
+    #ifndef NO_DSA
+        #ifndef NO_SHA
+        { CTC_SHAwDSA, CTC_SHAwDSA, oidSigType, "shaWithDSA" },
+        #endif
+    #endif /* NO_DSA */
+    #ifndef NO_RSA
+        #ifdef WOLFSSL_MD2
+        { CTC_MD2wRSA, CTC_MD2wRSA, oidSigType, "md2WithRSA" },
+        #endif
+        #ifndef NO_MD5
+        { CTC_MD5wRSA, CTC_MD5wRSA, oidSigType, "md5WithRSA" },
+        #endif
+        #ifndef NO_SHA
+        { CTC_SHAwRSA, CTC_SHAwRSA, oidSigType, "shaWithRSA" },
+        #endif
+        #ifdef WOLFSSL_SHA224
+        { CTC_SHA224wRSA, CTC_SHA224wRSA, oidSigType, "sha224WithRSA" },
+        #endif
+        #ifndef NO_SHA256
+        { CTC_SHA256wRSA, CTC_SHA256wRSA, oidSigType, "sha256WithRSA" },
+        #endif
+        #ifdef WOLFSSL_SHA384
+        { CTC_SHA384wRSA, CTC_SHA384wRSA, oidSigType, "sha384WithRSA" },
+        #endif
+        #ifdef WOLFSSL_SHA512
+        { CTC_SHA512wRSA, CTC_SHA512wRSA, oidSigType, "sha512WithRSA" },
+        #endif
+    #endif /* NO_RSA */
+    #ifdef HAVE_ECC
+        #ifndef NO_SHA
+        { CTC_SHAwECDSA, CTC_SHAwECDSA, oidSigType, "shaWithECDSA" },
+        #endif
+        #ifdef WOLFSSL_SHA224
+        { CTC_SHA224wECDSA, CTC_SHA224wECDSA, oidSigType, "sha224WithECDSA" },
+        #endif
+        #ifndef NO_SHA256
+        { CTC_SHA256wECDSA, CTC_SHA256wECDSA, oidSigType, "sha256WithECDSA" },
+        #endif
+        #ifdef WOLFSSL_SHA384
+        { CTC_SHA384wECDSA, CTC_SHA384wECDSA, oidSigType, "sha384WithECDSA" },
+        #endif
+        #ifdef WOLFSSL_SHA512
+        { CTC_SHA512wECDSA, CTC_SHA512wECDSA, oidSigType, "sha512WithECDSA" },
+        #endif
+    #endif /* HAVE_ECC */
+
+        /* oidKeyType */
+    #ifndef NO_DSA
+        { DSAk, DSAk, oidKeyType, "DSA key" },
+    #endif /* NO_DSA */
+    #ifndef NO_RSA
+        { RSAk, RSAk, oidKeyType, "RSA key" },
+    #endif /* NO_RSA */
+    #ifdef HAVE_NTRU
+        { NTRUk, NTRUk, oidKeyType, "NTRU key" },
+    #endif /* HAVE_NTRU */
+    #ifdef HAVE_ECC
+        { ECDSAk, ECDSAk, oidKeyType, "ECDSA key" },
+    #endif /* HAVE_ECC */
+
+        /* oidBlkType */
+    #ifdef WOLFSSL_AES_128
+        { AES128CBCb, AES128CBCb, oidBlkType, "AES-128-CBC" },
+    #endif
+    #ifdef WOLFSSL_AES_192
+        { AES192CBCb, AES192CBCb, oidBlkType, "AES-192-CBC" },
+    #endif
+    #ifdef WOLFSSL_AES_256
+        { AES256CBCb, AES256CBCb, oidBlkType, "AES-256-CBC" },
+    #endif
+    #ifndef NO_DES3
+        { NID_des, DESb, oidBlkType, "DES-CBC" },
+        { NID_des3, DES3b, oidBlkType, "DES3-CBC" },
+    #endif /* !NO_DES3 */
+
+        /* oidOcspType */
+    #ifdef HAVE_OCSP
+        { NID_id_pkix_OCSP_basic, OCSP_BASIC_OID, oidOcspType, "OCSP_basic" },
+        { OCSP_NONCE_OID, OCSP_NONCE_OID, oidOcspType, "OCSP_nonce" },
+    #endif /* HAVE_OCSP */
+
+    #ifndef NO_CERT
+        /* oidCertExtType */
+        { BASIC_CA_OID, BASIC_CA_OID, oidCertExtType, "X509 basic ca" },
+        { ALT_NAMES_OID, ALT_NAMES_OID, oidCertExtType, "X509 alt names" },
+        { CRL_DIST_OID, CRL_DIST_OID, oidCertExtType, "X509 crl" },
+        { AUTH_INFO_OID, AUTH_INFO_OID, oidCertExtType, "X509 auth info" },
+        { AUTH_KEY_OID, AUTH_KEY_OID, oidCertExtType, "X509 auth key" },
+        { SUBJ_KEY_OID, SUBJ_KEY_OID, oidCertExtType, "X509 subject key" },
+        { KEY_USAGE_OID, KEY_USAGE_OID, oidCertExtType, "X509 key usage" },
+        { INHIBIT_ANY_OID, INHIBIT_ANY_OID, oidCertExtType,
+                                                           "X509 inhibit any" },
+        { NID_ext_key_usage, KEY_USAGE_OID, oidCertExtType,
+                                                         "X509 ext key usage" },
+        { NID_name_constraints, NAME_CONS_OID, oidCertExtType,
+                                                      "X509 name constraints" },
+        { NID_certificate_policies, CERT_POLICY_OID, oidCertExtType,
+                                                  "X509 certificate policies" },
+
+        /* oidCertAuthInfoType */
+        { AIA_OCSP_OID, AIA_OCSP_OID, oidCertAuthInfoType, "Cert Auth OCSP" },
+        { AIA_CA_ISSUER_OID, AIA_CA_ISSUER_OID, oidCertAuthInfoType,
+                                                        "Cert Auth CA Issuer" },
+
+        /* oidCertPolicyType */
+        { NID_any_policy, CP_ANY_OID, oidCertPolicyType, "Cert any policy" },
+
+        /* oidCertAltNameType */
+        { NID_hw_name_oid, HW_NAME_OID, oidCertAltNameType, "Hardware name" },
+
+        /* oidCertKeyUseType */
+        { NID_anyExtendedKeyUsage, EKU_ANY_OID, oidCertKeyUseType,
+                                                      "Cert any extended key" },
+        { EKU_SERVER_AUTH_OID, EKU_SERVER_AUTH_OID, oidCertKeyUseType,
+                                                       "Cert server auth key" },
+        { EKU_CLIENT_AUTH_OID, EKU_CLIENT_AUTH_OID, oidCertKeyUseType,
+                                                       "Cert client auth key" },
+        { EKU_OCSP_SIGN_OID, EKU_OCSP_SIGN_OID, oidCertKeyUseType,
+                                                         "Cert OCSP sign key" },
+
+        /* oidCertNameType */
+        { NID_commonName, NID_commonName, oidCertNameType, "commonName" },
+        { NID_surname, NID_surname, oidCertNameType, "surname" },
+        { NID_serialNumber, NID_serialNumber, oidCertNameType, "serialNumber" },
+        { NID_countryName, NID_countryName, oidCertNameType, "countryName" },
+        { NID_localityName, NID_localityName, oidCertNameType, "localityName" },
+        { NID_stateOrProvinceName, NID_stateOrProvinceName, oidCertNameType,
+                                                        "stateOrProvinceName" },
+        { NID_organizationName, NID_organizationName, oidCertNameType,
+                                                           "organizationName" },
+        { NID_organizationalUnitName, NID_organizationalUnitName,
+                                    oidCertNameType, "organizationalUnitName" },
+        { NID_emailAddress, NID_emailAddress, oidCertNameType, "emailAddress" },
+    #endif
+
+    #ifndef NO_PWDBASED
+        /* oidKdfType */
+        { PBKDF2_OID, PBKDF2_OID, oidKdfType, "PBKDFv2" },
+
+        /* oidPBEType */
+        { PBE_SHA1_RC4_128, PBE_SHA1_RC4_128, oidPBEType,
+                                                         "PBE shaWithRC4-128" },
+        { PBE_SHA1_DES, PBE_SHA1_DES, oidPBEType, "PBE shaWithDES" },
+        { PBE_SHA1_DES3, PBE_SHA1_DES3, oidPBEType, "PBE shaWithDES3" },
+    #endif
+
+        /* oidKeyWrapType */
+    #ifdef WOLFSSL_AES_128
+        { AES128_WRAP, AES128_WRAP, oidKeyWrapType, "AES-128 wrap" },
+    #endif
+    #ifdef WOLFSSL_AES_192
+        { AES192_WRAP, AES192_WRAP, oidKeyWrapType, "AES-192 wrap" },
+    #endif
+    #ifdef WOLFSSL_AES_256
+        { AES256_WRAP, AES256_WRAP, oidKeyWrapType, "AES-256 wrap" },
+    #endif
+
+    #ifndef NO_PKCS7
+        #ifndef NO_DH
+        /* oidCmsKeyAgreeType */
+            #ifndef NO_SHA
+        { dhSinglePass_stdDH_sha1kdf_scheme, dhSinglePass_stdDH_sha1kdf_scheme,
+                                             oidCmsKeyAgreeType, "DH-SHA kdf" },
+            #endif
+            #ifdef WOLFSSL_SHA224
+        { dhSinglePass_stdDH_sha224kdf_scheme,
+                        dhSinglePass_stdDH_sha224kdf_scheme, oidCmsKeyAgreeType,
+                                                              "DH-SHA224 kdf" },
+            #endif
+            #ifndef NO_SHA256
+        { dhSinglePass_stdDH_sha256kdf_scheme,
+                        dhSinglePass_stdDH_sha256kdf_scheme, oidCmsKeyAgreeType,
+                                                              "DH-SHA256 kdf" },
+            #endif
+            #ifdef WOLFSSL_SHA384
+        { dhSinglePass_stdDH_sha384kdf_scheme,
+                        dhSinglePass_stdDH_sha384kdf_scheme, oidCmsKeyAgreeType,
+                                                              "DH-SHA384 kdf" },
+            #endif
+            #ifdef WOLFSSL_SHA512
+        { dhSinglePass_stdDH_sha512kdf_scheme,
+                        dhSinglePass_stdDH_sha512kdf_scheme, oidCmsKeyAgreeType,
+                                                              "DH-SHA512 kdf" },
+            #endif
+        #endif
+    #endif
+    };
+
+    #define WOLFSSL_OBJECT_INFO_SZ \
+                    (sizeof(wolfssl_object_info) / sizeof(*wolfssl_object_info))
+
+    int wolfSSL_X509_NAME_add_entry_by_txt(WOLFSSL_X509_NAME *name,
+                                           const char *field, int type,
+                                           const unsigned char *bytes, int len,
+                                           int loc, int set)
+{
+        int ret;
+        int i;
+        WOLFSSL_X509_NAME_ENTRY* entry;
+        size_t fieldSz;
+
+        (void)type;
+
+        if (name == NULL || field == NULL)
+            return WOLFSSL_FAILURE;
+
+        fieldSz = XSTRLEN(field);
+        for (i = 0; i < (int)WOLFSSL_OBJECT_INFO_SZ; i++) {
+            if (XSTRNCMP(field, wolfssl_object_info[i].sName, fieldSz) == 0)
+                break;
+    }
+
+        if (i == WOLFSSL_OBJECT_INFO_SZ)
+            return WOLFSSL_FAILURE;
+
+        entry = wolfSSL_X509_NAME_ENTRY_create_by_NID(NULL,
+                  wolfssl_object_info[i].nid, type, (unsigned char*)bytes, len);
+        if (entry == NULL)
+            return WOLFSSL_FAILURE;
+
+        ret = wolfSSL_X509_NAME_add_entry(name, entry, loc, set);
+        wolfSSL_X509_NAME_ENTRY_free(entry);
+        return ret;
+}
     #endif /* ifndef NO_CERTS */
 
-    #ifndef NO_CERTS
-    void wolfSSL_X509_NAME_free(WOLFSSL_X509_NAME *name){
-        FreeX509Name(name, NULL);
-        WOLFSSL_ENTER("wolfSSL_X509_NAME_free");
-    }
-    #endif /* NO_CERTS */
-
-#if defined(HAVE_LIGHTY)  || defined(WOLFSSL_MYSQL_COMPATIBLE) || \
-    defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \
-    defined(HAVE_POCO_LIB) || defined (WOLFSSL_HAPROXY)
-
-    unsigned char *wolfSSL_SHA1(const unsigned char *d, size_t n, unsigned char *md)
+
+    /* NID variables are dependent on compatibility header files currently
+     *
+     * returns a pointer to a new WOLFSSL_ASN1_OBJECT struct on success and NULL
+     *         on fail
+     */
+
+    WOLFSSL_ASN1_OBJECT* wolfSSL_OBJ_nid2obj(int id)
     {
-        (void) *d; (void) n; (void) *md;
+        return wolfSSL_OBJ_nid2obj_ex(id, NULL);
+    }
+
+
+    WOLFSSL_LOCAL WOLFSSL_ASN1_OBJECT* wolfSSL_OBJ_nid2obj_ex(int id,
+                                                WOLFSSL_ASN1_OBJECT* arg_obj)
+    {
+        word32 oidSz = 0;
+        const byte* oid;
+        word32 type = 0;
+        WOLFSSL_ASN1_OBJECT* obj = arg_obj;
+        byte objBuf[MAX_OID_SZ + MAX_LENGTH_SZ + 1]; /* +1 for object tag */
+        word32 objSz = 0;
+        const char* sName = NULL;
+        int i;
+
+        WOLFSSL_ENTER("wolfSSL_OBJ_nid2obj()");
+
+        for (i = 0; i < (int)WOLFSSL_OBJECT_INFO_SZ; i++) {
+            if (wolfssl_object_info[i].nid == id) {
+                id = wolfssl_object_info[i].id;
+                sName = wolfssl_object_info[i].sName;
+                type = wolfssl_object_info[i].type;
+                break;
+            }
+        }
+        if (i == (int)WOLFSSL_OBJECT_INFO_SZ) {
+            WOLFSSL_MSG("NID not in table");
+            return NULL;
+        }
+
+    #ifdef HAVE_ECC
+         if (type == 0 && wc_ecc_get_oid(id, &oid, &oidSz) > 0) {
+             type = oidCurveType;
+    }
+    #endif /* HAVE_ECC */
+
+        if (sName != NULL) {
+            if (XSTRLEN(sName) > WOLFSSL_MAX_SNAME - 1) {
+                WOLFSSL_MSG("Attempted short name is too large");
+        return NULL;
+    }
+    }
+
+        oid = OidFromId(id, type, &oidSz);
+
+        /* set object ID to buffer */
+        if (obj == NULL){
+            obj = wolfSSL_ASN1_OBJECT_new();
+            if (obj == NULL) {
+                WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct");
+                return NULL;
+                }
+            obj->dynamic |= WOLFSSL_ASN1_DYNAMIC;
+        } else {
+            obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC;
+                }
+        obj->type    = id;
+        obj->grp     = type;
+
+        obj->sName[0] = '\0';
+        if (sName != NULL) {
+            XMEMCPY(obj->sName, (char*)sName, XSTRLEN((char*)sName));
+        }
+
+        objBuf[0] = ASN_OBJECT_ID; objSz++;
+        objSz += SetLength(oidSz, objBuf + 1);
+        XMEMCPY(objBuf + objSz, oid, oidSz);
+        objSz     += oidSz;
+        obj->objSz = objSz;
+        if(((obj->dynamic & WOLFSSL_ASN1_DYNAMIC_DATA) != 0) ||
+          (((obj->dynamic & WOLFSSL_ASN1_DYNAMIC_DATA) == 0) &&
+                                                          (obj->obj == NULL))) {
+            obj->obj = (byte*)XREALLOC((byte*)obj->obj, obj->objSz, NULL,
+                                                             DYNAMIC_TYPE_ASN1);
+            if (obj->obj == NULL) {
+                wolfSSL_ASN1_OBJECT_free(obj);
+                return NULL;
+            }
+            obj->dynamic |= WOLFSSL_ASN1_DYNAMIC_DATA ;
+        } else {
+            obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA ;
+    }
+        XMEMCPY((byte*)obj->obj, objBuf, obj->objSz);
+
+        (void)type;
+
+        return obj;
+}
+
+
+    /* if no_name is one than use numerical form otherwise can be short name.
+     *
+     * returns the buffer size on success
+ */
+    int wolfSSL_OBJ_obj2txt(char *buf, int bufLen, WOLFSSL_ASN1_OBJECT *a, int no_name)
+{
+        int bufSz;
+
+        WOLFSSL_ENTER("wolfSSL_OBJ_obj2txt()");
+
+        if (buf == NULL || bufLen <= 1 || a == NULL) {
+            WOLFSSL_MSG("Bad input argument");
+            return WOLFSSL_FAILURE;
+    }
+
+        if (no_name == 1) {
+            int    length;
+            word32 idx = 0;
+
+            if (a->obj[idx++] != ASN_OBJECT_ID) {
+                WOLFSSL_MSG("Bad ASN1 Object");
+                return WOLFSSL_FAILURE;
+        }
+
+            if (GetLength((const byte*)a->obj, &idx, &length,
+                           a->objSz) < 0 || length < 0) {
+                return ASN_PARSE_E;
+    }
+
+            if (bufLen < MAX_OID_STRING_SZ) {
+                bufSz = bufLen - 1;
+    }
+            else {
+                bufSz = MAX_OID_STRING_SZ;
+            }
+
+            if ((bufSz = DecodePolicyOID(buf, (word32)bufSz, a->obj + idx,
+                        (word32)length)) <= 0) {
+                WOLFSSL_MSG("Error decoding OID");
+        return WOLFSSL_FAILURE;
+    }
+
+}
+        else { /* return short name */
+            if (XSTRLEN(a->sName) + 1 < (word32)bufLen - 1) {
+                bufSz = (int)XSTRLEN(a->sName);
+            }
+            else {
+                bufSz = bufLen - 1;
+            }
+            XMEMCPY(buf, a->sName, bufSz);
+        }
+
+        buf[bufSz] = '\0';
+        return bufSz;
+    }
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \
+    defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \
+    defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \
+    defined(WOLFSSL_HAPROXY)
+
+#ifndef NO_SHA
+    /* One shot SHA1 hash of message.
+     *
+     * d  message to hash
+     * n  size of d buffer
+     * md buffer to hold digest. Should be SHA_DIGEST_SIZE.
+     *
+     * Note: if md is null then a static buffer of SHA_DIGEST_SIZE is used.
+     *       When the static buffer is used this function is not thread safe.
+     *
+     * Returns a pointer to the message digest on success and NULL on failure.
+ */
+    unsigned char *wolfSSL_SHA1(const unsigned char *d, size_t n,
+            unsigned char *md)
+{
+        static byte dig[WC_SHA_DIGEST_SIZE];
+        wc_Sha sha;
+
         WOLFSSL_ENTER("wolfSSL_SHA1");
-        WOLFSSL_STUB("wolfssl_SHA1");
-
-        return NULL;
-    }
+
+        if (wc_InitSha_ex(&sha, NULL, 0) != 0) {
+            WOLFSSL_MSG("SHA1 Init failed");
+            return NULL;
+    }
+
+        if (wc_ShaUpdate(&sha, (const byte*)d, (word32)n) != 0) {
+            WOLFSSL_MSG("SHA1 Update failed");
+            return NULL;
+        }
+
+        if (wc_ShaFinal(&sha, dig) != 0) {
+            WOLFSSL_MSG("SHA1 Final failed");
+            return NULL;
+    }
+
+        wc_ShaFree(&sha);
+
+        if (md != NULL) {
+            XMEMCPY(md, dig, WC_SHA_DIGEST_SIZE);
+            return md;
+    }
+        else {
+            return (unsigned char*)dig;
+}
+    }
+#endif /* ! NO_SHA */
+
+#ifndef NO_SHA256
+    /* One shot SHA256 hash of message.
+     *
+     * d  message to hash
+     * n  size of d buffer
+     * md buffer to hold digest. Should be WC_SHA256_DIGEST_SIZE.
+     *
+     * Note: if md is null then a static buffer of WC_SHA256_DIGEST_SIZE is used.
+     *       When the static buffer is used this function is not thread safe.
+     *
+     * Returns a pointer to the message digest on success and NULL on failure.
+ */
+    unsigned char *wolfSSL_SHA256(const unsigned char *d, size_t n,
+            unsigned char *md)
+{
+        static byte dig[WC_SHA256_DIGEST_SIZE];
+        wc_Sha256 sha;
+
+        WOLFSSL_ENTER("wolfSSL_SHA256");
+
+        if (wc_InitSha256_ex(&sha, NULL, 0) != 0) {
+            WOLFSSL_MSG("SHA256 Init failed");
+            return NULL;
+}
+
+        if (wc_Sha256Update(&sha, (const byte*)d, (word32)n) != 0) {
+            WOLFSSL_MSG("SHA256 Update failed");
+            return NULL;
+        }
+
+        if (wc_Sha256Final(&sha, dig) != 0) {
+            WOLFSSL_MSG("SHA256 Final failed");
+            return NULL;
+        }
+
+        wc_Sha256Free(&sha);
+
+        if (md != NULL) {
+            XMEMCPY(md, dig, WC_SHA256_DIGEST_SIZE);
+            return md;
+}
+        else {
+            return (unsigned char*)dig;
+        }
+    }
+#endif /* ! NO_SHA256 */
+
+#ifdef WOLFSSL_SHA384
+     /* One shot SHA384 hash of message.
+      *
+      * d  message to hash
+      * n  size of d buffer
+      * md buffer to hold digest. Should be WC_SHA256_DIGEST_SIZE.
+      *
+      * Note: if md is null then a static buffer of WC_SHA256_DIGEST_SIZE is used.
+      *       When the static buffer is used this function is not thread safe.
+      *
+      * Returns a pointer to the message digest on success and NULL on failure.
+ */
+     unsigned char *wolfSSL_SHA384(const unsigned char *d, size_t n,
+             unsigned char *md)
+{
+         static byte dig[WC_SHA384_DIGEST_SIZE];
+         wc_Sha384 sha;
+
+         WOLFSSL_ENTER("wolfSSL_SHA384");
+
+         if (wc_InitSha384_ex(&sha, NULL, 0) != 0) {
+             WOLFSSL_MSG("SHA384 Init failed");
+             return NULL;
+    }
+
+         if (wc_Sha384Update(&sha, (const byte*)d, (word32)n) != 0) {
+             WOLFSSL_MSG("SHA384 Update failed");
+             return NULL;
+        }
+
+         if (wc_Sha384Final(&sha, dig) != 0) {
+             WOLFSSL_MSG("SHA384 Final failed");
+             return NULL;
+    }
+
+         wc_Sha384Free(&sha);
+
+         if (md != NULL) {
+             XMEMCPY(md, dig, WC_SHA384_DIGEST_SIZE);
+             return md;
+         }
+         else {
+             return (unsigned char*)dig;
+    }
+    }
+#endif /* WOLFSSL_SHA384  */
+
+
+#if defined(WOLFSSL_SHA512)
+     /* One shot SHA512 hash of message.
+      *
+      * d  message to hash
+      * n  size of d buffer
+      * md buffer to hold digest. Should be WC_SHA256_DIGEST_SIZE.
+      *
+      * Note: if md is null then a static buffer of WC_SHA256_DIGEST_SIZE is used.
+      *       When the static buffer is used this function is not thread safe.
+      *
+      * Returns a pointer to the message digest on success and NULL on failure.
+      */
+     unsigned char *wolfSSL_SHA512(const unsigned char *d, size_t n,
+             unsigned char *md)
+     {
+         static byte dig[WC_SHA512_DIGEST_SIZE];
+         wc_Sha512 sha;
+
+         WOLFSSL_ENTER("wolfSSL_SHA512");
+
+         if (wc_InitSha512_ex(&sha, NULL, 0) != 0) {
+             WOLFSSL_MSG("SHA512 Init failed");
+             return NULL;
+    }
+
+         if (wc_Sha512Update(&sha, (const byte*)d, (word32)n) != 0) {
+             WOLFSSL_MSG("SHA512 Update failed");
+             return NULL;
+    }
+
+         if (wc_Sha512Final(&sha, dig) != 0) {
+             WOLFSSL_MSG("SHA512 Final failed");
+             return NULL;
+    }
+
+         wc_Sha512Free(&sha);
+
+         if (md != NULL) {
+             XMEMCPY(md, dig, WC_SHA512_DIGEST_SIZE);
+             return md;
+         }
+         else {
+             return (unsigned char*)dig;
+         }
+}
+#endif /* defined(WOLFSSL_SHA512)  */
 
     char wolfSSL_CTX_use_certificate(WOLFSSL_CTX *ctx, WOLFSSL_X509 *x)
-    {
+{
         int ret;
 
@@ -23506,6 +31402,14 @@
             FreeX509(ctx->ourCert);
             XFREE(ctx->ourCert, ctx->heap, DYNAMIC_TYPE_X509);
-        }
+    }
+        #ifndef WOLFSSL_X509_STORE_CERTS
         ctx->ourCert = x;
+        #else
+        ctx->ourCert = wolfSSL_X509_d2i(NULL, x->derCert->buffer,x->derCert->length);
+        if(ctx->ourCert == NULL){
+            return 0;
+    }
+        #endif
+
         ctx->ownOurCert = 0;
 #endif
@@ -23521,13 +31425,14 @@
             case ECDSAk:
                 ctx->haveECC = 1;
-            #ifdef HAVE_ECC
+            #if defined(HAVE_ECC) || defined(HAVE_ED25519)
                 ctx->pkCurveOID = x->pkCurveOID;
             #endif
                 break;
-        }
-
-        return WOLFSSL_SUCCESS;
-    }
-
+    }
+
+    return WOLFSSL_SUCCESS;
+}
+
+    #ifndef NO_WOLFSSL_STUB
     int wolfSSL_BIO_read_filename(WOLFSSL_BIO *b, const char *name) {
     #ifndef NO_FILESYSTEM
@@ -23536,11 +31441,11 @@
         WOLFSSL_ENTER("wolfSSL_BIO_new_file");
 
-        if ((wolfSSL_BIO_get_fp(b, &fp) == WOLFSSL_SUCCESS) && (fp != NULL))
-        {
+        if ((wolfSSL_BIO_get_fp(b, &fp) == WOLFSSL_SUCCESS) && (fp != XBADFILE))
+{
             XFCLOSE(fp);
-        }
+}
 
         fp = XFOPEN(name, "r");
-        if (fp == NULL)
+        if (fp == XBADFILE)
             return WOLFSSL_BAD_FILE;
 
@@ -23558,4 +31463,5 @@
     #endif
     }
+    #endif
 
 #ifdef HAVE_ECC
@@ -23568,48 +31474,345 @@
             if (n == ecc_sets[i].id) {
                 return ecc_sets[i].name;
-            }
-        }
+        }
+    }
         return NULL;
     }
 
-    int wolfSSL_OBJ_obj2nid(const WOLFSSL_ASN1_OBJECT *o) {
-        (void)o;
+#endif /* HAVE_ECC */
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+    int wolfSSL_OBJ_sn2nid(const char *sn) {
+
+        WOLFSSL_ENTER("wolfSSL_OBJ_sn2nid");
+        return OBJ_sn2nid(sn);
+    }
+#endif
+
+    static int oid2nid(word32 oid, int grp)
+    {
+        /* get OID type */
+        switch (grp) {
+            /* oidHashType */
+            case oidHashType:
+                switch (oid) {
+                #ifdef WOLFSSL_MD2
+                    case MD2h:
+                        return NID_md2;
+                #endif
+                #ifndef NO_MD5
+                    case MD5h:
+                        return NID_md5;
+                #endif
+                #ifndef NO_SHA
+                    case SHAh:
+                        return NID_sha1;
+                #endif
+                    case SHA224h:
+                        return NID_sha224;
+                #ifndef NO_SHA256
+                    case SHA256h:
+                        return NID_sha256;
+                #endif
+                #ifdef WOLFSSL_SHA384
+                    case SHA384h:
+                        return NID_sha384;
+                #endif
+                #ifdef WOLFSSL_SHA512
+                    case SHA512h:
+                        return NID_sha512;
+                #endif
+    }
+                break;
+
+            /*  oidSigType */
+            case oidSigType:
+                switch (oid) {
+                #ifndef NO_DSA
+                    case CTC_SHAwDSA:
+                        return CTC_SHAwDSA;
+                #endif /* NO_DSA */
+                #ifndef NO_RSA
+                    case CTC_MD2wRSA:
+                        return CTC_MD2wRSA;
+                    case CTC_MD5wRSA:
+                        return CTC_MD5wRSA;
+                    case CTC_SHAwRSA:
+                        return CTC_SHAwRSA;
+                    case CTC_SHA224wRSA:
+                        return CTC_SHA224wRSA;
+                    case CTC_SHA256wRSA:
+                        return CTC_SHA256wRSA;
+                    case CTC_SHA384wRSA:
+                        return CTC_SHA384wRSA;
+                    case CTC_SHA512wRSA:
+                        return CTC_SHA512wRSA;
+                #endif /* NO_RSA */
+                #ifdef HAVE_ECC
+                    case CTC_SHAwECDSA:
+                        return CTC_SHAwECDSA;
+                    case CTC_SHA224wECDSA:
+                        return CTC_SHA224wECDSA;
+                    case CTC_SHA256wECDSA:
+                        return CTC_SHA256wECDSA;
+                    case CTC_SHA384wECDSA:
+                        return CTC_SHA384wECDSA;
+                    case CTC_SHA512wECDSA:
+                        return CTC_SHA512wECDSA;
+                #endif /* HAVE_ECC */
+        }
+                break;
+
+            /* oidKeyType */
+            case oidKeyType:
+                switch (oid) {
+                #ifndef NO_DSA
+                    case DSAk:
+                        return DSAk;
+                #endif /* NO_DSA */
+                #ifndef NO_RSA
+                    case RSAk:
+                        return RSAk;
+                #endif /* NO_RSA */
+                #ifdef HAVE_NTRU
+                    case NTRUk:
+                        return NTRUk;
+                #endif /* HAVE_NTRU */
+                #ifdef HAVE_ECC
+                    case ECDSAk:
+                        return ECDSAk;
+                #endif /* HAVE_ECC */
+    }
+                break;
+
+            /* oidBlkType */
+            case oidBlkType:
+                switch (oid) {
+                #ifdef WOLFSSL_AES_128
+                    case AES128CBCb:
+                        return AES128CBCb;
+                #endif
+                #ifdef WOLFSSL_AES_192
+                    case AES192CBCb:
+                        return AES192CBCb;
+                #endif
+                #ifdef WOLFSSL_AES_256
+                    case AES256CBCb:
+                        return AES256CBCb;
+                #endif
+                #ifndef NO_DES3
+                    case DESb:
+                        return NID_des;
+                    case DES3b:
+                        return NID_des3;
+                #endif
+    }
+                break;
+
+        #ifdef HAVE_OCSP
+            case oidOcspType:
+                switch (oid) {
+                    case OCSP_BASIC_OID:
+                        return NID_id_pkix_OCSP_basic;
+                    case OCSP_NONCE_OID:
+                        return OCSP_NONCE_OID;
+    }
+                break;
+        #endif /* HAVE_OCSP */
+
+            /* oidCertExtType */
+            case oidCertExtType:
+                switch (oid) {
+                    case BASIC_CA_OID:
+                        return BASIC_CA_OID;
+                    case ALT_NAMES_OID:
+                        return ALT_NAMES_OID;
+                    case CRL_DIST_OID:
+                        return CRL_DIST_OID;
+                    case AUTH_INFO_OID:
+                        return AUTH_INFO_OID;
+                    case AUTH_KEY_OID:
+                        return AUTH_KEY_OID;
+                    case SUBJ_KEY_OID:
+                        return SUBJ_KEY_OID;
+                    case INHIBIT_ANY_OID:
+                        return INHIBIT_ANY_OID;
+                    case KEY_USAGE_OID:
+                        return NID_ext_key_usage;
+                    case NAME_CONS_OID:
+                        return NID_name_constraints;
+                    case CERT_POLICY_OID:
+                        return NID_certificate_policies;
+    }
+                break;
+
+            /* oidCertAuthInfoType */
+            case oidCertAuthInfoType:
+                switch (oid) {
+                    case AIA_OCSP_OID:
+                        return AIA_OCSP_OID;
+                    case AIA_CA_ISSUER_OID:
+                        return AIA_CA_ISSUER_OID;
+    }
+                break;
+
+            /* oidCertPolicyType */
+            case oidCertPolicyType:
+                switch (oid) {
+                    case CP_ANY_OID:
+                        return NID_any_policy;
+}
+                break;
+
+            /* oidCertAltNameType */
+            case oidCertAltNameType:
+                switch (oid) {
+                    case HW_NAME_OID:
+                        return NID_hw_name_oid;
+                }
+                break;
+
+            /* oidCertKeyUseType */
+            case oidCertKeyUseType:
+                switch (oid) {
+                    case EKU_ANY_OID:
+                        return NID_anyExtendedKeyUsage;
+                    case EKU_SERVER_AUTH_OID:
+                        return EKU_SERVER_AUTH_OID;
+                    case EKU_CLIENT_AUTH_OID:
+                        return EKU_CLIENT_AUTH_OID;
+                    case EKU_OCSP_SIGN_OID:
+                        return EKU_OCSP_SIGN_OID;
+                }
+                break;
+
+            /* oidKdfType */
+            case oidKdfType:
+                switch (oid) {
+                    case PBKDF2_OID:
+                        return PBKDF2_OID;
+                }
+                break;
+
+            /* oidPBEType */
+            case oidPBEType:
+                switch (oid) {
+                    case PBE_SHA1_RC4_128:
+                        return PBE_SHA1_RC4_128;
+                    case PBE_SHA1_DES:
+                        return PBE_SHA1_DES;
+                    case PBE_SHA1_DES3:
+                        return PBE_SHA1_DES3;
+    }
+                break;
+
+            /* oidKeyWrapType */
+            case oidKeyWrapType:
+                switch (oid) {
+                #ifdef WOLFSSL_AES_128
+                    case AES128_WRAP:
+                        return AES128_WRAP;
+                #endif
+                #ifdef WOLFSSL_AES_192
+                    case AES192_WRAP:
+                        return AES192_WRAP;
+                #endif
+                #ifdef WOLFSSL_AES_256
+                    case AES256_WRAP:
+                        return AES256_WRAP;
+                #endif
+    }
+                break;
+
+            /* oidCmsKeyAgreeType */
+            case oidCmsKeyAgreeType:
+                switch (oid) {
+                    #ifndef NO_SHA
+                    case dhSinglePass_stdDH_sha1kdf_scheme:
+                        return dhSinglePass_stdDH_sha1kdf_scheme;
+                    #endif
+                    #ifdef WOLFSSL_SHA224
+                    case dhSinglePass_stdDH_sha224kdf_scheme:
+                        return dhSinglePass_stdDH_sha224kdf_scheme;
+                    #endif
+                    #ifndef NO_SHA256
+                    case dhSinglePass_stdDH_sha256kdf_scheme:
+                        return dhSinglePass_stdDH_sha256kdf_scheme;
+                    #endif
+                    #ifdef WOLFSSL_SHA384
+                    case dhSinglePass_stdDH_sha384kdf_scheme:
+                        return dhSinglePass_stdDH_sha384kdf_scheme;
+                    #endif
+                    #ifdef WOLFSSL_SHA512
+                    case dhSinglePass_stdDH_sha512kdf_scheme:
+                        return dhSinglePass_stdDH_sha512kdf_scheme;
+                    #endif
+    }
+                break;
+
+            default:
+                WOLFSSL_MSG("NID not in table");
+                return -1;
+}
+
+        return -1;
+    }
+
+    /* Gets the NID value that corresponds with the ASN1 object.
+     *
+     * o ASN1 object to get NID of
+     *
+     * Return NID on success and a negative value on failure
+ */
+    int wolfSSL_OBJ_obj2nid(const WOLFSSL_ASN1_OBJECT *o)
+{
+        word32 oid = 0;
+        word32 idx = 0;
+        int id;
+
         WOLFSSL_ENTER("wolfSSL_OBJ_obj2nid");
-        WOLFSSL_STUB("wolfSSL_OBJ_obj2nid");
+
+        if (o == NULL) {
+            return -1;
+        }
+        if (o->nid > 0)
+            return o->nid;
+        if ((id = GetObjectId(o->obj, &idx, &oid, o->grp, o->objSz)) < 0) {
+            WOLFSSL_MSG("Issue getting OID of object");
+            return -1;
+}
+
+        return oid2nid(oid, o->grp);
+    }
+
+#ifndef NO_WOLFSSL_STUB
+    char * wolfSSL_OBJ_nid2ln(int n)
+{
+        (void)n;
+        WOLFSSL_ENTER("wolfSSL_OBJ_nid2ln");
+        WOLFSSL_STUB("OBJ_nid2ln");
+
+    return NULL;
+}
+#endif
+
+#ifndef NO_WOLFSSL_STUB
+    int wolfSSL_OBJ_txt2nid(const char* s)
+{
+        (void)s;
+        WOLFSSL_STUB("OBJ_txt2nid");
 
         return 0;
-    }
-
-    int wolfSSL_OBJ_sn2nid(const char *sn) {
-        int i;
-        WOLFSSL_ENTER("wolfSSL_OBJ_osn2nid");
-
-        /* Nginx uses this OpenSSL string. */
-        if (XSTRNCMP(sn, "prime256v1", 10) == 0)
-            sn = "SECP256R1";
-        if (XSTRNCMP(sn, "secp384r1", 10) == 0)
-            sn = "SECP384R1";
-        /* find based on name and return NID */
-        for (i = 0; i < ecc_sets[i].size; i++) {
-            if (XSTRNCMP(sn, ecc_sets[i].name, ECC_MAXNAME) == 0) {
-                return ecc_sets[i].id;
-            }
-        }
-        return -1;
-    }
-#endif /* HAVE_ECC */
-
-
-    void wolfSSL_CTX_set_verify_depth(WOLFSSL_CTX *ctx, int depth) {
-        WOLFSSL_ENTER("wolfSSL_CTX_set_verify_depth");
-#ifndef OPENSSL_EXTRA
-        (void)ctx;
-        (void)depth;
-        WOLFSSL_STUB("wolfSSL_CTX_set_verify_depth");
-#else
-        ctx->verifyDepth = depth;
-#endif
-    }
-
+}
+#endif
+
+    /* compatibility function. It's intended use is to remove OID's from an
+     * internal table that have been added with OBJ_create. wolfSSL manages it's
+     * own interenal OID values and does not currently support OBJ_create. */
+    void wolfSSL_OBJ_cleanup(void)
+{
+        WOLFSSL_ENTER("wolfSSL_OBJ_cleanup()");
+}
+
+
+    #ifndef NO_WOLFSSL_STUB
     void wolfSSL_set_verify_depth(WOLFSSL *ssl, int depth) {
         WOLFSSL_ENTER("wolfSSL_set_verify_depth");
@@ -23619,68 +31822,146 @@
         WOLFSSL_STUB("wolfSSL_set_verify_depth");
 #else
-        ssl->options.verifyDepth = depth;
-#endif
-    }
-
-    void* wolfSSL_get_app_data( const WOLFSSL *ssl) {
-        /* checkout exdata stuff... */
-        return wolfSSL_get_ex_data(ssl,0);
-    }
-
-    int wolfSSL_set_app_data(WOLFSSL *ssl, void *arg) {
-        return wolfSSL_set_ex_data(ssl,0,(char *)arg);
-    }
+        ssl->options.verifyDepth = (byte)depth;
+#endif
+    }
+    #endif
+
 
     WOLFSSL_ASN1_OBJECT * wolfSSL_X509_NAME_ENTRY_get_object(WOLFSSL_X509_NAME_ENTRY *ne) {
-        (void)ne;
         WOLFSSL_ENTER("wolfSSL_X509_NAME_ENTRY_get_object");
-        WOLFSSL_STUB("wolfSSL_X509_NAME_ENTRY_get_object");
-
-        return NULL;
-    }
+        if (ne == NULL) return NULL;
+        wolfSSL_OBJ_nid2obj_ex(ne->nid, &ne->object);
+        ne->object.nid = ne->nid;
+        return &ne->object;
+}
+
+    static WOLFSSL_X509_NAME *get_nameByLoc( WOLFSSL_X509_NAME *name, int loc)
+{
+        switch (loc)
+        {
+        case 0:
+            name->cnEntry.value->length = name->fullName.cnLen;
+            name->cnEntry.value->data   = &name->fullName.fullName[name->fullName.cnIdx];
+            name->cnEntry.nid           = name->fullName.cnNid;
+            break;
+        case 1:
+            name->cnEntry.value->length = name->fullName.cLen;
+            name->cnEntry.value->data   = &name->fullName.fullName[name->fullName.cIdx];
+            name->cnEntry.nid           = name->fullName.cNid;
+            break;
+        case 2:
+            name->cnEntry.value->length = name->fullName.lLen;
+            name->cnEntry.value->data   = &name->fullName.fullName[name->fullName.lIdx];
+            name->cnEntry.nid           = name->fullName.lNid;
+            break;
+        case 3:
+            name->cnEntry.value->length = name->fullName.stLen;
+            name->cnEntry.value->data   = &name->fullName.fullName[name->fullName.stIdx];
+            name->cnEntry.nid           = name->fullName.stNid;
+            break;
+        case 4:
+            name->cnEntry.value->length = name->fullName.oLen;
+            name->cnEntry.value->data   = &name->fullName.fullName[name->fullName.oIdx];
+            name->cnEntry.nid           = name->fullName.oNid;
+            break;
+        case 5:
+            name->cnEntry.value->length = name->fullName.ouLen;
+            name->cnEntry.value->data   = &name->fullName.fullName[name->fullName.ouIdx];
+            name->cnEntry.nid           = name->fullName.ouNid;
+            break;
+        case 6:
+            name->cnEntry.value->length = name->fullName.emailLen;
+            name->cnEntry.value->data   = &name->fullName.fullName[name->fullName.emailIdx];
+            name->cnEntry.nid           = name->fullName.emailNid;
+            break;
+        case 7:
+            name->cnEntry.value->length = name->fullName.snLen;
+            name->cnEntry.value->data = &name->fullName.fullName[name->fullName.snIdx];
+            name->cnEntry.nid           = name->fullName.snNid;
+            break;
+        case 8:
+            name->cnEntry.value->length = name->fullName.uidLen;
+            name->cnEntry.value->data   = &name->fullName.fullName[name->fullName.uidIdx];
+            name->cnEntry.nid           = name->fullName.uidNid;
+            break;
+        case 9:
+            name->cnEntry.value->length = name->fullName.serialLen;
+            name->cnEntry.value->data   = &name->fullName.fullName[name->fullName.serialIdx];
+            name->cnEntry.nid           = name->fullName.serialNid;
+            break;
+        default:
+    return NULL;
+}
+        if (name->cnEntry.value->length == 0)
+            return NULL;
+        name->cnEntry.value->type   = CTC_UTF8;
+        return name;
+    }
+
 
     WOLFSSL_X509_NAME_ENTRY *wolfSSL_X509_NAME_get_entry(
-                                             WOLFSSL_X509_NAME *name, int loc) {
-
-        int maxLoc = name->fullName.fullNameLen;
-
+                                             WOLFSSL_X509_NAME *name, int loc)
+    {
         WOLFSSL_ENTER("wolfSSL_X509_NAME_get_entry");
 
-        if (loc < 0 || loc > maxLoc) {
+        if (name == NULL) {
+            return NULL;
+}
+
+        if (loc < 0 || loc > 9 + name->fullName.dcNum) {
             WOLFSSL_MSG("Bad argument");
             return NULL;
         }
 
-        /* common name index case */
-        if (loc == name->fullName.cnIdx) {
+        if (loc >= 0 && loc <= 9){
+            if (get_nameByLoc(name, loc) != NULL)
+                return &name->cnEntry;
+}
+
+        /* DC component */
+        if (name->fullName.dcMode){
+            if (name->fullName.fullName != NULL){
+                if (loc == name->fullName.dcNum){
+                    name->cnEntry.data.data   = &name->fullName.fullName[name->fullName.cIdx];
+                    name->cnEntry.data.length = name->fullName.cLen;
+                    name->cnEntry.nid         = ASN_COUNTRY_NAME;
+                } else {
+                    name->cnEntry.data.data   = &name->fullName.fullName[name->fullName.dcIdx[loc]];
+                    name->cnEntry.data.length = name->fullName.dcLen[loc];
+                    name->cnEntry.nid         = ASN_DOMAIN_COMPONENT;
+                }
+            }
+            name->cnEntry.data.type = CTC_UTF8;
+            name->cnEntry.set       = 1;
+
+         /* common name index case */
+        } else if (loc == name->fullName.cnIdx && name->x509 != NULL) {
             /* get CN shortcut from x509 since it has null terminator */
             name->cnEntry.data.data   = name->x509->subjectCN;
             name->cnEntry.data.length = name->fullName.cnLen;
-            name->cnEntry.data.type   = ASN_COMMON_NAME;
-            name->cnEntry.set  = 1;
-            return &(name->cnEntry);
-        }
-
-        /* additionall cases to check for go here */
-
-        WOLFSSL_MSG("Entry not found or implemented");
-        (void)name;
-        (void)loc;
-
-        return NULL;
-    }
-
+            name->cnEntry.data.type   = CTC_UTF8;
+            name->cnEntry.nid         = ASN_COMMON_NAME;
+            name->cnEntry.set         = 1;
+        }
+        else
+            return NULL;
+
+        return &name->cnEntry;
+    }
+
+    #ifndef NO_WOLFSSL_STUB
     void wolfSSL_sk_X509_NAME_pop_free(WOLF_STACK_OF(WOLFSSL_X509_NAME)* sk, void f (WOLFSSL_X509_NAME*)){
         (void) sk;
         (void) f;
         WOLFSSL_ENTER("wolfSSL_sk_X509_NAME_pop_free");
-        WOLFSSL_STUB("wolfSSL_sk_X509_NAME_pop_free");
-    }
-
+        WOLFSSL_STUB("sk_X509_NAME_pop_free");
+    }
+    #endif
+    #ifndef NO_WOLFSSL_STUB
     int wolfSSL_X509_check_private_key(WOLFSSL_X509 *x509, WOLFSSL_EVP_PKEY *key){
         (void) x509;
         (void) key;
         WOLFSSL_ENTER("wolfSSL_X509_check_private_key");
-        WOLFSSL_STUB("wolfSSL_X509_check_private_key");
+        WOLFSSL_STUB("X509_check_private_key");
 
         return WOLFSSL_SUCCESS;
@@ -23690,12 +31971,12 @@
         (void) sk;
         WOLFSSL_ENTER("wolfSSL_dup_CA_list");
-        WOLFSSL_STUB("wolfSSL_dup_CA_list");
+        WOLFSSL_STUB("SSL_dup_CA_list");
 
         return NULL;
-    }
-
-#endif /* HAVE_LIGHTY || WOLFSSL_MYSQL_COMPATIBLE || HAVE_STUNNEL || WOLFSSL_NGINX || HAVE_POCO_LIB || WOLFSSL_HAPROXY */
+}
+    #endif
+
+#endif /* OPENSSL_ALL || HAVE_LIGHTY || WOLFSSL_MYSQL_COMPATIBLE || HAVE_STUNNEL || WOLFSSL_NGINX || HAVE_POCO_LIB || WOLFSSL_HAPROXY */
 #endif /* OPENSSL_EXTRA */
-
 
 #ifdef OPENSSL_EXTRA
@@ -23710,5 +31991,5 @@
     (void)line;
     (void)file;
-#if defined(WOLFSSL_NGINX) || defined(DEBUG_WOLFSSL) || defined(WOLFSSL_HAPROXY)
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(DEBUG_WOLFSSL) || defined(WOLFSSL_HAPROXY)
     {
         int ret;
@@ -23717,7 +31998,7 @@
             WOLFSSL_MSG("Issue peeking at error node in queue");
             return 0;
-        }
-    #ifdef WOLFSSL_NGINX
-        if (ret == -SSL_NO_PEM_HEADER)
+    }
+    #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX)
+        if (ret == -ASN_NO_PEM_HEADER)
             return (ERR_LIB_PEM << 24) | PEM_R_NO_START_LINE;
     #endif
@@ -23727,5 +32008,5 @@
     return (unsigned long)(0 - NOT_COMPILED_IN);
 #endif
-}
+    }
 
 
@@ -23739,8 +32020,14 @@
     }
 
-    return wolfSSL_CTX_use_PrivateKey_buffer(ctx,
+    if (pkey->pkey.ptr != NULL) {
+        /* ptr for WOLFSSL_EVP_PKEY struct is expected to be DER format */
+        return wolfSSL_CTX_use_PrivateKey_buffer(ctx,
                                        (const unsigned char*)pkey->pkey.ptr,
-                                       pkey->pkey_sz, PRIVATEKEY_TYPE);
-}
+                                       pkey->pkey_sz, SSL_FILETYPE_ASN1);
+    }
+
+    WOLFSSL_MSG("wolfSSL private key not set");
+    return BAD_FUNC_ARG;
+    }
 #endif /* !NO_CERTS */
 
@@ -23752,5 +32039,5 @@
     if(ctx != NULL && idx < MAX_EX_DATA && idx >= 0) {
         return ctx->ex_data[idx];
-    }
+}
     #else
     (void)ctx;
@@ -23776,4 +32063,26 @@
 
 
+/* Return the index that can be used for the WOLFSSL structure to store
+ * application data.
+ *
+ */
+int wolfSSL_get_ex_new_index(long argValue, void* arg,
+        WOLFSSL_CRYPTO_EX_new* cb1, WOLFSSL_CRYPTO_EX_dup* cb2,
+        WOLFSSL_CRYPTO_EX_free* cb3)
+{
+    static int ssl_idx = 0;
+
+    WOLFSSL_ENTER("wolfSSL_get_ex_new_index");
+
+    (void)argValue;
+    (void)arg;
+    (void)cb1;
+    (void)cb2;
+    (void)cb3;
+
+    return ssl_idx++;
+}
+
+
 int wolfSSL_CTX_set_ex_data(WOLFSSL_CTX* ctx, int idx, void* data)
 {
@@ -23794,4 +32103,31 @@
 
 
+/* Returns char* to app data stored in ex[0].
+ *
+ * ssl WOLFSSL structure to get app data from
+ */
+void* wolfSSL_get_app_data(const WOLFSSL *ssl)
+{
+    /* checkout exdata stuff... */
+    WOLFSSL_ENTER("wolfSSL_get_app_data");
+
+    return wolfSSL_get_ex_data(ssl, 0);
+}
+
+
+/* Set ex array 0 to have app data
+ *
+ * ssl WOLFSSL struct to set app data in
+ * arg data to be stored
+ *
+ * Returns SSL_SUCCESS on sucess and SSL_FAILURE on failure
+ */
+int wolfSSL_set_app_data(WOLFSSL *ssl, void* arg) {
+    WOLFSSL_ENTER("wolfSSL_set_app_data");
+
+    return wolfSSL_set_ex_data(ssl, 0, arg);
+}
+
+
 int wolfSSL_set_ex_data(WOLFSSL* ssl, int idx, void* data)
 {
@@ -23804,4 +32140,5 @@
     }
 #else
+    WOLFSSL_MSG("HAVE_EX_DATA macro is not defined");
     (void)ssl;
     (void)idx;
@@ -23811,19 +32148,4 @@
 }
 
-
-int wolfSSL_get_ex_new_index(long idx, void* data, void* cb1, void* cb2,
-                         void* cb3)
-{
-    static int ssl_idx = 0;
-
-    WOLFSSL_ENTER("wolfSSL_get_ex_new_index");
-    (void)idx;
-    (void)data;
-    (void)cb1;
-    (void)cb2;
-    (void)cb3;
-
-    return ssl_idx++;
-}
 
 
@@ -23835,4 +32157,5 @@
         return ssl->ex_data[idx];
 #else
+    WOLFSSL_MSG("HAVE_EX_DATA macro is not defined");
     (void)ssl;
     (void)idx;
@@ -23844,5 +32167,5 @@
 WOLFSSL_DSA *wolfSSL_PEM_read_bio_DSAparams(WOLFSSL_BIO *bp, WOLFSSL_DSA **x,
         pem_password_cb *cb, void *u)
-{
+        {
     WOLFSSL_DSA* dsa;
     DsaKey* key;
@@ -23860,5 +32183,5 @@
         WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_DSAparams", ret);
         return NULL;
-    }
+            }
 
     bufSz = (word32)ret;
@@ -23870,5 +32193,5 @@
          */
         WOLFSSL_MSG("Not yet supporting call back or password for encrypted PEM");
-    }
+}
 
     if ((ret = PemToDer(buf, (long)bufSz, DSA_PARAM_TYPE, &pDer, NULL, NULL,
@@ -23906,5 +32229,5 @@
         wolfSSL_DSA_free(dsa);
         return NULL;
-    }
+}
 
     if (SetIndividualExternal(&dsa->p, &key->p) != WOLFSSL_SUCCESS) {
@@ -23926,6 +32249,6 @@
         FreeDer(&pDer);
         wolfSSL_DSA_free(dsa);
-        return NULL;
-    }
+    return NULL;
+}
 
     if (x != NULL) {
@@ -23941,25 +32264,78 @@
 #include "src/bio.c"
 
+/* Begin functions for openssl/buffer.h */
+WOLFSSL_BUF_MEM* wolfSSL_BUF_MEM_new(void)
+{
+    WOLFSSL_BUF_MEM* buf;
+    buf = (WOLFSSL_BUF_MEM*)XMALLOC(sizeof(WOLFSSL_BUF_MEM), NULL,
+                                                        DYNAMIC_TYPE_OPENSSL);
+    if (buf) {
+        XMEMSET(buf, 0, sizeof(WOLFSSL_BUF_MEM));
+    }
+    return buf;
+}
+
+
+/* returns length of buffer on success */
+int wolfSSL_BUF_MEM_grow(WOLFSSL_BUF_MEM* buf, size_t len)
+{
+    int len_int = (int)len;
+    int mx;
+
+    /* verify provided arguments */
+    if (buf == NULL || len_int < 0) {
+        return 0; /* BAD_FUNC_ARG; */
+    }
+
+    /* check to see if fits in existing length */
+    if (buf->length > len) {
+        buf->length = len;
+        return len_int;
+}
+
+    /* check to see if fits in max buffer */
+    if (buf->max >= len) {
+        if (buf->data != NULL) {
+            XMEMSET(&buf->data[buf->length], 0, len - buf->length);
+        }
+        buf->length = len;
+        return len_int;
+    }
+
+    /* expand size, to handle growth */
+    mx = (len_int + 3) / 3 * 4;
+
+    /* use realloc */
+    buf->data = (char*)XREALLOC(buf->data, mx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (buf->data == NULL) {
+        return 0; /* ERR_R_MALLOC_FAILURE; */
+}
+
+    buf->max = mx;
+    XMEMSET(&buf->data[buf->length], 0, len - buf->length);
+    buf->length = len;
+
+    return len_int;
+}
+
+void wolfSSL_BUF_MEM_free(WOLFSSL_BUF_MEM* buf)
+{
+    if (buf) {
+        if (buf->data) {
+            XFREE(buf->data, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            buf->data = NULL;
+        }
+        buf->max = 0;
+        buf->length = 0;
+        XFREE(buf, NULL, DYNAMIC_TYPE_OPENSSL);
+}
+}
+/* End Functions for openssl/buffer.h */
+
 #endif /* OPENSSL_EXTRA */
 
 
 #if defined(HAVE_LIGHTY) || defined(HAVE_STUNNEL) \
-    || defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(OPENSSL_EXTRA) || defined(WOLFSSL_HAPROXY)
-char * wolfSSL_OBJ_nid2ln(int n) {
-    (void)n;
-    WOLFSSL_ENTER("wolfSSL_OBJ_nid2ln");
-    WOLFSSL_STUB("wolfSSL_OBJ_nid2ln");
-
-    return NULL;
-}
-
-int wolfSSL_OBJ_txt2nid(const char* s) {
-    (void)s;
-    WOLFSSL_ENTER("wolfSSL_OBJ_txt2nid");
-    WOLFSSL_STUB("wolfSSL_OBJ_txt2nid");
-
-    return 0;
-}
-
+    || defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(OPENSSL_EXTRA)
 
 WOLFSSL_BIO *wolfSSL_BIO_new_file(const char *filename, const char *mode)
@@ -23972,6 +32348,6 @@
 
     fp = XFOPEN(filename, mode);
-    if (fp == NULL)
-        return NULL;
+    if (fp == XBADFILE)
+    return NULL;
 
     bio = wolfSSL_BIO_new(wolfSSL_BIO_s_file());
@@ -23979,5 +32355,5 @@
         XFCLOSE(fp);
         return bio;
-    }
+}
 
     if (wolfSSL_BIO_set_fp(bio, fp, BIO_CLOSE) != WOLFSSL_SUCCESS) {
@@ -23985,5 +32361,5 @@
         wolfSSL_BIO_free(bio);
         bio = NULL;
-    }
+}
 
     /* file is closed when BIO is free'd */
@@ -23993,5 +32369,5 @@
     (void)mode;
     return NULL;
-#endif
+#endif /* NO_FILESYSTEM */
 }
 
@@ -24020,8 +32396,8 @@
     if (bio == NULL) {
         WOLFSSL_MSG("Bad Function Argument bio is NULL");
-        return NULL;
-    }
-
-    if (bio->type == BIO_MEMORY) {
+    return NULL;
+}
+
+    if (bio->type == WOLFSSL_BIO_MEMORY) {
         /* Use the buffer directly. */
         ret = wolfSSL_BIO_get_mem_data(bio, &mem);
@@ -24032,9 +32408,11 @@
         size = ret;
     }
-    else if (bio->type == BIO_FILE) {
+    else if (bio->type == WOLFSSL_BIO_FILE) {
         /* Read whole file into a new buffer. */
-        XFSEEK(bio->file, 0, SEEK_END);
+        if(XFSEEK(bio->file, 0, SEEK_END) != 0)
+            goto end;
         sz = XFTELL(bio->file);
-        XFSEEK(bio->file, 0, SEEK_SET);
+        if(XFSEEK(bio->file, 0, SEEK_SET) != 0)
+            goto end;
         if (sz <= 0L)
             goto end;
@@ -24051,5 +32429,5 @@
         WOLFSSL_MSG("BIO type not supported for reading DH parameters");
         goto end;
-    }
+}
 
     ret = PemToDer(mem, size, DH_PARAM_TYPE, &der, NULL, NULL, NULL);
@@ -24066,5 +32444,5 @@
             goto end;
         XMEMSET(localDh, 0, sizeof(WOLFSSL_DH));
-    }
+}
 
     /* Load data in manually */
@@ -24119,47 +32497,146 @@
 #endif
 
+#ifdef WOLFSSL_CERT_GEN
+
+#ifdef WOLFSSL_CERT_REQ
+/* writes the x509 from x to the WOLFSSL_BIO bp
+ *
+ * returns WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on fail
+ */
+int wolfSSL_PEM_write_bio_X509_REQ(WOLFSSL_BIO *bp, WOLFSSL_X509 *x)
+{
+    byte* pem;
+    int   pemSz = 0;
+    const unsigned char* der;
+    int derSz;
+    int ret;
+
+    WOLFSSL_ENTER("wolfSSL_PEM_write_bio_X509_REQ()");
+
+    if (x == NULL || bp == NULL) {
+        return WOLFSSL_FAILURE;
+}
+
+    der = wolfSSL_X509_get_der(x, &derSz);
+    if (der == NULL) {
+        return WOLFSSL_FAILURE;
+    }
+
+    /* get PEM size */
+    pemSz = wc_DerToPemEx(der, derSz, NULL, 0, NULL, CERTREQ_TYPE);
+    if (pemSz < 0) {
+        return WOLFSSL_FAILURE;
+    }
+
+    /* create PEM buffer and convert from DER */
+    pem = (byte*)XMALLOC(pemSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (pem == NULL) {
+        return WOLFSSL_FAILURE;
+    }
+    if (wc_DerToPemEx(der, derSz, pem, pemSz, NULL, CERTREQ_TYPE) < 0) {
+        XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return WOLFSSL_FAILURE;
+}
+
+    /* write the PEM to BIO */
+    ret = wolfSSL_BIO_write(bp, pem, pemSz);
+    XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+    if (ret <= 0) return WOLFSSL_FAILURE;
+    return WOLFSSL_SUCCESS;
+}
+#endif /* WOLFSSL_CERT_REQ */
+
+
+/* writes the x509 from x to the WOLFSSL_BIO bp
+ *
+ * returns WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on fail
+ */
+int wolfSSL_PEM_write_bio_X509_AUX(WOLFSSL_BIO *bp, WOLFSSL_X509 *x)
+{
+    byte* pem;
+    int   pemSz = 0;
+    const unsigned char* der;
+    int derSz;
+    int ret;
+
+    WOLFSSL_ENTER("wolfSSL_PEM_write_bio_X509_AUX()");
+
+    if (bp == NULL || x == NULL) {
+        WOLFSSL_MSG("NULL argument passed in");
+        return WOLFSSL_FAILURE;
+}
+
+    der = wolfSSL_X509_get_der(x, &derSz);
+    if (der == NULL) {
+        return WOLFSSL_FAILURE;
+}
+
+    /* get PEM size */
+    pemSz = wc_DerToPemEx(der, derSz, NULL, 0, NULL, CERT_TYPE);
+    if (pemSz < 0) {
+        return WOLFSSL_FAILURE;
+}
+
+    /* create PEM buffer and convert from DER */
+    pem = (byte*)XMALLOC(pemSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (pem == NULL) {
+        return WOLFSSL_FAILURE;
+    }
+    if (wc_DerToPemEx(der, derSz, pem, pemSz, NULL, CERT_TYPE) < 0) {
+        XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return WOLFSSL_FAILURE;
+    }
+
+    /* write the PEM to BIO */
+    ret = wolfSSL_BIO_write(bp, pem, pemSz);
+    XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+    if (ret <= 0) return WOLFSSL_FAILURE;
+    return WOLFSSL_SUCCESS;
+}
+#endif /* WOLFSSL_CERT_GEN */
 
 int wolfSSL_PEM_write_bio_X509(WOLFSSL_BIO *bio, WOLFSSL_X509 *cert)
 {
-    byte* certDer;
+    byte* pem;
+    int   pemSz = 0;
+    const unsigned char* der;
     int derSz;
-    int pemSz;
     int ret;
 
-    WOLFSSL_ENTER("wolfSSL_PEM_write_bio_X509");
+    WOLFSSL_ENTER("wolfSSL_PEM_write_bio_X509_AUX()");
 
     if (bio == NULL || cert == NULL) {
+        WOLFSSL_MSG("NULL argument passed in");
         return WOLFSSL_FAILURE;
-    }
-
-    if (bio->type != BIO_MEMORY) {
-        WOLFSSL_MSG("BIO type not supported for writing X509 as PEM");
+}
+
+    der = wolfSSL_X509_get_der(cert, &derSz);
+    if (der == NULL) {
         return WOLFSSL_FAILURE;
     }
 
-    certDer = cert->derCert->buffer;
-    derSz   = cert->derCert->length;
-
-    /* Get PEM encoded length and allocate memory for it. */
-    pemSz = wc_DerToPem(certDer, derSz, NULL, 0, CERT_TYPE);
+    /* get PEM size */
+    pemSz = wc_DerToPemEx(der, derSz, NULL, 0, NULL, CERT_TYPE);
     if (pemSz < 0) {
-        WOLFSSL_LEAVE("wolfSSL_PEM_write_bio_X509", pemSz);
         return WOLFSSL_FAILURE;
     }
-    if (bio->mem != NULL) {
-        XFREE(bio->mem, NULL, DYNAMIC_TYPE_OPENSSL);
-    }
-    bio->mem = (byte*)XMALLOC(pemSz, NULL, DYNAMIC_TYPE_OPENSSL);
-    if (bio->mem == NULL) {
+
+    /* create PEM buffer and convert from DER */
+    pem = (byte*)XMALLOC(pemSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (pem == NULL) {
         return WOLFSSL_FAILURE;
     }
-    bio->memLen = pemSz;
-
-    ret = wc_DerToPemEx(certDer, derSz, bio->mem, bio->memLen, NULL, CERT_TYPE);
-    if (ret < 0) {
-        WOLFSSL_LEAVE("wolfSSL_PEM_write_bio_X509", ret);
+    if (wc_DerToPemEx(der, derSz, pem, pemSz, NULL, CERT_TYPE) < 0) {
+        XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
         return WOLFSSL_FAILURE;
-    }
-
+}
+
+    /* write the PEM to BIO */
+    ret = wolfSSL_BIO_write(bio, pem, pemSz);
+    XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+    if (ret <= 0) return WOLFSSL_FAILURE;
     return WOLFSSL_SUCCESS;
 }
@@ -24194,5 +32671,5 @@
         XFREE(p, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
         return MEMORY_E;
-    }
+}
 
     pSz = wolfSSL_BN_bn2bin(dh->p, p);
@@ -24208,20 +32685,422 @@
 }
 #endif /* OPENSSL_EXTRA && !NO_DH */
-#endif /* HAVE_LIGHTY || HAVE_STUNNEL || WOLFSSL_MYSQL_COMPATIBLE || WOLFSSL_HAPROXY */
+
+
+/* returns the enum value associated with handshake state
+ *
+ * ssl the WOLFSSL structure to get state of
+ */
+int wolfSSL_get_state(const WOLFSSL* ssl)
+{
+    WOLFSSL_ENTER("wolfSSL_get_state");
+
+    if (ssl == NULL) {
+        WOLFSSL_MSG("Null argument passed in");
+        return SSL_FAILURE;
+    }
+
+    return ssl->options.handShakeState;
+}
+#endif /* HAVE_LIGHTY || HAVE_STUNNEL || WOLFSSL_MYSQL_COMPATIBLE */
+
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO)
+
+/* Returns the verifyCallback from the ssl structure if successful.
+Returns NULL otherwise. */
+VerifyCallback wolfSSL_get_verify_callback(WOLFSSL* ssl)
+{
+    WOLFSSL_ENTER("wolfSSL_get_verify_callback()");
+    if (ssl) {
+        return ssl->verifyCallback;
+    }
+    return NULL;
+}
+
+/* Creates a new bio pair.
+Returns WOLFSSL_SUCCESS if no error, WOLFSSL_FAILURE otherwise.*/
+int wolfSSL_BIO_new_bio_pair(WOLFSSL_BIO **bio1_p, size_t writebuf1,
+                                         WOLFSSL_BIO **bio2_p, size_t writebuf2)
+{
+    WOLFSSL_BIO *bio1 = NULL, *bio2 = NULL;
+    int ret = 1;
+
+    WOLFSSL_ENTER("wolfSSL_BIO_new_bio_pair()");
+
+    if (bio1_p == NULL || bio2_p == NULL) {
+        WOLFSSL_MSG("Bad Function Argument");
+        return BAD_FUNC_ARG;
+}
+
+    /* set up the new bio structures and write buf sizes */
+    if ((bio1 = wolfSSL_BIO_new(wolfSSL_BIO_s_bio())) == NULL) {
+        WOLFSSL_MSG("Bio allocation failed");
+        ret = WOLFSSL_FAILURE;
+    }
+    if (ret) {
+        if ((bio2 = wolfSSL_BIO_new(wolfSSL_BIO_s_bio())) == NULL) {
+            WOLFSSL_MSG("Bio allocation failed");
+            ret = WOLFSSL_FAILURE;
+        }
+    }
+    if (ret && writebuf1) {
+        if (!(ret = wolfSSL_BIO_set_write_buf_size(bio1, writebuf1))) {
+            WOLFSSL_MSG("wolfSSL_BIO_set_write_buf() failure");
+        }
+    }
+    if (ret && writebuf2) {
+        if (!(ret = wolfSSL_BIO_set_write_buf_size(bio2, writebuf2))) {
+            WOLFSSL_MSG("wolfSSL_BIO_set_write_buf() failure");
+        }
+    }
+
+    if (ret) {
+        if ((ret = wolfSSL_BIO_make_bio_pair(bio1, bio2))) {
+            *bio1_p = bio1;
+            *bio2_p = bio2;
+        }
+    }
+    if (!ret) {
+        wolfSSL_BIO_free(bio1);
+        bio1 = NULL;
+        wolfSSL_BIO_free(bio2);
+        bio2 = NULL;
+    }
+    return ret;
+}
+
+
+#if !defined(NO_RSA)
+/* Converts an rsa key from a bio buffer into an internal rsa structure.
+Returns a pointer to the new WOLFSSL_RSA structure. */
+WOLFSSL_RSA* wolfSSL_d2i_RSAPrivateKey_bio(WOLFSSL_BIO *bio, WOLFSSL_RSA **out)
+{
+    const unsigned char* bioMem = NULL;
+    int bioMemSz = 0;
+    WOLFSSL_RSA* key = NULL;
+    unsigned char maxKeyBuf[4096];
+    unsigned char* bufPtr = NULL;
+    unsigned char* extraBioMem = NULL;
+    int extraBioMemSz = 0;
+    int derLength = 0;
+    int j = 0, i = 0;
+
+    WOLFSSL_ENTER("wolfSSL_d2i_RSAPrivateKey_bio()");
+
+    if (bio == NULL) {
+        WOLFSSL_MSG("Bad Function Argument");
+    return NULL;
+}
+    (void)out;
+
+    bioMemSz = wolfSSL_BIO_pending(bio);
+    if (bioMemSz <= 0) {
+        WOLFSSL_MSG("wolfSSL_BIO_pending() failure");
+        return NULL;
+}
+
+    bioMem = (unsigned char*)XMALLOC(bioMemSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (bioMem == NULL) {
+        WOLFSSL_MSG("Malloc failure");
+        return NULL;
+}
+
+    bufPtr = maxKeyBuf;
+    if (wolfSSL_BIO_read(bio, (unsigned char*)bioMem, (int)bioMemSz) == bioMemSz) {
+        const byte* bioMemPt = bioMem; /* leave bioMem pointer unaltered */
+        if ((key = wolfSSL_d2i_RSAPrivateKey(NULL, &bioMemPt, bioMemSz)) == NULL) {
+            XFREE((unsigned char*)bioMem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    return NULL;
+}
+
+        /* This function is used to get the total length of the rsa key. */
+        derLength = wolfSSL_i2d_RSAPrivateKey(key, &bufPtr);
+
+        /* Write extra data back into bio object if necessary. */
+        extraBioMemSz = (bioMemSz - derLength);
+        if (extraBioMemSz > 0) {
+            extraBioMem = (unsigned char *)XMALLOC(extraBioMemSz, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+            if (extraBioMem == NULL) {
+                WOLFSSL_MSG("Malloc failure");
+                XFREE((unsigned char*)extraBioMem, bio->heap,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE((unsigned char*)bioMem, bio->heap,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+                return NULL;
+            }
+
+            for (i = derLength; i < bioMemSz; i++) {
+                *(extraBioMem + j) = *(bioMem + i);
+                j++;
+            }
+
+            wolfSSL_BIO_write(bio, extraBioMem, extraBioMemSz);
+            if (wolfSSL_BIO_pending(bio) <= 0) {
+                WOLFSSL_MSG("Failed to write memory to bio");
+                XFREE((unsigned char*)extraBioMem, bio->heap,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE((unsigned char*)bioMem, bio->heap,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+                return NULL;
+            }
+            XFREE((unsigned char*)extraBioMem, bio->heap,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+        }
+
+        if (out != NULL && key != NULL) {
+            *out = key;
+        }
+    }
+    XFREE((unsigned char*)bioMem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    return key;
+}
+#endif
+
+
+/* Adds the ASN1 certificate to the user ctx.
+Returns WOLFSSL_SUCCESS if no error, returns WOLFSSL_FAILURE otherwise.*/
+int wolfSSL_CTX_use_certificate_ASN1(WOLFSSL_CTX *ctx, int derSz,
+                                                       const unsigned char *der)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_ASN1()");
+    if (der != NULL && ctx != NULL) {
+        if (wolfSSL_CTX_use_certificate_buffer(ctx, der, derSz,
+                                      WOLFSSL_FILETYPE_ASN1) == WOLFSSL_SUCCESS) {
+            return WOLFSSL_SUCCESS;
+        }
+
+    }
+    return WOLFSSL_FAILURE;
+}
+
+
+#if !defined(NO_RSA) && !defined(HAVE_FAST_RSA)
+/* Adds the rsa private key to the user ctx.
+Returns WOLFSSL_SUCCESS if no error, returns WOLFSSL_FAILURE otherwise.*/
+int wolfSSL_CTX_use_RSAPrivateKey(WOLFSSL_CTX* ctx, WOLFSSL_RSA* rsa)
+    {
+    int ret;
+    int derSize;
+    unsigned char maxDerBuf[4096];
+    unsigned char* key = NULL;
+
+    WOLFSSL_ENTER("wolfSSL_CTX_use_RSAPrivateKey()");
+
+    if (ctx == NULL || rsa == NULL) {
+        WOLFSSL_MSG("one or more inputs were NULL");
+        return BAD_FUNC_ARG;
+        }
+    key = maxDerBuf;
+    /* convert RSA struct to der encoded buffer and get the size */
+    if ((derSize = wolfSSL_i2d_RSAPrivateKey(rsa, &key)) <= 0) {
+        WOLFSSL_MSG("wolfSSL_i2d_RSAPrivateKey() failure");
+        return WOLFSSL_FAILURE;
+            }
+    ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx, (const unsigned char*)maxDerBuf,
+                                                    derSize, SSL_FILETYPE_ASN1);
+    if (ret != WOLFSSL_SUCCESS) {
+        WOLFSSL_MSG("wolfSSL_CTX_USE_PrivateKey_buffer() failure");
+        return WOLFSSL_FAILURE;
+        }
+    return ret;
+}
+#endif /* NO_RSA && !HAVE_FAST_RSA */
+
+
+/* Converts EVP_PKEY data from a bio buffer to a WOLFSSL_EVP_PKEY structure.
+Returns pointer to private EVP_PKEY struct upon success, NULL if there
+is a failure.*/
+WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_bio(WOLFSSL_BIO* bio,
+                                                         WOLFSSL_EVP_PKEY** out)
+{
+    unsigned char* mem = NULL;
+    int memSz = 0;
+    WOLFSSL_EVP_PKEY* key = NULL;
+    int i = 0, j = 0;
+    unsigned char* extraBioMem = NULL;
+    int extraBioMemSz = 0;
+    int derLength = 0;
+
+    WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey_bio()");
+
+    if (bio == NULL) {
+            return NULL;
+        }
+    (void)out;
+
+    memSz = wolfSSL_BIO_pending(bio);
+    if (memSz <= 0) {
+        WOLFSSL_MSG("wolfSSL_BIO_pending() failure");
+            return NULL;
+                }
+
+    mem = (unsigned char*)XMALLOC(memSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (mem == NULL) {
+        WOLFSSL_MSG("Malloc failure");
+        return NULL;
+            }
+
+    if (wolfSSL_BIO_read(bio, (unsigned char*)mem, memSz) == memSz) {
+        /* Determines key type and returns the new private EVP_PKEY object */
+        if ((key = wolfSSL_d2i_PrivateKey_EVP(NULL, &mem, (long)memSz)) == NULL) {
+            WOLFSSL_MSG("wolfSSL_d2i_PrivateKey_EVP() failure");
+            XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
+            return NULL;
+        }
+
+        /* Write extra data back into bio object if necessary. */
+        derLength = key->pkey_sz;
+        extraBioMemSz = (memSz - derLength);
+        if (extraBioMemSz > 0) {
+            extraBioMem = (unsigned char *)XMALLOC(extraBioMemSz, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+            if (extraBioMem == NULL) {
+                WOLFSSL_MSG("Malloc failure");
+                XFREE((unsigned char*)extraBioMem, bio->heap,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
+                return NULL;
+        }
+
+            for (i = derLength; i < memSz; i++) {
+                *(extraBioMem + j) = *(mem + i);
+                j++;
+            }
+
+            wolfSSL_BIO_write(bio, extraBioMem, extraBioMemSz);
+            if (wolfSSL_BIO_pending(bio) <= 0) {
+                WOLFSSL_MSG("Failed to write memory to bio");
+                XFREE((unsigned char*)extraBioMem, bio->heap,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
+                return NULL;
+            }
+            XFREE((unsigned char*)extraBioMem, bio->heap,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+        }
+
+        if (out != NULL && key != NULL) {
+            *out = key;
+        }
+    }
+    XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    return key;
+    }
+
+
+/* Converts a DER encoded private key to a WOLFSSL_EVP_PKEY structure.
+ * returns a pointer to a new WOLFSSL_EVP_PKEY structure on success and NULL
+ * on fail */
+WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_EVP(WOLFSSL_EVP_PKEY** out,
+                                                  unsigned char** in, long inSz)
+{
+    WOLFSSL_EVP_PKEY* pkey = NULL;
+    const unsigned char* mem;
+    long memSz = inSz;
+
+    WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey_EVP()");
+
+    if (in == NULL || *in == NULL || inSz < 0) {
+        WOLFSSL_MSG("Bad argument");
+        return NULL;
+    }
+    mem = *in;
+
+    #if !defined(NO_RSA)
+    {
+        RsaKey rsa;
+        word32 keyIdx = 0;
+
+        /* test if RSA key */
+        if (wc_InitRsaKey(&rsa, NULL) == 0 &&
+            wc_RsaPrivateKeyDecode(mem, &keyIdx, &rsa, (word32)memSz) == 0) {
+            wc_FreeRsaKey(&rsa);
+            pkey = wolfSSL_PKEY_new();
+            if (pkey != NULL) {
+                pkey->pkey_sz = keyIdx;
+                pkey->pkey.ptr = (char*)XMALLOC(memSz, NULL,
+                        DYNAMIC_TYPE_PRIVATE_KEY);
+                if (pkey->pkey.ptr == NULL) {
+                    wolfSSL_EVP_PKEY_free(pkey);
+        return NULL;
+    }
+                XMEMCPY(pkey->pkey.ptr, mem, keyIdx);
+                pkey->type = EVP_PKEY_RSA;
+                if (out != NULL) {
+                    *out = pkey;
+                }
+
+                pkey->ownRsa = 1;
+                pkey->rsa = wolfSSL_RSA_new();
+                if (pkey->rsa == NULL) {
+                    wolfSSL_EVP_PKEY_free(pkey);
+                    return NULL;
+                }
+
+                if (wolfSSL_RSA_LoadDer_ex(pkey->rsa,
+                            (const unsigned char*)pkey->pkey.ptr,
+                            pkey->pkey_sz, WOLFSSL_RSA_LOAD_PRIVATE) != 1) {
+                    wolfSSL_EVP_PKEY_free(pkey);
+                    return NULL;
+                }
+
+                return pkey;
+        }
+        }
+        wc_FreeRsaKey(&rsa);
+    }
+    #endif /* NO_RSA */
+
+            #ifdef HAVE_ECC
+    {
+        word32  keyIdx = 0;
+        ecc_key ecc;
+
+        /* test if ecc key */
+        if (wc_ecc_init(&ecc) == 0 &&
+            wc_EccPrivateKeyDecode(mem, &keyIdx, &ecc, (word32)memSz) == 0) {
+            wc_ecc_free(&ecc);
+            pkey = wolfSSL_PKEY_new();
+            if (pkey != NULL) {
+                pkey->pkey_sz = keyIdx;
+                pkey->pkey.ptr = (char*)XMALLOC(keyIdx, NULL,
+                        DYNAMIC_TYPE_PRIVATE_KEY);
+                if (pkey->pkey.ptr == NULL) {
+                    wolfSSL_EVP_PKEY_free(pkey);
+                    return NULL;
+    }
+                XMEMCPY(pkey->pkey.ptr, mem, keyIdx);
+                pkey->type = EVP_PKEY_EC;
+                if (out != NULL) {
+                    *out = pkey;
+                }
+                return pkey;
+            }
+        }
+        wc_ecc_free(&ecc);
+    }
+    #endif /* HAVE_ECC */
+    return pkey;
+}
+#endif /* OPENSSL_ALL || WOLFSSL_ASIO */
 
 
 /* stunnel compatibility functions*/
-#if defined(OPENSSL_EXTRA) && (defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX))
-void WOLFSSL_ERR_remove_thread_state(void* pid)
-{
+#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && (defined(HAVE_STUNNEL) || \
+                             defined(WOLFSSL_NGINX) || defined(HAVE_LIGHTY) || \
+                             defined(WOLFSSL_HAPROXY)))
+void wolfSSL_ERR_remove_thread_state(void* pid)
+        {
     (void) pid;
     return;
-}
-
+        }
+
+#ifndef NO_FILESYSTEM
 /***TBD ***/
-void wolfSSL_print_all_errors_fp(XFILE *fp)
+void wolfSSL_print_all_errors_fp(XFILE fp)
 {
     (void)fp;
-}
+        }
+#endif
 
 int wolfSSL_SESSION_set_ex_data(WOLFSSL_SESSION* session, int idx, void* data)
@@ -24233,7 +33112,11 @@
         return WOLFSSL_SUCCESS;
     }
-#endif
+    #else
+    (void)session;
+    (void)idx;
+    (void)data;
+    #endif
     return WOLFSSL_FAILURE;
-}
+    }
 
 
@@ -24246,12 +33129,12 @@
     (void)cb2;
     (void)cb3;
-    if(XSTRNCMP((const char*)data, "redirect index", 14) == 0) {
+    if (XSTRNCMP((const char*)data, "redirect index", 14) == 0) {
         return 0;
-    }
-    else if(XSTRNCMP((const char*)data, "addr index", 10) == 0) {
+            }
+    else if (XSTRNCMP((const char*)data, "addr index", 10) == 0) {
         return 1;
-    }
+        }
     return WOLFSSL_FAILURE;
-}
+    }
 
 
@@ -24262,9 +33145,12 @@
     if (session != NULL && idx < MAX_EX_DATA && idx >= 0)
         return session->ex_data[idx];
+#else
+    (void)session;
+    (void)idx;
 #endif
     return NULL;
-}
-
-
+    }
+
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_CRYPTO_set_mem_ex_functions(void *(*m) (size_t, const char *, int),
                                 void *(*r) (void *, size_t, const char *,
@@ -24275,10 +33161,17 @@
     (void) f;
     WOLFSSL_ENTER("wolfSSL_CRYPTO_set_mem_ex_functions");
-    WOLFSSL_STUB("wolfSSL_CRYPTO_set_mem_ex_functions");
+    WOLFSSL_STUB("CRYPTO_set_mem_ex_functions");
 
     return WOLFSSL_FAILURE;
-}
-
-
+    }
+#endif
+
+
+void wolfSSL_CRYPTO_cleanup_all_ex_data(void){
+    WOLFSSL_ENTER("CRYPTO_cleanup_all_ex_data");
+    }
+
+
+#ifndef NO_WOLFSSL_STUB
 WOLFSSL_DH *wolfSSL_DH_generate_parameters(int prime_len, int generator,
                            void (*callback) (int, int, void *), void *cb_arg)
@@ -24289,9 +33182,11 @@
     (void)cb_arg;
     WOLFSSL_ENTER("wolfSSL_DH_generate_parameters");
-    WOLFSSL_STUB("wolfSSL_DH_generate_parameters");
+    WOLFSSL_STUB("DH_generate_parameters");
 
     return NULL;
-}
-
+    }
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_DH_generate_parameters_ex(WOLFSSL_DH* dh, int prime_len, int generator,
                            void (*callback) (int, int, void *))
@@ -24302,67 +33197,50 @@
     (void)dh;
     WOLFSSL_ENTER("wolfSSL_DH_generate_parameters_ex");
-    WOLFSSL_STUB("wolfSSL_DH_generate_parameters_ex");
+    WOLFSSL_STUB("DH_generate_parameters_ex");
 
     return -1;
-}
-
+    }
+#endif
 
 void wolfSSL_ERR_load_crypto_strings(void)
 {
     WOLFSSL_ENTER("wolfSSL_ERR_load_crypto_strings");
-    WOLFSSL_ENTER("wolfSSL_ERR_load_crypto_strings");
+    /* Do nothing */
     return;
-}
-
-
-unsigned long wolfSSL_ERR_peek_last_error(void)
-{
-    WOLFSSL_ENTER("wolfSSL_ERR_peek_last_error");
-
-#ifdef WOLFSSL_NGINX
-    {
-        int ret;
-
-        if ((ret = wc_PeekErrorNode(-1, NULL, NULL, NULL)) < 0) {
-            WOLFSSL_MSG("Issue peeking at error node in queue");
-            return 0;
-        }
-        if (ret == -SSL_NO_PEM_HEADER)
-            return (ERR_LIB_PEM << 24) | PEM_R_NO_START_LINE;
-        return (unsigned long)ret;
-    }
-#else
-    return (unsigned long)(0 - NOT_COMPILED_IN);
-#endif
-}
-
-
+    }
+
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_FIPS_mode(void)
 {
     WOLFSSL_ENTER("wolfSSL_FIPS_mode");
-    WOLFSSL_STUB("wolfSSL_FIPS_mode");
+    WOLFSSL_STUB("FIPS_mode");
 
     return WOLFSSL_FAILURE;
-}
-
+    }
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_FIPS_mode_set(int r)
 {
     (void)r;
     WOLFSSL_ENTER("wolfSSL_FIPS_mode_set");
-    WOLFSSL_STUB("wolfSSL_FIPS_mode_set");
+    WOLFSSL_STUB("FIPS_mode_set");
 
     return WOLFSSL_FAILURE;
 }
-
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_RAND_set_rand_method(const void *meth)
 {
     (void) meth;
     WOLFSSL_ENTER("wolfSSL_RAND_set_rand_method");
-    WOLFSSL_STUB("wolfSSL_RAND_set_rand_method");
-
-    return WOLFSSL_FAILURE;
-}
-
+    WOLFSSL_STUB("RAND_set_rand_method");
+
+    /* if implemented RAND_bytes and RAND_pseudo_bytes need updated
+     * those two functions will call the respective functions from meth */
+    return SSL_FAILURE;
+        }
+#endif
 
 int wolfSSL_CIPHER_get_bits(const WOLFSSL_CIPHER *c, int *alg_bits)
@@ -24377,6 +33255,5 @@
     }
     return ret;
-}
-
+        }
 
 int wolfSSL_sk_X509_NAME_num(const WOLF_STACK_OF(WOLFSSL_X509_NAME) *s)
@@ -24389,5 +33266,4 @@
 }
 
-
 int wolfSSL_sk_X509_num(const WOLF_STACK_OF(WOLFSSL_X509) *s)
 {
@@ -24397,6 +33273,5 @@
         return -1;
     return (int)s->num;
-}
-
+    }
 
 int wolfSSL_X509_NAME_print_ex(WOLFSSL_BIO* bio, WOLFSSL_X509_NAME* name,
@@ -24420,18 +33295,19 @@
         return WOLFSSL_FAILURE;
 
-    return WOLFSSL_SUCCESS;
-}
-
-
+        return WOLFSSL_SUCCESS;
+    }
+
+#ifndef NO_WOLFSSL_STUB
 WOLFSSL_ASN1_BIT_STRING* wolfSSL_X509_get0_pubkey_bitstr(const WOLFSSL_X509* x)
 {
     (void)x;
     WOLFSSL_ENTER("wolfSSL_X509_get0_pubkey_bitstr");
-    WOLFSSL_STUB("wolfSSL_X509_get0_pubkey_bitstr");
-
-    return NULL;
-}
-
-
+    WOLFSSL_STUB("X509_get0_pubkey_bitstr");
+
+        return NULL;
+    }
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_CTX_add_session(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* session)
 {
@@ -24439,48 +33315,13 @@
     (void)session;
     WOLFSSL_ENTER("wolfSSL_CTX_add_session");
-    WOLFSSL_STUB("wolfSSL_CTX_add_session");
+    WOLFSSL_STUB("SSL_CTX_add_session");
 
     return WOLFSSL_SUCCESS;
 }
-
-
-int wolfSSL_get_state(const WOLFSSL* ssl)
-{
-    (void)ssl;
-    WOLFSSL_ENTER("wolfSSL_get_state");
-    WOLFSSL_STUB("wolfSSL_get_state");
-
-    return WOLFSSL_FAILURE;
-}
-
-
-void* wolfSSL_sk_X509_NAME_value(const WOLF_STACK_OF(WOLFSSL_X509_NAME)* sk, int i)
-{
-    WOLFSSL_ENTER("wolfSSL_sk_X509_NAME_value");
-
-    for (; sk != NULL && i > 0; i--)
-        sk = sk->next;
-
-    if (i != 0 || sk == NULL)
-        return NULL;
-    return sk->data.name;
-}
-
-
-void* wolfSSL_sk_X509_value(WOLF_STACK_OF(WOLFSSL_X509)* sk, int i)
-{
-    WOLFSSL_ENTER("wolfSSL_sk_X509_value");
-
-    for (; sk != NULL && i > 0; i--)
-        sk = sk->next;
-
-    if (i != 0 || sk == NULL)
-        return NULL;
-    return sk->data.x509;
-}
+#endif
 
 
 int wolfSSL_version(WOLFSSL* ssl)
-{
+    {
     WOLFSSL_ENTER("wolfSSL_version");
     if (ssl->version.major == SSLv3_MAJOR) {
@@ -24510,20 +33351,4 @@
 
 
-WOLF_STACK_OF(WOLFSSL_X509)* wolfSSL_get_peer_cert_chain(const WOLFSSL* ssl)
-{
-    (void)ssl;
-    WOLFSSL_ENTER("wolfSSL_get_peer_cert_chain");
-    WOLFSSL_STUB("wolfSSL_get_peer_cert_chain");
-
-    return NULL;
-}
-
-
-WOLFSSL_CTX* wolfSSL_get_SSL_CTX(WOLFSSL* ssl)
-{
-    WOLFSSL_ENTER("wolfSSL_get_SSL_CTX");
-    return ssl->ctx;
-}
-
 int wolfSSL_X509_NAME_get_sz(WOLFSSL_X509_NAME* name)
 {
@@ -24532,6 +33357,5 @@
         return -1;
     return name->sz;
-}
-
+    }
 
 #ifdef HAVE_SNI
@@ -24541,5 +33365,5 @@
     WOLFSSL_ENTER("wolfSSL_set_tlsext_host_name");
     ret = wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME,
-            host_name, XSTRLEN(host_name));
+            host_name, (word16)XSTRLEN(host_name));
     WOLFSSL_LEAVE("wolfSSL_set_tlsext_host_name", ret);
     return ret;
@@ -24552,5 +33376,5 @@
     void * serverName = NULL;
     if (ssl == NULL)
-        return NULL;
+    return NULL;
     TLSX_SNI_GetRequest(ssl->extensions, type, &serverName);
     return (const char *)serverName;
@@ -24585,5 +33409,5 @@
 int wolfSSL_CTX_set_tlsext_servername_callback(WOLFSSL_CTX* ctx,
                                                CallbackSniRecv cb)
-{
+    {
     WOLFSSL_ENTER("wolfSSL_CTX_set_tlsext_servername_callback");
     if (ctx) {
@@ -24601,53 +33425,79 @@
 }
 
-
-long wolfSSL_CTX_clear_options(WOLFSSL_CTX* ctx, long opt)
-{
-    WOLFSSL_ENTER("SSL_CTX_clear_options");
-    WOLFSSL_STUB("SSL_CTX_clear_options");
-    (void)ctx;
-    (void)opt;
-    return opt;
-}
-
+void wolfSSL_ERR_load_BIO_strings(void) {
+    WOLFSSL_ENTER("ERR_load_BIO_strings");
+    /* do nothing */
+}
+
+#ifndef NO_WOLFSSL_STUB
 void wolfSSL_THREADID_set_callback(void(*threadid_func)(void*))
-{
+    {
     WOLFSSL_ENTER("wolfSSL_THREADID_set_callback");
-    WOLFSSL_STUB("wolfSSL_THREADID_set_callback");
+    WOLFSSL_STUB("CRYPTO_THREADID_set_callback");
     (void)threadid_func;
     return;
-}
-
+    }
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 void wolfSSL_THREADID_set_numeric(void* id, unsigned long val)
 {
     WOLFSSL_ENTER("wolfSSL_THREADID_set_numeric");
-    WOLFSSL_STUB("wolfSSL_THREADID_set_numeric");
+    WOLFSSL_STUB("CRYPTO_THREADID_set_numeric");
     (void)id;
     (void)val;
     return;
 }
-
-
+#endif
+
+
+#ifndef NO_WOLFSSL_STUB
 WOLF_STACK_OF(WOLFSSL_X509)* wolfSSL_X509_STORE_get1_certs(WOLFSSL_X509_STORE_CTX* ctx,
                                                 WOLFSSL_X509_NAME* name)
 {
     WOLFSSL_ENTER("wolfSSL_X509_STORE_get1_certs");
-    WOLFSSL_STUB("wolfSSL_X509_STORE_get1_certs");
+    WOLFSSL_STUB("X509_STORE_get1_certs");
     (void)ctx;
     (void)name;
     return NULL;
 }
-
-void wolfSSL_sk_X509_pop_free(WOLF_STACK_OF(WOLFSSL_X509)* sk, void f (WOLFSSL_X509*)){
-    (void) sk;
-    (void) f;
-    WOLFSSL_ENTER("wolfSSL_sk_X509_pop_free");
-    WOLFSSL_STUB("wolfSSL_sk_X509_pop_free");
-}
-
-#endif /* OPENSSL_EXTRA and HAVE_STUNNEL */
-#if defined(OPENSSL_EXTRA) && (defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX))\
-    || defined(WOLFSSL_HAPROXY)
-
+#endif
+
+#endif /* OPENSSL_ALL || (OPENSSL_EXTRA && (HAVE_STUNNEL || WOLFSSL_NGINX || HAVE_LIGHTY)) */
+
+
+#if defined(OPENSSL_EXTRA)
+unsigned long wolfSSL_ERR_peek_last_error(void)
+{
+    WOLFSSL_ENTER("wolfSSL_ERR_peek_last_error");
+
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_NGINX)
+{
+        int ret;
+
+        if ((ret = wc_PeekErrorNode(-1, NULL, NULL, NULL)) < 0) {
+            WOLFSSL_MSG("Issue peeking at error node in queue");
+            return 0;
+        }
+        if (ret == -ASN_NO_PEM_HEADER)
+            return (ERR_LIB_PEM << 24) | PEM_R_NO_START_LINE;
+        return (unsigned long)ret;
+    }
+#else
+    return (unsigned long)(0 - NOT_COMPILED_IN);
+#endif
+}
+
+#endif /* OPENSSL_EXTRA */
+
+WOLFSSL_CTX* wolfSSL_get_SSL_CTX(WOLFSSL* ssl)
+{
+    WOLFSSL_ENTER("wolfSSL_get_SSL_CTX");
+    return ssl->ctx;
+}
+
+#if defined(OPENSSL_ALL) || \
+    (defined(OPENSSL_EXTRA) && (defined(HAVE_STUNNEL) || \
+     defined(WOLFSSL_NGINX)) || defined(WOLFSSL_HAPROXY))
 
 const byte* wolfSSL_SESSION_get_id(WOLFSSL_SESSION* sess, unsigned int* idLen)
@@ -24663,6 +33513,7 @@
 #endif
 
-#if (defined(OPENSSL_EXTRA) && defined(HAVE_STUNNEL)) \
+#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && defined(HAVE_STUNNEL)) \
     || defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX)
+
 int wolfSSL_CTX_get_verify_mode(WOLFSSL_CTX* ctx)
 {
@@ -24686,5 +33537,5 @@
     WOLFSSL_LEAVE("wolfSSL_CTX_get_verify_mode", mode);
     return mode;
-}
+    }
 #endif
 
@@ -24736,5 +33587,5 @@
         else
             rng = &globalRNG;
-    }
+}
 
     if (rng) {
@@ -24754,5 +33605,5 @@
 
         wc_curve25519_free(&key);
-    }
+}
 
     if (initTmpRng)
@@ -24806,5 +33657,5 @@
         wc_curve25519_free(&privkey);
         return ret;
-    }
+}
 
     /* import public key */
@@ -24834,5 +33685,5 @@
     return ret;
 #endif /* WOLFSSL_KEY_GEN */
-}
+    }
 #endif /* OPENSSL_EXTRA && HAVE_CURVE25519 */
 
@@ -24911,5 +33762,5 @@
     return ret;
 #endif /* WOLFSSL_KEY_GEN */
-}
+    }
 
 /* return 1 if success, 0 if error
@@ -24940,5 +33791,5 @@
         WOLFSSL_MSG("Bad arguments");
         return WOLFSSL_FAILURE;
-    }
+}
 
     /* import key */
@@ -24964,5 +33815,5 @@
     return ret;
 #endif /* WOLFSSL_KEY_GEN */
-}
+    }
 
 /* return 1 if success, 0 if error
@@ -24982,5 +33833,5 @@
     (void) sig;
     (void) sigSz;
-    return WOLFSSL_FAILURE;
+        return WOLFSSL_FAILURE;
 #else /* WOLFSSL_KEY_GEN */
     ed25519_key key;
@@ -25057,5 +33908,5 @@
     return wolfAsync_EventQueuePoll(&ctx->event_queue, NULL,
                                         events, maxEvents, flags, eventCount);
-}
+    }
 
 int wolfSSL_AsyncPoll(WOLFSSL* ssl, WOLF_EVENT_FLAG flags)
@@ -25094,9 +33945,9 @@
     if (flags != NULL) {
         *flags = 0;
-    }
-
-#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \
-    defined(WOLFSSL_MYSQL_COMPATIBLE)
-    {
+}
+
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \
+    defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_MYSQL_COMPATIBLE)
+{
         int ret = 0;
 
@@ -25104,9 +33955,9 @@
             if ((ret = wc_PeekErrorNode(-1, file, NULL, line)) < 0) {
                 WOLFSSL_MSG("Issue peeking at error node in queue");
-                return 0;
-            }
+        return 0;
+    }
             ret = -ret;
 
-            if (ret == SSL_NO_PEM_HEADER)
+            if (ret == ASN_NO_PEM_HEADER)
                 return (ERR_LIB_PEM << 24) | PEM_R_NO_START_LINE;
             if (ret != WANT_READ && ret != WANT_WRITE &&
@@ -25116,5 +33967,5 @@
 
             wc_RemoveErrorNode(-1);
-        }
+}
 
         return (unsigned long)ret;
@@ -25126,6 +33977,7 @@
 #endif
 
-#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
-
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+
+#ifndef NO_WOLFSSL_STUB
 WOLF_STACK_OF(WOLFSSL_CIPHER) *wolfSSL_get_ciphers_compat(const WOLFSSL *ssl)
 {
@@ -25134,11 +33986,17 @@
     return NULL;
 }
-
+#endif
+
+#ifndef NO_WOLFSSL_STUB
 void wolfSSL_OPENSSL_config(char *config_name)
 {
-    WOLFSSL_STUB("wolfSSL_OPENSSL_config");
     (void)config_name;
-}
-
+    WOLFSSL_STUB("OPENSSL_config");
+}
+#endif
+#endif
+
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) \
+    || defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY)
 int wolfSSL_X509_get_ex_new_index(int idx, void *arg, void *a, void *b, void *c)
 {
@@ -25156,10 +34014,10 @@
 
 void *wolfSSL_X509_get_ex_data(X509 *x509, int idx)
-{
+    {
     WOLFSSL_ENTER("wolfSSL_X509_get_ex_data");
     #ifdef HAVE_EX_DATA
     if (x509 != NULL && idx < MAX_EX_DATA && idx >= 0) {
         return x509->ex_data[idx];
-    }
+        }
     #else
     (void)x509;
@@ -25177,9 +34035,9 @@
         return WOLFSSL_SUCCESS;
     }
-    #else
+#else
     (void)x509;
     (void)idx;
     (void)data;
-    #endif
+#endif
     return WOLFSSL_FAILURE;
 }
@@ -25190,8 +34048,14 @@
 
     if (name == NULL || type == NULL)
-        return WOLFSSL_FAILURE;
-
+    return WOLFSSL_FAILURE;
+
+#ifndef NO_FILESYSTEM
     return wolfSSL_EVP_Digest((unsigned char*)name->fullName.fullName,
                               name->fullName.fullNameLen, md, len, type, NULL);
+#else
+    (void)md;
+    (void)len;
+    return NOT_COMPILED_IN;
+#endif
 }
 
@@ -25234,5 +34098,5 @@
         /* Don't remove session just timeout session. */
         s->timeout = 0;
-    }
+}
 
 #ifdef HAVE_EXT_CACHE
@@ -25247,9 +34111,11 @@
 {
     WOLFSSL_ENTER("wolfSSL_SSL_get_rbio");
-    (void)s;
     /* Nginx sets the buffer size if the read BIO is different to write BIO.
      * The setting buffer size doesn't do anything so return NULL for both.
      */
-    return NULL;
+    if (s == NULL)
+        return NULL;
+
+    return s->biord;
 }
 BIO *wolfSSL_SSL_get_wbio(const WOLFSSL *s)
@@ -25260,5 +34126,8 @@
      * The setting buffer size doesn't do anything so return NULL for both.
      */
-    return NULL;
+    if (s == NULL)
+        return NULL;
+
+    return s->biowr;
 }
 
@@ -25270,8 +34139,20 @@
         return WOLFSSL_FAILURE;
 
-    if (s->options.side == WOLFSSL_CLIENT_END)
+    if (s->options.side == WOLFSSL_CLIENT_END) {
+    #ifndef NO_WOLFSSL_CLIENT
         return wolfSSL_connect(s);
+    #else
+        WOLFSSL_MSG("Client not compiled in");
+            return WOLFSSL_FAILURE;
+    #endif
+    }
+
+#ifndef NO_WOLFSSL_SERVER
     return wolfSSL_accept(s);
-}
+#else
+    WOLFSSL_MSG("Server not compiled in");
+            return WOLFSSL_FAILURE;
+#endif
+    }
 
 int wolfSSL_SSL_in_init(WOLFSSL *s)
@@ -25296,6 +34177,6 @@
 
     if (ssl == NULL) {
-        return NULL;
-    }
+    return NULL;
+}
 
     session = wolfSSL_get_session((WOLFSSL*)ssl);
@@ -25321,4 +34202,9 @@
     (void)flags;
     (void)peername;
+
+    if (flags == WOLFSSL_NO_WILDCARDS) {
+        WOLFSSL_MSG("X509_CHECK_FLAG_NO_WILDCARDS not yet implemented");
+        return WOLFSSL_FAILURE;
+    }
 
     InitDecodedCert(&dCert, x->derCert->buffer, x->derCert->length, NULL);
@@ -25380,5 +34266,5 @@
         wolfSSL_BIO_write(bp, "00", 2);
         return 2;
-    }
+        }
 
     /* Don't do negative - just write out every byte. */
@@ -25393,5 +34279,5 @@
 
 
-#ifdef HAVE_SESSION_TICKET
+#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER)
 /* Expected return values from implementations of OpenSSL ticket key callback.
  */
@@ -25428,5 +34314,5 @@
                                   int encTicketLen, int* encLen, void* ctx)
 {
-    byte                    digest[MAX_DIGEST_SIZE];
+    byte                    digest[WC_MAX_DIGEST_SIZE];
     WOLFSSL_EVP_CIPHER_CTX  evpCtx;
     WOLFSSL_HMAC_CTX        hmacCtx;
@@ -25448,5 +34334,5 @@
 
     if (enc)
-    {
+{
         /* Encrypt in place. */
         if (!wolfSSL_EVP_CipherUpdate(&evpCtx, encTicket, &len,
@@ -25461,12 +34347,21 @@
 
         /* HMAC the encrypted data into the parameter 'mac'. */
-        wolfSSL_HMAC_Update(&hmacCtx, encTicket, encTicketLen);
-        wolfSSL_HMAC_Final(&hmacCtx, mac, &mdSz);
-    }
+        if (!wolfSSL_HMAC_Update(&hmacCtx, encTicket, encTicketLen))
+            goto end;
+#ifdef WOLFSSL_SHA512
+        /* Check for SHA512, which would overrun the mac buffer */
+        if (hmacCtx.hmac.macType == WC_SHA512)
+            goto end;
+#endif
+        if (!wolfSSL_HMAC_Final(&hmacCtx, mac, &mdSz))
+            goto end;
+}
     else
     {
         /* HMAC the encrypted data and compare it to the passed in data. */
-        wolfSSL_HMAC_Update(&hmacCtx, encTicket, encTicketLen);
-        wolfSSL_HMAC_Final(&hmacCtx, digest, &mdSz);
+        if (!wolfSSL_HMAC_Update(&hmacCtx, encTicket, encTicketLen))
+            goto end;
+        if (!wolfSSL_HMAC_Final(&hmacCtx, digest, &mdSz))
+            goto end;
         if (XMEMCMP(mac, digest, mdSz) != 0)
             goto end;
@@ -25510,4 +34405,8 @@
 #endif /* HAVE_SESSION_TICKET */
 
+#endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY ||
+    OPENSSL_EXTRA || HAVE_LIGHTY */
+
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
 #ifdef HAVE_OCSP
 /* Not an OpenSSL API. */
@@ -25533,5 +34432,9 @@
     return WOLFSSL_SUCCESS;
 }
-
+#endif /* OCSP */
+#endif /* OPENSSL_ALL / WOLFSSL_NGINX  / WOLFSSL_HAPROXY */
+
+#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \
+    defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)
 int wolfSSL_CTX_get_extra_chain_certs(WOLFSSL_CTX* ctx, WOLF_STACK_OF(X509)** chain)
 {
@@ -25548,5 +34451,5 @@
         *chain = ctx->x509Chain;
         return WOLFSSL_SUCCESS;
-    }
+}
 
     /* If there are no chains then success! */
@@ -25554,5 +34457,5 @@
     if (ctx->certChain == NULL || ctx->certChain->length == 0) {
         return WOLFSSL_SUCCESS;
-    }
+}
 
     /* Create a new stack of WOLFSSL_X509 object from chain buffer. */
@@ -25576,5 +34479,5 @@
             ctx->x509Chain = *chain;
             return WOLFSSL_FAILURE;
-        }
+}
         idx += length;
 
@@ -25587,5 +34490,5 @@
             (*chain)->num++;
             last->next = node;
-        }
+}
 
         last = node;
@@ -25603,4 +34506,6 @@
         return WOLFSSL_FAILURE;
 
+#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \
+ || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
     /* Ensure stapling is on for callback to be used. */
     wolfSSL_CTX_EnableOCSPStapling(ctx);
@@ -25610,4 +34515,8 @@
 
     ctx->cm->ocsp_stapling->statusCb = cb;
+#else
+    (void)cb;
+#endif
+
     return WOLFSSL_SUCCESS;
 }
@@ -25632,6 +34541,6 @@
                 *issuer = x;
                 return WOLFSSL_SUCCESS;
-            }
-        }
+    }
+    }
     }
 
@@ -25654,5 +34563,5 @@
         ca = GetCA(ctx->store->cm, cert->issuerHash);
     #endif /* NO SKID */
-    }
+}
     FreeDecodedCert(cert);
 #ifdef WOLFSSL_SMALL_STACK
@@ -25661,5 +34570,5 @@
 
     if (ca == NULL)
-        return WOLFSSL_FAILURE;
+    return WOLFSSL_FAILURE;
 
     *issuer = (WOLFSSL_X509 *)XMALLOC(sizeof(WOLFSSL_X509), 0,
@@ -25670,10 +34579,21 @@
     /* Create an empty certificate as CA doesn't have a certificate. */
     XMEMSET(*issuer, 0, sizeof(WOLFSSL_X509));
-    /* TODO: store the full certificate and dup when required. */
+    (*issuer)->dynamicMemory = 1;
+#ifdef WOLFSSL_SIGNER_DER_CERT
+    if (AllocDer(&(*issuer)->derCert, ca->derCert->length, ca->derCert->type,
+                                                                   NULL) == 0) {
+        XMEMCPY((*issuer)->derCert->buffer, ca->derCert->buffer,
+                                                           ca->derCert->length);
+    }
+    else {
+        XFREE(*issuer, 0, DYNAMIC_TYPE_OPENSSL);
+        return WOLFSSL_FAILURE;
+    }
+#endif
 
     /* Result is ignored when passed to wolfSSL_OCSP_cert_to_id(). */
 
     return WOLFSSL_SUCCESS;
-}
+    }
 
 void wolfSSL_X509_email_free(WOLF_STACK_OF(WOLFSSL_STRING) *sk)
@@ -25687,19 +34607,25 @@
         XFREE(curr, NULL, DYNAMIC_TYPE_OPENSSL);
     }
-}
+    }
 
 WOLF_STACK_OF(WOLFSSL_STRING) *wolfSSL_X509_get1_ocsp(WOLFSSL_X509 *x)
 {
-    WOLFSSL_STACK *list = NULL;
+    WOLFSSL_STACK* list = NULL;
+    char*          url;
 
     if (x->authInfoSz == 0)
         return NULL;
 
-    list = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL,
-                                   DYNAMIC_TYPE_OPENSSL);
+    list = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK) + x->authInfoSz + 1,
+                                   NULL, DYNAMIC_TYPE_OPENSSL);
     if (list == NULL)
         return NULL;
 
-    list->data.string = (char*)x->authInfo;
+    url = (char*)list;
+    url += sizeof(WOLFSSL_STACK);
+    XMEMCPY(url, x->authInfo, x->authInfoSz);
+    url[x->authInfoSz] = '\0';
+
+    list->data.string = url;
     list->next = NULL;
 
@@ -25726,5 +34652,5 @@
                         issuer->subjKeyIdSz) != 0) {
             return X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
-        }
+    }
     }
 
@@ -25735,5 +34661,5 @@
 {
     return wolfSSL_X509_d2i(NULL, x->derCert->buffer, x->derCert->length);
-}
+    }
 
 char* wolfSSL_sk_WOLFSSL_STRING_value(WOLF_STACK_OF(WOLFSSL_STRING)* strings,
@@ -25746,6 +34672,7 @@
     return strings->data.string;
 }
-#endif /* HAVE_OCSP */
-
+#endif /* WOLFSSL_NGINX || WOLFSSL_HAPROXY || OPENSSL_EXTRA || OPENSSL_ALL */
+
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
 #ifdef HAVE_ALPN
 void wolfSSL_get0_alpn_selected(const WOLFSSL *ssl, const unsigned char **data,
@@ -25804,5 +34731,5 @@
         ctx->alpnSelectArg = arg;
     }
-}
+    }
 
 void wolfSSL_CTX_set_next_protos_advertised_cb(WOLFSSL_CTX *s,
@@ -25860,5 +34787,5 @@
         len = idx - 1 - start;
         if (len > MAX_CURVE_NAME_SZ - 1)
-            return WOLFSSL_FAILURE;
+        return WOLFSSL_FAILURE;
 
         XMEMCPY(name, names + start, len);
@@ -25869,13 +34796,13 @@
                                       (XSTRNCMP(name, "P-256", len) == 0)) {
             curve = WOLFSSL_ECC_SECP256R1;
-        }
+    }
         else if ((XSTRNCMP(name, "secp384r1", len) == 0) ||
                                           (XSTRNCMP(name, "P-384", len) == 0)) {
             curve = WOLFSSL_ECC_SECP384R1;
-        }
+    }
         else if ((XSTRNCMP(name, "secp521r1", len) == 0) ||
                                           (XSTRNCMP(name, "P-521", len) == 0)) {
             curve = WOLFSSL_ECC_SECP521R1;
-        }
+    }
         else if (XSTRNCMP(name, "X25519", len) == 0)
             curve = WOLFSSL_ECC_X25519;
@@ -25886,11 +34813,12 @@
         ctx->disabledCurves &= ~(1 << curve);
         start = idx + 1;
-    }
-
-    return WOLFSSL_SUCCESS;
-}
+}
+
+        return WOLFSSL_SUCCESS;
+    }
 #endif
 
 #ifdef OPENSSL_EXTRA
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_CTX_set_msg_callback(WOLFSSL_CTX *ctx, SSL_Msg_Cb cb)
 {
@@ -25900,11 +34828,30 @@
     return WOLFSSL_FAILURE;
 }
+#endif
+
+
+/* Sets a callback for when sending and receiving protocol messages.
+ *
+ * ssl WOLFSSL structure to set callback in
+ * cb  callback to use
+ *
+ * return SSL_SUCCESS on success and SSL_FAILURE with error case
+ */
 int wolfSSL_set_msg_callback(WOLFSSL *ssl, SSL_Msg_Cb cb)
 {
-    WOLFSSL_STUB("SSL_set_msg_callback");
-    (void)ssl;
-    (void)cb;
-    return WOLFSSL_FAILURE;
-}
+    WOLFSSL_ENTER("wolfSSL_set_msg_callback");
+
+    if (ssl == NULL) {
+        return SSL_FAILURE;
+    }
+
+    if (cb != NULL) {
+        ssl->toInfoOn = 1;
+}
+
+    ssl->protoMsgCb = cb;
+    return SSL_SUCCESS;
+}
+#ifndef NO_WOLFSSL_STUB
 int wolfSSL_CTX_set_msg_callback_arg(WOLFSSL_CTX *ctx, void* arg)
 {
@@ -25913,14 +34860,1172 @@
     (void)arg;
     return WOLFSSL_FAILURE;
-}
+    }
+#endif
+
 int wolfSSL_set_msg_callback_arg(WOLFSSL *ssl, void* arg)
 {
-    WOLFSSL_STUB("SSL_set_msg_callback_arg");
-    (void)ssl;
-    (void)arg;
+    WOLFSSL_ENTER("wolfSSL_set_msg_callback_arg");
+    if (ssl == NULL)
+        return WOLFSSL_FAILURE;
+
+    ssl->protoMsgCtx = arg;
+    return WOLFSSL_SUCCESS;
+}
+
+void *wolfSSL_OPENSSL_memdup(const void *data, size_t siz, const char* file, int line)
+{
+    void *ret;
+    (void)file;
+    (void)line;
+
+    if (data == NULL || siz >= INT_MAX)
+        return NULL;
+
+    ret = OPENSSL_malloc(siz);
+    if (ret == NULL) {
+        return NULL;
+    }
+    return XMEMCPY(ret, data, siz);
+    }
+
+int wolfSSL_CTX_set_alpn_protos(WOLFSSL_CTX *ctx, const unsigned char *p,
+                            unsigned int p_len)
+    {
+    WOLFSSL_ENTER("wolfSSL_CTX_set_alpn_protos");
+    if(ctx == NULL)
+        return BAD_FUNC_ARG;
+    if((void *)ctx->alpn_cli_protos != NULL)
+        wolfSSL_OPENSSL_free((void *)ctx->alpn_cli_protos);
+    ctx->alpn_cli_protos =
+        (const unsigned char *)wolfSSL_OPENSSL_memdup(p, p_len, NULL, 0);
+    if (ctx->alpn_cli_protos == NULL) {
+        return SSL_FAILURE;
+            }
+    ctx->alpn_cli_protos_len = p_len;
+
+    return SSL_SUCCESS;
+        }
+
+#endif
+
+#endif /* WOLFCRYPT_ONLY */
+
+#if defined(OPENSSL_EXTRA)
+int wolfSSL_X509_check_ca(WOLFSSL_X509 *x509)
+{
+    WOLFSSL_ENTER("X509_check_ca");
+
+    if (x509 == NULL)
+        return WOLFSSL_FAILURE;
+    if (x509->isCa)
+        return 1;
+    if (x509->extKeyUsageCrit)
+        return 4;
+
+    return 0;
+}
+
+
+const char *wolfSSL_ASN1_tag2str(int tag)
+{
+    static const char *const tag_label[31] = {
+        "EOC", "BOOLEAN", "INTEGER", "BIT STRING", "OCTET STRING", "NULL",
+        "OBJECT", "OBJECT DESCRIPTOR", "EXTERNAL", "REAL", "ENUMERATED",
+        "<ASN1 11>", "UTF8STRING", "<ASN1 13>", "<ASN1 14>", "<ASN1 15>",
+        "SEQUENCE", "SET", "NUMERICSTRING", "PRINTABLESTRING", "T61STRING",
+        "VIDEOTEXTSTRING", "IA5STRING", "UTCTIME", "GENERALIZEDTIME",
+        "GRAPHICSTRING", "VISIBLESTRING", "GENERALSTRING", "UNIVERSALSTRING",
+        "<ASN1 29>", "BMPSTRING"
+    };
+
+    if ((tag == V_ASN1_NEG_INTEGER) || (tag == V_ASN1_NEG_ENUMERATED))
+        tag &= ~0x100;
+    if (tag < 0 || tag > 30)
+        return "(unknown)";
+    return tag_label[tag];
+}
+
+static int check_esc_char(char c, char *esc)
+    {
+    char *ptr = NULL;
+
+    ptr = esc;
+    while(*ptr != 0){
+        if (c == *ptr)
+            return 1;
+        ptr++;
+    }
+    return 0;
+}
+
+int wolfSSL_ASN1_STRING_print_ex(WOLFSSL_BIO *out, WOLFSSL_ASN1_STRING *str,
+                                 unsigned long flags)
+{
+    size_t str_len = 0, type_len = 0;
+    unsigned char *typebuf = NULL;
+    const char *hash="#";
+
+    WOLFSSL_ENTER("wolfSSL_ASN1_STRING_PRINT_ex");
+    if (out == NULL || str == NULL)
+        return WOLFSSL_FAILURE;
+
+    /* add ASN1 type tag */
+    if (flags & ASN1_STRFLGS_SHOW_TYPE){
+        const char *tag = wolfSSL_ASN1_tag2str(str->type);
+        /* colon len + tag len + null*/
+        type_len = XSTRLEN(tag) + 2;
+        typebuf = (unsigned char *)XMALLOC(type_len , NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (typebuf == NULL){
+            WOLFSSL_MSG("memory alloc failed.");
+            return WOLFSSL_FAILURE;
+        }
+        XMEMSET(typebuf, 0, type_len);
+        XSNPRINTF((char*)typebuf, (size_t)type_len , "%s:", tag);
+        type_len--;
+}
+
+    /* dump hex */
+    if (flags & ASN1_STRFLGS_DUMP_ALL){
+        static const char hex_char[] = { '0', '1', '2', '3', '4', '5', '6',
+                                         '7','8', '9', 'A', 'B', 'C', 'D',
+                                         'E', 'F' };
+        char hex_tmp[4];
+        char *str_ptr, *str_end;
+
+        if (type_len > 0){
+            if (wolfSSL_BIO_write(out, typebuf, (int)type_len) != (int)type_len){
+                XFREE(typebuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                return WOLFSSL_FAILURE;
+            }
+            str_len += type_len;
+        }
+        if (wolfSSL_BIO_write(out, hash, 1) != 1){
+            goto err_exit;
+        }
+        str_len++;
+        if (flags & ASN1_STRFLGS_DUMP_DER){
+            hex_tmp[0] = hex_char[str->type >> 4];
+            hex_tmp[1] = hex_char[str->type & 0xf];
+            hex_tmp[2] = hex_char[str->length >> 4];
+            hex_tmp[3] = hex_char[str->length & 0xf];
+            if (wolfSSL_BIO_write(out, hex_tmp, 4) != 4){
+                goto err_exit;
+            }
+            str_len += 4;
+            XMEMSET(hex_tmp, 0, 4);
+        }
+
+        str_ptr = str->data;
+        str_end = str->data + str->length;
+        while (str_ptr < str_end){
+            hex_tmp[0] = hex_char[*str_ptr >> 4];
+            hex_tmp[1] = hex_char[*str_ptr & 0xf];
+            if (wolfSSL_BIO_write(out, hex_tmp, 2) != 2){
+                goto err_exit;
+}
+            str_ptr++;
+            str_len += 2;
+        }
+        if (type_len > 0)
+            XFREE(typebuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+        return (int)str_len;
+    }
+
+    if (type_len > 0){
+        if (wolfSSL_BIO_write(out, typebuf, (int)type_len) != (int)type_len){
+            XFREE(typebuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            return WOLFSSL_FAILURE;
+        }
+        str_len += type_len;
+    }
+
+    if (flags & ASN1_STRFLGS_ESC_2253){
+        char esc_ch[] = "+;<>\\";
+        char* esc_ptr = NULL;
+
+        esc_ptr = str->data;
+        while (*esc_ptr != 0){
+            if (check_esc_char(*esc_ptr, esc_ch)){
+                if (wolfSSL_BIO_write(out,"\\", 1) != 1)
+                    goto err_exit;
+                str_len++;
+            }
+            if (wolfSSL_BIO_write(out, esc_ptr, 1) != 1)
+                goto err_exit;
+            str_len++;
+            esc_ptr++;
+        }
+        if (type_len > 0)
+            XFREE(typebuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return (int)str_len;
+}
+
+    if (wolfSSL_BIO_write(out, str->data, str->length) != str->length){
+        goto err_exit;
+    }
+    str_len += str->length;
+    if (type_len > 0)
+        XFREE(typebuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+    return (int)str_len;
+
+err_exit:
+    if (type_len > 0)
+        XFREE(typebuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
     return WOLFSSL_FAILURE;
-}
-#endif
-
-
-#endif /* WOLFCRYPT_ONLY */
+    }
+
+#ifndef NO_ASN_TIME
+int wolfSSL_ASN1_TIME_get_length(WOLFSSL_ASN1_TIME *t)
+{
+    WOLFSSL_ENTER("wolfSSL_ASN1_TIME_get_length");
+    if (t == NULL)
+        return WOLFSSL_FAILURE;
+
+    return (int)t->data[1];
+}
+
+unsigned char* wolfSSL_ASN1_TIME_get_data(WOLFSSL_ASN1_TIME *t)
+{
+    unsigned char *dptr = NULL;
+
+    WOLFSSL_ENTER("wolfSSL_ASN1_TIME_get_data");
+    if (t == NULL)
+    return NULL;
+
+    dptr = t->data + 2;
+    return dptr;
+}
+
+WOLFSSL_ASN1_TIME *wolfSSL_ASN1_TIME_to_generalizedtime(WOLFSSL_ASN1_TIME *t,
+                                                        WOLFSSL_ASN1_TIME **out)
+{
+    unsigned char time_type;
+    WOLFSSL_ASN1_TIME *ret = NULL;
+    unsigned char *data_ptr = NULL;
+
+    WOLFSSL_ENTER("wolfSSL_ASN1_TIME_to_generalizedtime");
+    if (t == NULL)
+        return NULL;
+
+    time_type = t->data[0];
+    if (time_type != ASN_UTC_TIME && time_type != ASN_GENERALIZED_TIME){
+        WOLFSSL_MSG("Invalid ASN_TIME type.");
+        return NULL;
+    }
+    if (out == NULL || *out == NULL){
+        ret = (WOLFSSL_ASN1_TIME*)XMALLOC(sizeof(WOLFSSL_ASN1_TIME), NULL,
+                                        DYNAMIC_TYPE_TMP_BUFFER);
+        if (ret == NULL){
+            WOLFSSL_MSG("memory alloc failed.");
+    return NULL;
+}
+        XMEMSET(ret, 0, sizeof(WOLFSSL_ASN1_TIME));
+    } else
+        ret = *out;
+
+    if (time_type == ASN_GENERALIZED_TIME){
+        XMEMCPY(ret->data, t->data, ASN_GENERALIZED_TIME_SIZE);
+        return ret;
+    } else if (time_type == ASN_UTC_TIME){
+        ret->data[0] = ASN_GENERALIZED_TIME;
+        ret->data[1] = ASN_GENERALIZED_TIME_SIZE;
+        data_ptr  = ret->data + 2;
+        if (t->data[2] >= '5')
+            XSNPRINTF((char*)data_ptr, ASN_UTC_TIME_SIZE + 2, "19%s", t->data + 2);
+        else
+            XSNPRINTF((char*)data_ptr, ASN_UTC_TIME_SIZE + 2, "20%s", t->data + 2);
+
+        return ret;
+    }
+
+    WOLFSSL_MSG("Invalid ASN_TIME value");
+    return NULL;
+}
+#endif /* !NO_ASN_TIME */
+
+
+#ifndef NO_ASN
+int wolfSSL_i2c_ASN1_INTEGER(WOLFSSL_ASN1_INTEGER *a, unsigned char **pp)
+{
+    unsigned char *pptr = NULL;
+    char pad = 0 ;
+    unsigned char pad_val = 0;
+    int ret_size = 0;
+    unsigned char data1 = 0;
+    unsigned char neg = 0;
+    int i = 0;
+
+    WOLFSSL_ENTER("wolfSSL_i2c_ASN1_INTEGER");
+    if (a == NULL)
+        return WOLFSSL_FAILURE;
+
+    ret_size = a->intData[1];
+    if (ret_size == 0)
+        ret_size = 1;
+    else{
+        ret_size = (int)a->intData[1];
+        neg = a->negative;
+        data1 = a->intData[2];
+        if (ret_size == 1 && data1 == 0)
+            neg = 0;
+        /* 0x80 or greater positive number in first byte */
+        if (!neg && (data1 > 127)){
+            pad = 1;
+            pad_val = 0;
+        } else if (neg){
+            /* negative number */
+            if (data1 > 128){
+                pad = 1;
+                pad_val = 0xff;
+            } else if (data1 == 128){
+                for (i = 3; i < a->intData[1] + 2; i++){
+                    if (a->intData[i]){
+                        pad = 1;
+                        pad_val = 0xff;
+                        break;
+                    }
+}
+            }
+        }
+        ret_size += (int)pad;
+    }
+    if (pp == NULL)
+        return ret_size;
+
+    pptr = *pp;
+    if (pad)
+        *(pptr++) = pad_val;
+    if (a->intData[1] == 0)
+        *(pptr++) = 0;
+    else if (!neg){
+        /* positive number */
+        for (i=0; i < a->intData[1]; i++){
+            *pptr = a->intData[i+2];
+            pptr++;
+        }
+    } else {
+        /* negative number */
+        int str_len = 0;
+
+        /* 0 padding from end of buffer */
+        str_len = (int)a->intData[1];
+        pptr += a->intData[1] - 1;
+        while (!a->intData[str_len + 2] && str_len > 1){
+            *(pptr--) = 0;
+            str_len--;
+        }
+        /* 2's complement next octet */
+        *(pptr--) = ((a->intData[str_len + 1]) ^ 0xff) + 1;
+        str_len--;
+        /* Complement any octets left */
+        while (str_len > 0){
+            *(pptr--) = a->intData[str_len + 1] ^ 0xff;
+            str_len--;
+        }
+    }
+    *pp += ret_size;
+    return ret_size;
+}
+#endif /* !NO_ASN */
+
+#ifndef NO_CERTS
+int wolfSSL_X509_CA_num(WOLFSSL_X509_STORE* store)
+{
+    int i = 0;
+    int cnt_ret = 0;
+    Signer **table;
+
+    WOLFSSL_ENTER("wolfSSL_X509_CA_num");
+    if (store == NULL || store->cm == NULL){
+        WOLFSSL_MSG("invalid parameter");
+        return WOLFSSL_FAILURE;
+    }
+
+    table = store->cm->caTable;
+    if (table){
+        if (wc_LockMutex(&store->cm->caLock) == 0){
+            for (i = 0; i < CA_TABLE_SIZE; i++) {
+                Signer* signer = table[i];
+                while (signer) {
+                    Signer* next = signer->next;
+                    cnt_ret++;
+                    signer = next;
+                }
+            }
+            wc_UnLockMutex(&store->cm->caLock);
+        }
+    }
+
+    return cnt_ret;
+}
+#endif /* !NO_CERTS */
+
+long wolfSSL_X509_get_version(const WOLFSSL_X509 *x509)
+{
+    int version = 0;
+
+    WOLFSSL_ENTER("wolfSSL_X509_get_version");
+
+    if (x509 == NULL){
+        WOLFSSL_MSG("invalid parameter");
+        return 0L;
+}
+    version = x509->version;
+    if (version != 0)
+        return (long)version - 1L;
+
+    return 0L;
+}
+
+int wolfSSL_X509_get_signature_nid(const WOLFSSL_X509 *x)
+{
+    if (x == NULL)
+        return 0;
+
+    return oid2nid(x->sigOID, oidSigType);
+}
+#endif  /* OPENSSL_EXTRA */
+
+#if defined(OPENSSL_ALL)
+int wolfSSL_EVP_PKEY_assign_RSA(EVP_PKEY* pkey, WOLFSSL_RSA* key)
+{
+    if (pkey == NULL || key == NULL)
+        return WOLFSSL_FAILURE;
+
+    pkey->type = EVP_PKEY_RSA;
+    pkey->rsa = key;
+    pkey->ownRsa = 1;
+
+    return WOLFSSL_SUCCESS;
+}
+
+int wolfSSL_EVP_PKEY_assign_EC_KEY(EVP_PKEY* pkey, WOLFSSL_EC_KEY* key)
+{
+    if (pkey == NULL || key == NULL)
+        return WOLFSSL_FAILURE;
+
+    pkey->type = EVP_PKEY_EC;
+    pkey->ecc = key;
+    pkey->ownEcc = 1;
+
+    return WOLFSSL_SUCCESS;
+    }
+#endif
+
+#if defined(OPENSSL_ALL) && defined(HAVE_PKCS7)
+PKCS7* wolfSSL_PKCS7_new(void)
+{
+    WOLFSSL_PKCS7* pkcs7;
+    int ret = 0;
+
+    pkcs7 = (WOLFSSL_PKCS7*)XMALLOC(sizeof(*pkcs7), NULL, DYNAMIC_TYPE_PKCS7);
+    if (pkcs7 != NULL) {
+        XMEMSET(pkcs7, 0, sizeof(*pkcs7));
+        ret = wc_PKCS7_Init(&pkcs7->pkcs7, NULL, INVALID_DEVID);
+}
+
+    if (ret != 0 && pkcs7 != NULL)
+        XFREE(pkcs7, NULL, DYNAMIC_TYPE_PKCS7);
+
+    return (PKCS7*)pkcs7;
+}
+
+void wolfSSL_PKCS7_free(PKCS7* pkcs7)
+{
+    WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7;
+
+    if (p7 != NULL) {
+        if (p7->data != NULL)
+            XFREE(p7->data, NULL, DYNAMIC_TYPE_PKCS7);
+        wc_PKCS7_Free(&p7->pkcs7);
+        XFREE(p7, NULL, DYNAMIC_TYPE_PKCS7);
+    }
+}
+
+PKCS7* wolfSSL_d2i_PKCS7(PKCS7** p7, const unsigned char** in, int len)
+{
+    WOLFSSL_PKCS7* pkcs7 = NULL;
+    word32 idx = 0;
+
+    if (in == NULL)
+        return NULL;
+
+    if ((pkcs7 = (WOLFSSL_PKCS7*)wolfSSL_PKCS7_new()) == NULL)
+        return NULL;
+
+    if (GetSequence(*in, &idx, &pkcs7->len, len) < 0) {
+        wolfSSL_PKCS7_free((PKCS7*)pkcs7);
+        return NULL;
+    }
+    pkcs7->len += idx;
+
+    pkcs7->data = (byte*)XMALLOC(pkcs7->len, NULL, DYNAMIC_TYPE_PKCS7);
+    if (pkcs7->data == NULL) {
+        wolfSSL_PKCS7_free((PKCS7*)pkcs7);
+        return NULL;
+    }
+    XMEMCPY(pkcs7->data, *in, pkcs7->len);
+    *in += pkcs7->len;
+
+    if (p7 != NULL)
+        *p7 = (PKCS7*)pkcs7;
+    return (PKCS7*)pkcs7;
+    }
+
+PKCS7* wolfSSL_d2i_PKCS7_bio(WOLFSSL_BIO* bio, PKCS7** p7)
+    {
+    WOLFSSL_PKCS7* pkcs7;
+
+    if (bio == NULL)
+        return NULL;
+
+    if ((pkcs7 = (WOLFSSL_PKCS7*)wolfSSL_PKCS7_new()) == NULL)
+        return NULL;
+
+    pkcs7->len = wolfSSL_BIO_pending(bio);
+    pkcs7->data = (byte*)XMALLOC(pkcs7->len, NULL, DYNAMIC_TYPE_PKCS7);
+    if (pkcs7->data == NULL) {
+        wolfSSL_PKCS7_free((PKCS7*)pkcs7);
+        return NULL;
+    }
+
+    if (wolfSSL_BIO_read(bio, pkcs7->data, pkcs7->len) != pkcs7->len) {
+        wolfSSL_PKCS7_free((PKCS7*)pkcs7);
+        return NULL;
+    }
+
+    if (p7 != NULL)
+        *p7 = (PKCS7*)pkcs7;
+    return (PKCS7*)pkcs7;
+}
+
+int wolfSSL_PKCS7_verify(PKCS7* pkcs7, WOLFSSL_STACK* certs,
+                         WOLFSSL_X509_STORE* store, WOLFSSL_BIO* in,
+                         WOLFSSL_BIO* out, int flags)
+{
+    int ret = 0;
+    unsigned char* mem = NULL;
+    int memSz = 0;
+    WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7;
+
+    if (pkcs7 == NULL)
+        return WOLFSSL_FAILURE;
+
+    if (in != NULL) {
+        if ((memSz = wolfSSL_BIO_get_mem_data(in, &mem)) < 0)
+            return WOLFSSL_FAILURE;
+
+        p7->pkcs7.content = mem;
+        p7->pkcs7.contentSz = memSz;
+    }
+    if (ret != 0)
+        return WOLFSSL_FAILURE;
+
+    /* certs is the list of certificates to find the cert with issuer/serial. */
+    (void)certs;
+    /* store is the certificate store to use to verify signer certificate
+     * associated with the signers.
+     */
+    (void)store;
+
+    ret = wc_PKCS7_VerifySignedData_ex(&p7->pkcs7, NULL, 0, p7->data, p7->len,
+                                                                       NULL, 0);
+    if (ret != 0)
+        return WOLFSSL_FAILURE;
+
+    if ((flags & PKCS7_NOVERIFY) != PKCS7_NOVERIFY) {
+        /* All signer certificates are verified. */
+        return WOLFSSL_FAILURE;
+    }
+
+    if (out != NULL)
+       wolfSSL_BIO_write(out, p7->pkcs7.content, p7->pkcs7.contentSz);
+
+    return WOLFSSL_SUCCESS;
+}
+
+WOLFSSL_STACK* wolfSSL_PKCS7_get0_signers(PKCS7* pkcs7, WOLFSSL_STACK* certs,
+                                          int flags)
+{
+    WOLFSSL_STACK* signers = NULL;
+    WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7;
+
+    if (p7 == NULL)
+        return NULL;
+    /* Only PKCS#7 messages with a single cert that is the verifying certificate
+     * is supported.
+     */
+    if ((flags | PKCS7_NOINTERN) == PKCS7_NOINTERN)
+        return NULL;
+
+    signers = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL,
+                                                             DYNAMIC_TYPE_X509);
+    if (signers == NULL)
+        return NULL;
+
+    signers->num = 1;
+    signers->data.x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL,
+                                                             DYNAMIC_TYPE_X509);
+    if (signers->data.x509 == NULL) {
+        XFREE(signers, NULL, DYNAMIC_TYPE_X509);
+        return NULL;
+}
+
+    if (DecodeToX509(signers->data.x509, p7->pkcs7.singleCert,
+                                                 p7->pkcs7.singleCertSz) != 0) {
+        XFREE(signers->data.x509, NULL, DYNAMIC_TYPE_X509);
+        XFREE(signers, NULL, DYNAMIC_TYPE_X509);
+        return NULL;
+}
+
+    (void)certs;
+
+    return signers;
+}
+#endif
+
+#ifdef OPENSSL_ALL
+WOLFSSL_STACK* wolfSSL_sk_X509_new(void)
+{
+    WOLFSSL_STACK* s = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL,
+                                                             DYNAMIC_TYPE_X509);
+    if (s != NULL)
+        XMEMSET(s, 0, sizeof(*s));
+
+    return s;
+    }
+#endif
+
+#ifdef OPENSSL_ALL
+int wolfSSL_PEM_write_bio_PKCS8PrivateKey(WOLFSSL_BIO* bio,
+                                          WOLFSSL_EVP_PKEY* pkey,
+                                          const WOLFSSL_EVP_CIPHER* enc,
+                                          char* passwd, int passwdSz,
+                                          pem_password_cb* cb, void* ctx)
+{
+    int ret = 0;
+    char password[NAME_SZ];
+    byte* key = NULL;
+    word32 keySz;
+    byte* pem = NULL;
+    int pemSz;
+    int type = PKCS8_PRIVATEKEY_TYPE;
+    int algId;
+    const byte* curveOid;
+    word32 oidSz;
+    int encAlgId;
+
+    if (bio == NULL || pkey == NULL)
+        return -1;
+
+    keySz = pkey->pkey_sz + 128;
+    key = (byte*)XMALLOC(keySz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (key == NULL)
+        ret = MEMORY_E;
+
+    if (ret == 0 && enc != NULL && passwd == NULL) {
+        passwdSz = cb(password, sizeof(password), 1, ctx);
+        if (passwdSz < 0)
+            ret = WOLFSSL_FAILURE;
+        passwd = password;
+        }
+
+    if (ret == 0 && enc != NULL) {
+        WC_RNG rng;
+        ret = wc_InitRng(&rng);
+        if (ret == 0) {
+        #ifndef NO_DES3
+            if (enc == EVP_DES_CBC)
+                encAlgId = DESb;
+            else if (enc == EVP_DES_EDE3_CBC)
+                encAlgId = DES3b;
+            else
+        #endif
+        #if !defined(NO_AES) && defined(HAVE_AES_CBC)
+            #ifdef WOLFSSL_AES_256
+            if (enc == EVP_AES_256_CBC)
+                encAlgId = AES256CBCb;
+            else
+            #endif
+        #endif
+                ret = -1;
+            if (ret == 0) {
+                ret = TraditionalEnc((byte*)pkey->pkey.ptr, pkey->pkey_sz, key,
+                                       &keySz, passwd, passwdSz, PKCS5, PBES2,
+                                       encAlgId, NULL, 0, WC_PKCS12_ITT_DEFAULT,
+                                       &rng, NULL);
+                if (ret > 0) {
+                    keySz = ret;
+                    ret = 0;
+                }
+            }
+            wc_FreeRng(&rng);
+        }
+        type = PKCS8_ENC_PRIVATEKEY_TYPE;
+    }
+    if (ret == 0 && enc == NULL) {
+        type = PKCS8_PRIVATEKEY_TYPE;
+        if (pkey->type == EVP_PKEY_EC) {
+            algId = ECDSAk;
+            ret = wc_ecc_get_oid(pkey->ecc->group->curve_oid, &curveOid,
+                                                                        &oidSz);
+        }
+        else {
+            algId = RSAk;
+            curveOid = NULL;
+            oidSz = 0;
+        }
+
+        if (ret >= 0) {
+            ret = wc_CreatePKCS8Key(key, &keySz, (byte*)pkey->pkey.ptr,
+                                         pkey->pkey_sz, algId, curveOid, oidSz);
+            keySz = ret;
+        }
+    }
+
+    if (password == passwd)
+        XMEMSET(password, 0, passwdSz);
+
+    if (ret >= 0) {
+        pemSz = 2 * keySz + 2 * 64;
+        pem = (byte*)XMALLOC(pemSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (pem == NULL)
+            ret = MEMORY_E;
+}
+
+    if (ret >= 0)
+        ret = wc_DerToPemEx(key, keySz, pem, pemSz, NULL, type);
+
+    if (key != NULL)
+        XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+    if (ret >= 0) {
+        if (wolfSSL_BIO_write(bio, pem, ret) != ret)
+            ret = -1;
+    }
+
+    if (pem != NULL)
+        XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+    return ret < 0 ? 0 : ret;
+
+}
+
+static int bio_get_data(WOLFSSL_BIO* bio, byte** data)
+{
+    int ret = 0;
+    byte* mem = NULL;
+#ifndef NO_FILESYSTEM
+    long memSz;
+    XFILE file;
+    long curr;
+#endif
+
+    if ((ret = wolfSSL_BIO_pending(bio)) > 0) {
+            }
+#ifndef NO_FILESYSTEM
+    else if (bio->type == WOLFSSL_BIO_FILE) {
+        if (wolfSSL_BIO_get_fp(bio, &file) != WOLFSSL_SUCCESS)
+            ret = BAD_FUNC_ARG;
+        if (ret == 0) {
+            curr = XFTELL(file);
+            if (XFSEEK(file, 0, XSEEK_END) != 0)
+                ret = WOLFSSL_BAD_FILE;
+        }
+        if (ret == 0) {
+            memSz = XFTELL(file) - curr;
+            ret = (int)memSz;
+            if (XFSEEK(file, curr, SEEK_SET) != 0)
+                ret = WOLFSSL_BAD_FILE;
+        }
+    }
+#endif
+
+    if (ret > 0) {
+        mem = (byte*)XMALLOC(ret, bio->heap, DYNAMIC_TYPE_OPENSSL);
+        if (mem == NULL) {
+            WOLFSSL_MSG("Memory error");
+            ret = MEMORY_E;
+        }
+        if (ret >= 0) {
+            if ((ret = wolfSSL_BIO_read(bio, mem, ret)) <= 0) {
+                XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL);
+                ret = MEMORY_E;
+            }
+        }
+    }
+
+    *data = mem;
+    return ret;
+}
+
+/* DER data is PKCS#8 encrypted. */
+WOLFSSL_EVP_PKEY* wolfSSL_d2i_PKCS8PrivateKey_bio(WOLFSSL_BIO* bio,
+                                                  WOLFSSL_EVP_PKEY** pkey,
+                                                  pem_password_cb* cb,
+                                                  void* ctx)
+{
+    int ret;
+    byte* der;
+    int len;
+    byte* p;
+    char password[NAME_SZ];
+    int passwordSz;
+    word32 algId;
+    WOLFSSL_EVP_PKEY* key;
+
+    if ((len = bio_get_data(bio, &der)) < 0)
+        return NULL;
+
+    if (cb != NULL) {
+        passwordSz = cb(password, sizeof(password), PEM_PASS_READ, ctx);
+        if (passwordSz < 0)
+            return NULL;
+
+        ret = ToTraditionalEnc(der, len, password, passwordSz, &algId);
+        if (ret < 0)
+            return NULL;
+        XMEMSET(password, 0, passwordSz);
+}
+
+    p = der;
+    key = wolfSSL_d2i_PrivateKey_EVP(pkey, &p, len);
+    XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL);
+    return key;
+}
+
+/* Detect which type of key it is before decoding. */
+WOLFSSL_EVP_PKEY* wolfSSL_d2i_AutoPrivateKey(WOLFSSL_EVP_PKEY** pkey,
+                                             const unsigned char** pp,
+                                             long length)
+{
+    int ret;
+    WOLFSSL_EVP_PKEY* key = NULL;
+    const byte* der = *pp;
+    word32 idx = 0;
+    int len = 0;
+    word32 end = 0;
+    int cnt = 0;
+    int type;
+    word32 algId;
+    word32 keyLen = (word32)length;
+
+    /* Take off PKCS#8 wrapper if found. */
+    if ((len = ToTraditionalInline_ex(der, &idx, keyLen, &algId)) >= 0) {
+        der += idx;
+        keyLen = len;
+    }
+    idx = 0;
+    len = 0;
+
+    /* Use the number of elements in the outer sequence to determine key type.
+     */
+    ret = GetSequence(der, &idx, &len, keyLen);
+    if (ret >= 0) {
+        end = idx + len;
+        while (ret >= 0 && idx < end) {
+            /* Skip type */
+            idx++;
+            /* Get length and skip over - keeping count */
+            len = 0;
+            ret = GetLength(der, &idx, &len, keyLen);
+            if (ret >= 0) {
+                if (idx + len > end)
+                    ret = ASN_PARSE_E;
+                else {
+                    idx += len;
+                    cnt++;
+                }
+            }
+    }
+}
+
+    if (ret >= 0) {
+        /* ECC includes version, private[, curve][, public key] */
+        if (cnt >= 2 && cnt <= 4)
+            type = EVP_PKEY_EC;
+        else
+            type = EVP_PKEY_RSA;
+
+        key = wolfSSL_d2i_PrivateKey(type, pkey, &der, keyLen);
+        *pp = der;
+    }
+
+    return key;
+}
+#endif
+
+#if defined(OPENSSL_ALL) && !defined(NO_CERT) && defined(WOLFSSL_CERT_GEN) && \
+                                                       defined(WOLFSSL_CERT_REQ)
+int wolfSSL_i2d_X509_REQ(WOLFSSL_X509* req, unsigned char** out)
+{
+    const unsigned char* der;
+    int derSz = 0;
+
+    if (req == NULL || out == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    der = wolfSSL_X509_get_der(req, &derSz);
+    if (der == NULL) {
+        return MEMORY_E;
+    }
+
+    if (*out == NULL) {
+        *out = (unsigned char*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_OPENSSL);
+        if (*out == NULL) {
+            return MEMORY_E;
+        }
+    }
+
+    XMEMCPY(*out, der, derSz);
+
+    return derSz;
+}
+
+int wolfSSL_X509_set_subject_name(WOLFSSL_X509 *cert, WOLFSSL_X509_NAME *name)
+{
+    int i;
+    WOLFSSL_X509_NAME_ENTRY* ne;
+
+    if (cert == NULL || name == NULL)
+        return WOLFSSL_FAILURE;
+
+    FreeX509Name(&cert->subject, cert->heap);
+    InitX509Name(&cert->subject, 0);
+    if (name->dynamicName) {
+        cert->subject.name = (char*)XMALLOC(name->sz, cert->heap,
+                                                       DYNAMIC_TYPE_SUBJECT_CN);
+        if (cert->subject.name == NULL)
+            return WOLFSSL_FAILURE;
+    }
+    XMEMCPY(cert->subject.name, name->name, name->sz);
+    cert->subject.sz = name->sz;
+
+    for (i = 0; i < 10; i++) {
+        ne = wolfSSL_X509_NAME_get_entry(name, i);
+        if (ne != NULL)
+            wolfSSL_X509_NAME_add_entry(&cert->subject, ne, i, 1);
+}
+    cert->subject.x509 = cert;
+
+    return WOLFSSL_SUCCESS;
+}
+
+int wolfSSL_X509_set_pubkey(WOLFSSL_X509 *cert, WOLFSSL_EVP_PKEY *pkey)
+{
+    byte* p;
+
+    if (cert == NULL || pkey == NULL)
+        return WOLFSSL_FAILURE;
+
+    if (pkey->type == EVP_PKEY_RSA)
+        cert->pubKeyOID = RSAk;
+    else if (pkey->type == EVP_PKEY_EC)
+        cert->pubKeyOID = ECDSAk;
+    else
+        return WOLFSSL_FAILURE;
+
+    p = (byte*)XMALLOC(pkey->pkey_sz, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+    if (p == NULL)
+        return WOLFSSL_FAILURE;
+
+    if (cert->pubKey.buffer != NULL)
+        XFREE(cert->pubKey.buffer, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+    cert->pubKey.buffer = p;
+    XMEMCPY(cert->pubKey.buffer, pkey->pkey.ptr, pkey->pkey_sz);
+    cert->pubKey.length = pkey->pkey_sz;
+
+    return WOLFSSL_SUCCESS;
+}
+
+
+WOLFSSL_X509* wolfSSL_X509_REQ_new(void)
+{
+    return wolfSSL_X509_new();
+}
+
+void wolfSSL_X509_REQ_free(WOLFSSL_X509* req)
+{
+    wolfSSL_X509_free(req);
+}
+
+
+static int ReqCertFromX509(Cert* cert, WOLFSSL_X509* req)
+{
+    int ret;
+
+    ret = CopyX509NameToCertName(&req->subject, &cert->subject);
+    if (ret == WOLFSSL_SUCCESS) {
+        cert->version = req->version;
+        cert->isCA = req->isCa;
+        if (req->subjKeyIdSz != 0) {
+            XMEMCPY(cert->skid, req->subjKeyId, req->subjKeyIdSz);
+            cert->skidSz = req->subjKeyIdSz;
+        }
+        if (req->keyUsageSet)
+            cert->keyUsage = req->keyUsage;
+        /* Extended Key Usage not supported. */
+}
+
+    return ret;
+}
+
+int wolfSSL_X509_REQ_sign(WOLFSSL_X509 *req, WOLFSSL_EVP_PKEY *pkey,
+                          const WOLFSSL_EVP_MD *md)
+{
+    int ret;
+    Cert cert;
+    byte der[2048];
+    int derSz = sizeof(der);
+    void* key;
+    int type;
+    int sigType;
+    int hashType;
+    RsaKey rsa;
+    ecc_key ecc;
+    WC_RNG rng;
+    word32 idx = 0;
+
+    if (req == NULL || pkey == NULL || md == NULL)
+        return WOLFSSL_FAILURE;
+
+    /* Create a Cert that has the certificate request fields. */
+    if (wc_InitCert(&cert) != 0)
+        return WOLFSSL_FAILURE;
+    if (ReqCertFromX509(&cert, req) != WOLFSSL_SUCCESS)
+            return WOLFSSL_FAILURE;
+
+    /* Convert key type and hash algorithm to a signature algorithm */
+    if (wolfSSL_EVP_get_hashinfo(md, &hashType, NULL) == WOLFSSL_FAILURE)
+        return WOLFSSL_FAILURE;
+
+    if (pkey->type == EVP_PKEY_RSA) {
+        switch (hashType) {
+            case WC_HASH_TYPE_SHA:
+                sigType = CTC_SHAwRSA;
+                break;
+            case WC_HASH_TYPE_SHA224:
+                sigType = CTC_SHA224wRSA;
+                break;
+            case WC_HASH_TYPE_SHA256:
+                sigType = CTC_SHA256wRSA;
+                break;
+            case WC_HASH_TYPE_SHA384:
+                sigType = CTC_SHA384wRSA;
+                break;
+            case WC_HASH_TYPE_SHA512:
+                sigType = CTC_SHA512wRSA;
+                break;
+            default:
+                return WOLFSSL_FAILURE;
+        }
+        }
+    else if (pkey->type == EVP_PKEY_EC) {
+        switch (hashType) {
+            case WC_HASH_TYPE_SHA:
+                sigType = CTC_SHAwECDSA;
+                break;
+            case WC_HASH_TYPE_SHA224:
+                sigType = CTC_SHA224wECDSA;
+                break;
+            case WC_HASH_TYPE_SHA256:
+                sigType = CTC_SHA256wECDSA;
+                break;
+            case WC_HASH_TYPE_SHA384:
+                sigType = CTC_SHA384wECDSA;
+                break;
+            case WC_HASH_TYPE_SHA512:
+                sigType = CTC_SHA512wECDSA;
+                break;
+            default:
+                return WOLFSSL_FAILURE;
+        }
+    }
+    else
+            return WOLFSSL_FAILURE;
+
+    /* Create a public key object from requests public key. */
+    if (req->pubKeyOID == RSAk) {
+        type = RSA_TYPE;
+        ret = wc_InitRsaKey(&rsa, req->heap);
+        if (ret != 0)
+            return WOLFSSL_FAILURE;
+        ret = wc_RsaPublicKeyDecode(req->pubKey.buffer, &idx, &rsa,
+                                                            req->pubKey.length);
+        if (ret != 0) {
+            wc_FreeRsaKey(&rsa);
+            return WOLFSSL_FAILURE;
+    }
+        key = (void*)&rsa;
+    }
+    else {
+        type = ECC_TYPE;
+        ret = wc_ecc_init(&ecc);
+        if (ret != 0)
+            return WOLFSSL_FAILURE;
+        ret = wc_EccPublicKeyDecode(req->pubKey.buffer, &idx, &ecc,
+                                                            req->pubKey.length);
+        if (ret != 0) {
+            wc_ecc_free(&ecc);
+            return WOLFSSL_FAILURE;
+        }
+        key = (void*)&ecc;
+}
+
+    /* Make the body of the certificate request. */
+    ret = wc_MakeCertReq_ex(&cert, der, derSz, type, key);
+    if (ret < 0)
+    return WOLFSSL_FAILURE;
+
+    /* Dispose of the public key object. */
+    if (req->pubKeyOID == RSAk)
+        wc_FreeRsaKey(&rsa);
+    else
+        wc_ecc_free(&ecc);
+
+    idx = 0;
+    /* Get the private key object and type from pkey. */
+    if (pkey->type == EVP_PKEY_RSA) {
+        type = RSA_TYPE;
+        key = pkey->rsa->internal;
+}
+    else {
+        type = ECC_TYPE;
+        key = pkey->ecc->internal;
+    }
+
+    /* Sign the certificate request body. */
+    ret = wc_InitRng(&rng);
+    if (ret != 0)
+        return WOLFSSL_FAILURE;
+    ret = wc_SignCert_ex(cert.bodySz, sigType, der, sizeof(der), type, key,
+                                                                          &rng);
+    wc_FreeRng(&rng);
+    if (ret < 0)
+        return WOLFSSL_FAILURE;
+
+    /* Put in the new certificate request encoding into the request object. */
+    FreeDer(&req->derCert);
+    if (AllocDer(&req->derCert, ret, CERTREQ_TYPE, NULL) != 0)
+    return WOLFSSL_FAILURE;
+    XMEMCPY(req->derCert->buffer, der, ret);
+    req->derCert->length = ret;
+
+    return WOLFSSL_SUCCESS;
+}
+
+int wolfSSL_X509_REQ_set_subject_name(WOLFSSL_X509 *req,
+                                      WOLFSSL_X509_NAME *name)
+{
+    return wolfSSL_X509_set_subject_name(req, name);
+}
+
+int wolfSSL_X509_REQ_set_pubkey(WOLFSSL_X509 *req, WOLFSSL_EVP_PKEY *pkey)
+{
+    return wolfSSL_X509_set_pubkey(req, pkey);
+}
+#endif
+
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/tls.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/tls.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/tls.c	(revision 372)
@@ -49,4 +49,5 @@
     #include <wolfssl/wolfcrypt/random.h>
 #endif
+
 #ifdef HAVE_QSH
     static int TLSX_AddQSHKey(QSHKey** list, QSHKey* key);
@@ -57,4 +58,19 @@
 #endif /* HAVE_QSH */
 
+#if (!defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_TLS13) && \
+        !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)) || \
+    (defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES))
+static int TLSX_KeyShare_IsSupported(int namedGroup);
+#endif
+
+#if (!defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_TLS13) && \
+        !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)) || \
+    (defined(WOLFSSL_TLS13) && !defined(HAVE_ECC) && \
+        !defined(HAVE_CURVE25519) && defined(HAVE_SUPPORTED_CURVES)) || \
+    ((defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \
+        defined(HAVE_SUPPORTED_CURVES))
+static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions);
+#endif
+
 
 #ifndef NO_TLS
@@ -72,4 +88,24 @@
 #endif
 
+#ifdef WOLFSSL_TLS13
+    #if !defined(NO_DH) && \
+        !defined(HAVE_FFDHE_2048) && !defined(HAVE_FFDHE_3072) && \
+        !defined(HAVE_FFDHE_4096) && !defined(HAVE_FFDHE_6144) && \
+        !defined(HAVE_FFDHE_8192)
+        #error Please configure your TLS 1.3 DH key size using either: HAVE_FFDHE_2048, HAVE_FFDHE_3072, HAVE_FFDHE_4096, HAVE_FFDHE_6144 or HAVE_FFDHE_8192
+    #endif
+    #if !defined(NO_RSA) && !defined(WC_RSA_PSS)
+        #error The build option WC_RSA_PSS is required for TLS 1.3 with RSA
+    #endif
+#endif
+
+/* Optional Pre-Master-Secret logging for Wireshark */
+#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SSLKEYLOGFILE)
+#ifndef WOLFSSL_SSLKEYLOGFILE_OUTPUT
+    #define WOLFSSL_SSLKEYLOGFILE_OUTPUT "sslkeylog.log"
+#endif
+#endif
+
+#ifndef WOLFSSL_NO_TLS12
 
 #ifdef WOLFSSL_SHA384
@@ -78,5 +114,4 @@
     #define P_HASH_MAX_SIZE WC_SHA256_DIGEST_SIZE
 #endif
-
 
 /* compute p_hash for MD5, SHA-1, SHA-256, or SHA-384 for TLSv1 PRF */
@@ -207,9 +242,11 @@
 #undef P_HASH_MAX_SIZE
 
+#endif /* !WOLFSSL_NO_TLS12 */
+
 
 #ifndef NO_OLD_TLS
 
 /* calculate XOR for TLSv1 PRF */
-static INLINE void get_xor(byte *digest, word32 digLen, byte* md5, byte* sha)
+static WC_INLINE void get_xor(byte *digest, word32 digLen, byte* md5, byte* sha)
 {
     word32 i;
@@ -231,5 +268,4 @@
     byte* md5_half;
     byte* sha_half;
-    byte* labelSeed;
     byte* md5_result;
     byte* sha_result;
@@ -237,30 +273,40 @@
     byte  md5_half[MAX_PRF_HALF];     /* half is real size */
     byte  sha_half[MAX_PRF_HALF];     /* half is real size */
-    byte  labelSeed[MAX_PRF_LABSEED]; /* labLen + seedLen is real size */
     byte  md5_result[MAX_PRF_DIG];    /* digLen is real size */
     byte  sha_result[MAX_PRF_DIG];    /* digLen is real size */
 #endif
-
-    if (half > MAX_PRF_HALF)
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+    DECLARE_VAR(labelSeed, byte, MAX_PRF_LABSEED, heap);
+    if (labelSeed == NULL)
+        return MEMORY_E;
+#else
+    byte labelSeed[MAX_PRF_LABSEED];
+#endif
+
+    if (half > MAX_PRF_HALF ||
+        labLen + seedLen > MAX_PRF_LABSEED ||
+        digLen > MAX_PRF_DIG)
+    {
+    #if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+        FREE_VAR(labelSeed, heap);
+    #endif
         return BUFFER_E;
-    if (labLen + seedLen > MAX_PRF_LABSEED)
-        return BUFFER_E;
-    if (digLen > MAX_PRF_DIG)
-        return BUFFER_E;
+    }
 
 #ifdef WOLFSSL_SMALL_STACK
     md5_half   = (byte*)XMALLOC(MAX_PRF_HALF,    heap, DYNAMIC_TYPE_DIGEST);
     sha_half   = (byte*)XMALLOC(MAX_PRF_HALF,    heap, DYNAMIC_TYPE_DIGEST);
-    labelSeed  = (byte*)XMALLOC(MAX_PRF_LABSEED, heap, DYNAMIC_TYPE_SEED);
     md5_result = (byte*)XMALLOC(MAX_PRF_DIG,     heap, DYNAMIC_TYPE_DIGEST);
     sha_result = (byte*)XMALLOC(MAX_PRF_DIG,     heap, DYNAMIC_TYPE_DIGEST);
 
-    if (md5_half == NULL || sha_half == NULL || labelSeed == NULL ||
-                                     md5_result == NULL || sha_result == NULL) {
+    if (md5_half == NULL || sha_half == NULL || md5_result == NULL ||
+                                                           sha_result == NULL) {
         if (md5_half)   XFREE(md5_half,   heap, DYNAMIC_TYPE_DIGEST);
         if (sha_half)   XFREE(sha_half,   heap, DYNAMIC_TYPE_DIGEST);
-        if (labelSeed)  XFREE(labelSeed,  heap, DYNAMIC_TYPE_SEED);
         if (md5_result) XFREE(md5_result, heap, DYNAMIC_TYPE_DIGEST);
         if (sha_result) XFREE(sha_result, heap, DYNAMIC_TYPE_DIGEST);
+    #if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+        FREE_VAR(labelSeed, heap);
+    #endif
 
         return MEMORY_E;
@@ -288,9 +334,12 @@
     XFREE(md5_half,   heap, DYNAMIC_TYPE_DIGEST);
     XFREE(sha_half,   heap, DYNAMIC_TYPE_DIGEST);
-    XFREE(labelSeed,  heap, DYNAMIC_TYPE_SEED);
     XFREE(md5_result, heap, DYNAMIC_TYPE_DIGEST);
     XFREE(sha_result, heap, DYNAMIC_TYPE_DIGEST);
 #endif
 
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+    FREE_VAR(labelSeed, heap);
+#endif
+
     return ret;
 }
@@ -298,4 +347,6 @@
 #endif
 
+
+#ifndef WOLFSSL_NO_TLS12
 
 /* Wrapper to call straight thru to p_hash in TSL 1.2 cases to remove stack
@@ -308,18 +359,14 @@
 
     if (useAtLeastSha256) {
-#ifdef WOLFSSL_SMALL_STACK
-        byte* labelSeed;
+    #if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+        DECLARE_VAR(labelSeed, byte, MAX_PRF_LABSEED, heap);
+        if (labelSeed == NULL)
+            return MEMORY_E;
 #else
-        byte labelSeed[MAX_PRF_LABSEED]; /* labLen + seedLen is real size */
+        byte labelSeed[MAX_PRF_LABSEED];
 #endif
 
         if (labLen + seedLen > MAX_PRF_LABSEED)
             return BUFFER_E;
-
-#ifdef WOLFSSL_SMALL_STACK
-        labelSeed = (byte*)XMALLOC(MAX_PRF_LABSEED, heap, DYNAMIC_TYPE_SEED);
-        if (labelSeed == NULL)
-           return MEMORY_E;
-#endif
 
         XMEMCPY(labelSeed, label, labLen);
@@ -333,6 +380,6 @@
                      labLen + seedLen, hash_type, heap, devId);
 
-#ifdef WOLFSSL_SMALL_STACK
-        XFREE(labelSeed, heap, DYNAMIC_TYPE_SEED);
+    #if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+        FREE_VAR(labelSeed, heap);
 #endif
     }
@@ -356,4 +403,5 @@
 int BuildTlsHandshakeHash(WOLFSSL* ssl, byte* hash, word32* hashLen)
 {
+    int ret = 0;
     word32 hashSz = FINISHED_SZ;
 
@@ -361,7 +409,8 @@
         return BAD_FUNC_ARG;
 
+    /* for constant timing perform these even if error */
 #ifndef NO_OLD_TLS
-    wc_Md5GetHash(&ssl->hsHashes->hashMd5, hash);
-    wc_ShaGetHash(&ssl->hsHashes->hashSha, &hash[WC_MD5_DIGEST_SIZE]);
+    ret |= wc_Md5GetHash(&ssl->hsHashes->hashMd5, hash);
+    ret |= wc_ShaGetHash(&ssl->hsHashes->hashSha, &hash[WC_MD5_DIGEST_SIZE]);
 #endif
 
@@ -370,9 +419,5 @@
         if (ssl->specs.mac_algorithm <= sha256_mac ||
             ssl->specs.mac_algorithm == blake2b_mac) {
-            int ret = wc_Sha256GetHash(&ssl->hsHashes->hashSha256, hash);
-
-            if (ret != 0)
-                return ret;
-
+            ret |= wc_Sha256GetHash(&ssl->hsHashes->hashSha256, hash);
             hashSz = WC_SHA256_DIGEST_SIZE;
         }
@@ -380,9 +425,5 @@
 #ifdef WOLFSSL_SHA384
         if (ssl->specs.mac_algorithm == sha384_mac) {
-            int ret = wc_Sha384GetHash(&ssl->hsHashes->hashSha384, hash);
-
-            if (ret != 0)
-                return ret;
-
+            ret |= wc_Sha384GetHash(&ssl->hsHashes->hashSha384, hash);
             hashSz = WC_SHA384_DIGEST_SIZE;
         }
@@ -392,5 +433,8 @@
     *hashLen = hashSz;
 
-    return 0;
+    if (ret != 0)
+        ret = BUILD_MSG_ERROR;
+
+    return ret;
 }
 
@@ -400,11 +444,12 @@
     int         ret;
     const byte* side;
-    byte*       handshake_hash;
     word32      hashSz = HSHASH_SZ;
-
-    /* using allocate here to allow async hardware to use buffer directly */
-    handshake_hash = (byte*)XMALLOC(hashSz, ssl->heap, DYNAMIC_TYPE_DIGEST);
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+    DECLARE_VAR(handshake_hash, byte, HSHASH_SZ, ssl->heap);
     if (handshake_hash == NULL)
         return MEMORY_E;
+#else
+    byte handshake_hash[HSHASH_SZ];
+#endif
 
     ret = BuildTlsHandshakeHash(ssl, handshake_hash, &hashSz);
@@ -421,12 +466,16 @@
     }
 
-    XFREE(handshake_hash, ssl->heap, DYNAMIC_TYPE_DIGEST);
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+    FREE_VAR(handshake_hash, ssl->heap);
+#endif
 
     return ret;
 }
 
+#endif /* !WOLFSSL_NO_TLS12 */
 
 #ifndef NO_OLD_TLS
 
+#ifdef WOLFSSL_ALLOW_TLSV10
 ProtocolVersion MakeTLSv1(void)
 {
@@ -437,4 +486,5 @@
     return pv;
 }
+#endif /* WOLFSSL_ALLOW_TLSV10 */
 
 
@@ -448,6 +498,8 @@
 }
 
-#endif
-
+#endif /* !NO_OLD_TLS */
+
+
+#ifndef WOLFSSL_NO_TLS12
 
 ProtocolVersion MakeTLSv1_2(void)
@@ -459,4 +511,6 @@
     return pv;
 }
+
+#endif /* !WOLFSSL_NO_TLS12 */
 
 #ifdef WOLFSSL_TLS13
@@ -475,4 +529,5 @@
 #endif
 
+#ifndef WOLFSSL_NO_TLS12
 
 #ifdef HAVE_EXTENDED_MASTER
@@ -489,11 +544,24 @@
                          void* heap, int devId)
 {
+    int ret;
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+    DECLARE_VAR(seed, byte, SEED_LEN, heap);
+    if (seed == NULL)
+        return MEMORY_E;
+#else
     byte  seed[SEED_LEN];
+#endif
 
     XMEMCPY(seed,           sr, RAN_LEN);
     XMEMCPY(seed + RAN_LEN, cr, RAN_LEN);
 
-    return PRF(key_dig, key_dig_len, ms, msLen, key_label, KEY_LABEL_SZ,
+    ret = PRF(key_dig, key_dig_len, ms, msLen, key_label, KEY_LABEL_SZ,
                seed, SEED_LEN, tls1_2, hash_type, heap, devId);
+
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+    FREE_VAR(seed, heap);
+#endif
+
+    return ret;
 }
 
@@ -549,11 +617,24 @@
                                void* heap, int devId)
 {
+    int ret;
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+    DECLARE_VAR(seed, byte, SEED_LEN, heap);
+    if (seed == NULL)
+        return MEMORY_E;
+#else
     byte  seed[SEED_LEN];
+#endif
 
     XMEMCPY(seed,           cr, RAN_LEN);
     XMEMCPY(seed + RAN_LEN, sr, RAN_LEN);
 
-    return PRF(ms, msLen, pms, pmsLen, master_label, MASTER_LABEL_SZ,
+    ret = PRF(ms, msLen, pms, pmsLen, master_label, MASTER_LABEL_SZ,
                seed, SEED_LEN, tls1_2, hash_type, heap, devId);
+
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+    FREE_VAR(seed, heap);
+#endif
+
+    return ret;
 }
 
@@ -597,20 +678,19 @@
 {
     int    ret;
+
 #ifdef HAVE_EXTENDED_MASTER
     if (ssl->options.haveEMS) {
-        byte*  handshake_hash;
         word32 hashSz = HSHASH_SZ;
-
-        handshake_hash = (byte*)XMALLOC(HSHASH_SZ, ssl->heap,
+    #ifdef WOLFSSL_SMALL_STACK
+        byte* handshake_hash = (byte*)XMALLOC(HSHASH_SZ, ssl->heap,
                                         DYNAMIC_TYPE_DIGEST);
         if (handshake_hash == NULL)
             return MEMORY_E;
+    #else
+        byte handshake_hash[HSHASH_SZ];
+    #endif
 
         ret = BuildTlsHandshakeHash(ssl, handshake_hash, &hashSz);
-        if (ret < 0) {
-            XFREE(handshake_hash, ssl->heap, DYNAMIC_TYPE_DIGEST);
-            return ret;
-        }
-
+        if (ret == 0) {
         ret = _MakeTlsExtendedMasterSecret(
                 ssl->arrays->masterSecret, SECRET_LEN,
@@ -619,8 +699,13 @@
                 IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm,
                 ssl->heap, ssl->devId);
-
+        }
+
+    #ifdef WOLFSSL_SMALL_STACK
         XFREE(handshake_hash, ssl->heap, DYNAMIC_TYPE_DIGEST);
-    } else
-#endif
+#endif
+    }
+    else
+#endif /* HAVE_EXTENDED_MASTER */
+    {
     ret = _MakeTlsMasterSecret(ssl->arrays->masterSecret, SECRET_LEN,
               ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz,
@@ -628,14 +713,45 @@
               IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm,
               ssl->heap, ssl->devId);
-
+    }
     if (ret == 0) {
     #ifdef SHOW_SECRETS
-        int i;
-
-        printf("master secret: ");
-        for (i = 0; i < SECRET_LEN; i++)
-            printf("%02x", ssl->arrays->masterSecret[i]);
-        printf("\n");
-    #endif
+        /* Wireshark Pre-Master-Secret Format:
+         *  CLIENT_RANDOM <clientrandom> <mastersecret>
+         */
+        const char* CLIENT_RANDOM_LABEL = "CLIENT_RANDOM";
+        int i, pmsPos = 0;
+        char pmsBuf[13 + 1 + 64 + 1 + 96 + 1 + 1];
+
+        XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "%s ",
+            CLIENT_RANDOM_LABEL);
+        pmsPos += XSTRLEN(CLIENT_RANDOM_LABEL) + 1;
+        for (i = 0; i < RAN_LEN; i++) {
+            XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "%02x",
+                ssl->arrays->clientRandom[i]);
+            pmsPos += 2;
+        }
+        XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, " ");
+        pmsPos += 1;
+        for (i = 0; i < SECRET_LEN; i++) {
+            XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "%02x",
+                ssl->arrays->masterSecret[i]);
+            pmsPos += 2;
+        }
+        XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "\n");
+        pmsPos += 1;
+
+        /* print master secret */
+        puts(pmsBuf);
+
+        #if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SSLKEYLOGFILE)
+        {
+            FILE* f = XFOPEN(WOLFSSL_SSLKEYLOGFILE_OUTPUT, "a");
+            if (f != XBADFILE) {
+                XFWRITE(pmsBuf, 1, pmsPos, f);
+                XFCLOSE(f);
+            }
+        }
+    #endif
+    #endif /* SHOW_SECRETS */
 
         ret = DeriveTlsKeys(ssl);
@@ -684,5 +800,5 @@
 
 
-static INLINE void GetSEQIncrement(WOLFSSL* ssl, int verify, word32 seq[2])
+static WC_INLINE void GetSEQIncrement(WOLFSSL* ssl, int verify, word32 seq[2])
 {
     if (verify) {
@@ -706,5 +822,5 @@
 
 #ifdef WOLFSSL_DTLS
-static INLINE void DtlsGetSEQ(WOLFSSL* ssl, int order, word32 seq[2])
+static WC_INLINE void DtlsGetSEQ(WOLFSSL* ssl, int order, word32 seq[2])
 {
     if (order == PREV_ORDER) {
@@ -728,5 +844,5 @@
 
 
-static INLINE void WriteSEQ(WOLFSSL* ssl, int verifyOrder, byte* out)
+static WC_INLINE void WriteSEQ(WOLFSSL* ssl, int verifyOrder, byte* out)
 {
     word32 seq[2] = {0, 0};
@@ -813,11 +929,403 @@
 
 
-/* TLS type HMAC */
-int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz,
-              int content, int verify)
-{
-    Hmac hmac;
-    int  ret = 0;
-    byte myInner[WOLFSSL_TLS_HMAC_INNER_SZ];
+#ifndef WOLFSSL_AEAD_ONLY
+#if !defined(WOLFSSL_NO_HASH_RAW) && !defined(HAVE_FIPS) && \
+    !defined(HAVE_SELFTEST)
+
+/* Update the hash in the HMAC.
+ *
+ * hmac  HMAC object.
+ * data  Data to be hashed.
+ * sz    Size of data to hash.
+ * returns 0 on success, otherwise failure.
+ */
+static int Hmac_HashUpdate(Hmac* hmac, const byte* data, word32 sz)
+{
+    int ret = BAD_FUNC_ARG;
+
+    switch (hmac->macType) {
+    #ifndef NO_SHA
+        case WC_SHA:
+            ret = wc_ShaUpdate(&hmac->hash.sha, data, sz);
+            break;
+    #endif /* !NO_SHA */
+
+    #ifndef NO_SHA256
+        case WC_SHA256:
+            ret = wc_Sha256Update(&hmac->hash.sha256, data, sz);
+            break;
+    #endif /* !NO_SHA256 */
+
+    #ifdef WOLFSSL_SHA384
+        case WC_SHA384:
+            ret = wc_Sha384Update(&hmac->hash.sha384, data, sz);
+            break;
+    #endif /* WOLFSSL_SHA384 */
+
+    #ifdef WOLFSSL_SHA512
+        case WC_SHA512:
+            ret = wc_Sha512Update(&hmac->hash.sha512, data, sz);
+            break;
+    #endif /* WOLFSSL_SHA512 */
+    }
+
+    return ret;
+}
+
+/* Finalize the hash but don't put the EOC, padding or length in.
+ *
+ * hmac  HMAC object.
+ * hash  Hash result.
+ * returns 0 on success, otherwise failure.
+ */
+static int Hmac_HashFinalRaw(Hmac* hmac, unsigned char* hash)
+{
+    int ret = BAD_FUNC_ARG;
+
+    switch (hmac->macType) {
+    #ifndef NO_SHA
+        case WC_SHA:
+            ret = wc_ShaFinalRaw(&hmac->hash.sha, hash);
+            break;
+    #endif /* !NO_SHA */
+
+    #ifndef NO_SHA256
+        case WC_SHA256:
+            ret = wc_Sha256FinalRaw(&hmac->hash.sha256, hash);
+            break;
+    #endif /* !NO_SHA256 */
+
+    #ifdef WOLFSSL_SHA384
+        case WC_SHA384:
+            ret = wc_Sha384FinalRaw(&hmac->hash.sha384, hash);
+            break;
+    #endif /* WOLFSSL_SHA384 */
+
+    #ifdef WOLFSSL_SHA512
+        case WC_SHA512:
+            ret = wc_Sha512FinalRaw(&hmac->hash.sha512, hash);
+            break;
+    #endif /* WOLFSSL_SHA512 */
+    }
+
+    return ret;
+}
+
+/* Finalize the HMAC by performing outer hash.
+ *
+ * hmac  HMAC object.
+ * mac   MAC result.
+ * returns 0 on success, otherwise failure.
+ */
+static int Hmac_OuterHash(Hmac* hmac, unsigned char* mac)
+{
+    int ret = BAD_FUNC_ARG;
+    wc_HashAlg hash;
+    enum wc_HashType hashType = (enum wc_HashType)hmac->macType;
+    int digestSz = wc_HashGetDigestSize(hashType);
+    int blockSz = wc_HashGetBlockSize(hashType);
+
+    ret = wc_HashInit(&hash, hashType);
+    if (ret == 0) {
+        ret = wc_HashUpdate(&hash, hashType, (byte*)hmac->opad,
+            blockSz);
+        if (ret == 0)
+            ret = wc_HashUpdate(&hash, hashType, (byte*)hmac->innerHash,
+                digestSz);
+        if (ret == 0)
+            ret = wc_HashFinal(&hash, hashType, mac);
+        wc_HashFree(&hash, hashType);
+    }
+
+    return ret;
+}
+
+/* Calculate the HMAC of the header + message data.
+ * Constant time implementation using wc_Sha*FinalRaw().
+ *
+ * hmac    HMAC object.
+ * digest  MAC result.
+ * in      Message data.
+ * sz      Size of the message data.
+ * header  Constructed record header with length of handshake data.
+ * returns 0 on success, otherwise failure.
+ */
+static int Hmac_UpdateFinal_CT(Hmac* hmac, byte* digest, const byte* in,
+                               word32 sz, byte* header)
+{
+    byte lenBytes[8];
+    int  i, j, k;
+    int  blockBits, blockMask;
+    int  realLen, lastBlockLen, macLen, extraLen, eocIndex;
+    int  blocks, safeBlocks, lenBlock, eocBlock;
+    int  maxLen;
+    int  blockSz, padSz;
+    int  ret;
+    byte extraBlock;
+
+    switch (hmac->macType) {
+    #ifndef NO_SHA
+        case WC_SHA:
+            blockSz = WC_SHA_BLOCK_SIZE;
+            blockBits = 6;
+            macLen = WC_SHA_DIGEST_SIZE;
+            padSz = WC_SHA_BLOCK_SIZE - WC_SHA_PAD_SIZE + 1;
+            break;
+    #endif /* !NO_SHA */
+
+    #ifndef NO_SHA256
+        case WC_SHA256:
+            blockSz = WC_SHA256_BLOCK_SIZE;
+            blockBits = 6;
+            macLen = WC_SHA256_DIGEST_SIZE;
+            padSz = WC_SHA256_BLOCK_SIZE - WC_SHA256_PAD_SIZE + 1;
+            break;
+    #endif /* !NO_SHA256 */
+
+    #ifdef WOLFSSL_SHA384
+        case WC_SHA384:
+            blockSz = WC_SHA384_BLOCK_SIZE;
+            blockBits = 7;
+            macLen = WC_SHA384_DIGEST_SIZE;
+            padSz = WC_SHA384_BLOCK_SIZE - WC_SHA384_PAD_SIZE + 1;
+            break;
+    #endif /* WOLFSSL_SHA384 */
+
+    #ifdef WOLFSSL_SHA512
+        case WC_SHA512:
+            blockSz = WC_SHA512_BLOCK_SIZE;
+            blockBits = 7;
+            macLen = WC_SHA512_DIGEST_SIZE;
+            padSz = WC_SHA512_BLOCK_SIZE - WC_SHA512_PAD_SIZE + 1;
+            break;
+    #endif /* WOLFSSL_SHA512 */
+
+        default:
+            return BAD_FUNC_ARG;
+}
+    blockMask = blockSz - 1;
+
+    /* Size of data to HMAC if padding length byte is zero. */
+    maxLen = WOLFSSL_TLS_HMAC_INNER_SZ + sz - 1 - macLen;
+    /* Complete data (including padding) has block for EOC and/or length. */
+    extraBlock = ctSetLTE((maxLen + padSz) & blockMask, padSz);
+    /* Total number of blocks for data including padding. */
+    blocks = ((maxLen + blockSz - 1) >> blockBits) + extraBlock;
+    /* Up to last 6 blocks can be hashed safely. */
+    safeBlocks = blocks - 6;
+
+    /* Length of message data. */
+    realLen = maxLen - in[sz - 1];
+    /* Number of message bytes in last block. */
+    lastBlockLen = realLen & blockMask;
+    /* Number of padding bytes in last block. */
+    extraLen = ((blockSz * 2 - padSz - lastBlockLen) & blockMask) + 1;
+    /* Number of blocks to create for hash. */
+    lenBlock = (realLen + extraLen) >> blockBits;
+    /* Block containing EOC byte. */
+    eocBlock = realLen >> blockBits;
+    /* Index of EOC byte in block. */
+    eocIndex = realLen & blockMask;
+
+    /* Add length of hmac's ipad to total length. */
+    realLen += blockSz;
+    /* Length as bits - 8 bytes bigendian. */
+    c32toa(realLen >> ((sizeof(word32) * 8) - 3), lenBytes);
+    c32toa(realLen << 3, lenBytes + sizeof(word32));
+
+    ret = Hmac_HashUpdate(hmac, (unsigned char*)hmac->ipad, blockSz);
+    if (ret != 0)
+        return ret;
+
+    XMEMSET(hmac->innerHash, 0, macLen);
+
+    if (safeBlocks > 0) {
+        ret = Hmac_HashUpdate(hmac, header, WOLFSSL_TLS_HMAC_INNER_SZ);
+        if (ret != 0)
+            return ret;
+        ret = Hmac_HashUpdate(hmac, in, safeBlocks * blockSz -
+                                                     WOLFSSL_TLS_HMAC_INNER_SZ);
+        if (ret != 0)
+            return ret;
+    }
+    else
+        safeBlocks = 0;
+
+    XMEMSET(digest, 0, macLen);
+    k = safeBlocks * blockSz;
+    for (i = safeBlocks; i < blocks; i++) {
+        unsigned char hashBlock[WC_MAX_BLOCK_SIZE];
+        unsigned char isEocBlock = ctMaskEq(i, eocBlock);
+        unsigned char isOutBlock = ctMaskEq(i, lenBlock);
+
+        for (j = 0; j < blockSz; j++, k++) {
+            unsigned char atEoc = ctMaskEq(j, eocIndex) & isEocBlock;
+            unsigned char pastEoc = ctMaskGT(j, eocIndex) & isEocBlock;
+            unsigned char b = 0;
+
+            if (k < WOLFSSL_TLS_HMAC_INNER_SZ)
+                b = header[k];
+            else if (k < maxLen)
+                b = in[k - WOLFSSL_TLS_HMAC_INNER_SZ];
+
+            b = ctMaskSel(atEoc, 0x80, b);
+            b &= (unsigned char)~(word32)pastEoc;
+            b &= ((unsigned char)~(word32)isOutBlock) | isEocBlock;
+
+            if (j >= blockSz - 8) {
+                b = ctMaskSel(isOutBlock, lenBytes[j - (blockSz - 8)], b);
+            }
+
+            hashBlock[j] = b;
+        }
+
+        ret = Hmac_HashUpdate(hmac, hashBlock, blockSz);
+        if (ret != 0)
+            return ret;
+        ret = Hmac_HashFinalRaw(hmac, hashBlock);
+        if (ret != 0)
+            return ret;
+        for (j = 0; j < macLen; j++)
+            ((unsigned char*)hmac->innerHash)[j] |= hashBlock[j] & isOutBlock;
+    }
+
+    ret = Hmac_OuterHash(hmac, digest);
+
+    return ret;
+}
+
+#endif
+
+#if defined(WOLFSSL_NO_HASH_RAW) || defined(HAVE_FIPS) || \
+    defined(HAVE_SELFTEST) || defined(HAVE_BLAKE2)
+
+/* Calculate the HMAC of the header + message data.
+ * Constant time implementation using normal hashing operations.
+ * Update-Final need to be constant time.
+ *
+ * hmac    HMAC object.
+ * digest  MAC result.
+ * in      Message data.
+ * sz      Size of the message data.
+ * header  Constructed record header with length of handshake data.
+ * returns 0 on success, otherwise failure.
+ */
+static int Hmac_UpdateFinal(Hmac* hmac, byte* digest, const byte* in,
+                            word32 sz, byte* header)
+{
+    byte       dummy[WC_MAX_BLOCK_SIZE] = {0};
+    int        ret;
+    word32     msgSz, blockSz, macSz, padSz, maxSz, realSz;
+    word32     currSz, offset;
+    int        msgBlocks, blocks, blockBits;
+    int        i;
+
+    switch (hmac->macType) {
+    #ifndef NO_SHA
+        case WC_SHA:
+            blockSz = WC_SHA_BLOCK_SIZE;
+            blockBits = 6;
+            macSz = WC_SHA_DIGEST_SIZE;
+            padSz = WC_SHA_BLOCK_SIZE - WC_SHA_PAD_SIZE + 1;
+            break;
+    #endif /* !NO_SHA */
+
+    #ifndef NO_SHA256
+        case WC_SHA256:
+            blockSz = WC_SHA256_BLOCK_SIZE;
+            blockBits = 6;
+            macSz = WC_SHA256_DIGEST_SIZE;
+            padSz = WC_SHA256_BLOCK_SIZE - WC_SHA256_PAD_SIZE + 1;
+            break;
+    #endif /* !NO_SHA256 */
+
+    #ifdef WOLFSSL_SHA384
+        case WC_SHA384:
+            blockSz = WC_SHA384_BLOCK_SIZE;
+            blockBits = 7;
+            macSz = WC_SHA384_DIGEST_SIZE;
+            padSz = WC_SHA384_BLOCK_SIZE - WC_SHA384_PAD_SIZE + 1;
+            break;
+    #endif /* WOLFSSL_SHA384 */
+
+    #ifdef WOLFSSL_SHA512
+        case WC_SHA512:
+            blockSz = WC_SHA512_BLOCK_SIZE;
+            blockBits = 7;
+            macSz = WC_SHA512_DIGEST_SIZE;
+            padSz = WC_SHA512_BLOCK_SIZE - WC_SHA512_PAD_SIZE + 1;
+            break;
+    #endif /* WOLFSSL_SHA512 */
+
+    #ifdef HAVE_BLAKE2
+        case WC_HASH_TYPE_BLAKE2B:
+            blockSz = BLAKE2B_BLOCKBYTES;
+            blockBits = 7;
+            macSz = BLAKE2B_256;
+            padSz = 0;
+            break;
+    #endif /* HAVE_BLAK2 */
+
+        default:
+            return BAD_FUNC_ARG;
+    }
+
+    msgSz = sz - (1 + in[sz - 1] + macSz);
+    /* Make negative result 0 */
+    msgSz &= ~(0 - (msgSz >> 31));
+    realSz = WOLFSSL_TLS_HMAC_INNER_SZ + msgSz;
+    maxSz = WOLFSSL_TLS_HMAC_INNER_SZ + (sz - 1) - macSz;
+
+    /* Calculate #blocks processed in HMAC for max and real data. */
+    blocks      = maxSz >> blockBits;
+    blocks     += ((maxSz + padSz) % blockSz) < padSz;
+    msgBlocks   = realSz >> blockBits;
+    /* #Extra blocks to process. */
+    blocks -= msgBlocks + (((realSz + padSz) % blockSz) < padSz);
+    /* Calculate whole blocks. */
+    msgBlocks--;
+
+    ret = wc_HmacUpdate(hmac, header, WOLFSSL_TLS_HMAC_INNER_SZ);
+    if (ret == 0) {
+        /* Fill the rest of the block with any available data. */
+        currSz = ctMaskLT(msgSz, blockSz) & msgSz;
+        currSz |= ctMaskGTE(msgSz, blockSz) & blockSz;
+        currSz -= WOLFSSL_TLS_HMAC_INNER_SZ;
+        currSz &= ~(0 - (currSz >> 31));
+        ret = wc_HmacUpdate(hmac, in, currSz);
+        offset = currSz;
+    }
+    if (ret == 0) {
+        /* Do the hash operations on a block basis. */
+        for (i = 0; i < msgBlocks; i++, offset += blockSz) {
+            ret = wc_HmacUpdate(hmac, in + offset, blockSz);
+            if (ret != 0)
+                break;
+        }
+    }
+    if (ret == 0)
+        ret = wc_HmacUpdate(hmac, in + offset, msgSz - offset);
+    if (ret == 0)
+        ret = wc_HmacFinal(hmac, digest);
+    if (ret == 0) {
+        /* Do the dummy hash operations. Do at least one. */
+        for (i = 0; i < blocks + 1; i++) {
+            ret = wc_HmacUpdate(hmac, dummy, blockSz);
+            if (ret != 0)
+                break;
+        }
+    }
+
+    return ret;
+}
+
+#endif
+
+int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, int padSz,
+             int content, int verify)
+{
+    Hmac   hmac;
+    byte   myInner[WOLFSSL_TLS_HMAC_INNER_SZ];
+    int    ret = 0;
 
     if (ssl == NULL)
@@ -825,6 +1333,14 @@
 
 #ifdef HAVE_FUZZER
-    if (ssl->fuzzerCb)
-        ssl->fuzzerCb(ssl, in, sz, FUZZ_HMAC, ssl->fuzzerCtx);
+    /* Fuzz "in" buffer with sz to be used in HMAC algorithm */
+    if (ssl->fuzzerCb) {
+        if (verify && padSz >= 0) {
+            ssl->fuzzerCb(ssl, in, sz + ssl->specs.hash_size + padSz + 1,
+                FUZZ_HMAC, ssl->fuzzerCtx);
+        }
+        else {
+            ssl->fuzzerCb(ssl, in, sz, FUZZ_HMAC, ssl->fuzzerCtx);
+        }
+}
 #endif
 
@@ -836,16 +1352,46 @@
 
     ret = wc_HmacSetKey(&hmac, wolfSSL_GetHmacType(ssl),
-                     wolfSSL_GetMacSecret(ssl, verify), ssl->specs.hash_size);
+                                              wolfSSL_GetMacSecret(ssl, verify),
+                                              ssl->specs.hash_size);
     if (ret == 0) {
-        ret = wc_HmacUpdate(&hmac, myInner, sizeof(myInner));
-        if (ret == 0)
-            ret = wc_HmacUpdate(&hmac, in, sz);                    /* content */
-        if (ret == 0)
-            ret = wc_HmacFinal(&hmac, digest);
-    }
+        /* Constant time verification required. */
+        if (verify && padSz >= 0) {
+#if !defined(WOLFSSL_NO_HASH_RAW) && !defined(HAVE_FIPS) && \
+    !defined(HAVE_SELFTEST)
+    #ifdef HAVE_BLAKE2
+            if (wolfSSL_GetHmacType(ssl) == WC_HASH_TYPE_BLAKE2B) {
+                ret = Hmac_UpdateFinal(&hmac, digest, in, sz +
+                                               ssl->specs.hash_size + padSz + 1,
+                                               myInner);
+            }
+            else
+#endif
+            {
+                ret = Hmac_UpdateFinal_CT(&hmac, digest, in, sz +
+                                               ssl->specs.hash_size + padSz + 1,
+                                               myInner);
+            }
+#else
+            ret = Hmac_UpdateFinal(&hmac, digest, in, sz +
+                                               ssl->specs.hash_size + padSz + 1,
+                                               myInner);
+#endif
+        }
+        else {
+            ret = wc_HmacUpdate(&hmac, myInner, sizeof(myInner));
+            if (ret == 0)
+                ret = wc_HmacUpdate(&hmac, in, sz);                /* content */
+            if (ret == 0)
+                ret = wc_HmacFinal(&hmac, digest);
+        }
+    }
+
     wc_HmacFree(&hmac);
 
     return ret;
 }
+#endif /* WOLFSSL_AEAD_ONLY */
+
+#endif /* !WOLFSSL_NO_TLS12 */
 
 #ifdef HAVE_TLS_EXTENSIONS
@@ -878,5 +1424,5 @@
  *   'remapped' extension type.
  */
-static INLINE word16 TLSX_ToSemaphore(word16 type)
+static WC_INLINE word16 TLSX_ToSemaphore(word16 type)
 {
     switch (type) {
@@ -918,4 +1464,6 @@
     TLSX* extension = (TLSX*)XMALLOC(sizeof(TLSX), heap, DYNAMIC_TYPE_TLSX);
 
+    (void)heap;
+
     if (extension) {
         extension->type = type;
@@ -953,6 +1501,7 @@
             TLSX_FreeAll(next, heap);
 
-            /* there is no way to occur more than */
-            /* two extensions of the same type.   */
+            /* there is no way to occur more than
+             * two extensions of the same type.
+             */
             break;
         }
@@ -962,5 +1511,32 @@
 }
 
-#ifndef NO_WOLFSSL_SERVER
+#ifndef NO_WOLFSSL_CLIENT
+
+int TLSX_CheckUnsupportedExtension(WOLFSSL* ssl, TLSX_Type type);
+
+int TLSX_CheckUnsupportedExtension(WOLFSSL* ssl, TLSX_Type type)
+{
+    TLSX *extension = TLSX_Find(ssl->extensions, type);
+
+    if (!extension)
+        extension = TLSX_Find(ssl->ctx->extensions, type);
+
+    return extension == NULL;
+}
+
+int TLSX_HandleUnsupportedExtension(WOLFSSL* ssl);
+
+int TLSX_HandleUnsupportedExtension(WOLFSSL* ssl)
+{
+    SendAlert(ssl, alert_fatal, unsupported_extension);
+    return UNSUPPORTED_EXTENSION;
+}
+
+#else
+
+#define TLSX_CheckUnsupportedExtension(ssl, type) 0
+#define TLSX_HandleUnsupportedExtension(ssl) 0
+
+#endif
 
 /** Mark an extension to be sent back to the client. */
@@ -969,11 +1545,9 @@
 void TLSX_SetResponse(WOLFSSL* ssl, TLSX_Type type)
 {
-    TLSX *ext = TLSX_Find(ssl->extensions, type);
-
-    if (ext)
-        ext->resp = 1;
-}
-
-#endif
+    TLSX *extension = TLSX_Find(ssl->extensions, type);
+
+    if (extension)
+        extension->resp = 1;
+}
 
 /******************************************************************************/
@@ -1153,5 +1727,5 @@
                                                TLSX_APPLICATION_LAYER_PROTOCOL);
 
-#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
     if (ssl->alpnSelect != NULL) {
         const byte* out;
@@ -1173,7 +1747,6 @@
 
     if (extension == NULL || extension->data == NULL) {
-        WOLFSSL_MSG("No ALPN extensions not used or bad");
-        return isRequest ? 0             /* not using ALPN */
-                         : BUFFER_ERROR; /* unexpected ALPN response */
+        return isRequest ? 0
+                         : TLSX_HandleUnsupportedExtension(ssl);
     }
 
@@ -1382,5 +1955,5 @@
                 if (sni->data.host_name) {
                     XSTRNCPY(sni->data.host_name, (const char*)data, size);
-                    sni->data.host_name[size] = 0;
+                    sni->data.host_name[size] = '\0';
                 } else {
                     XFREE(sni, heap, DYNAMIC_TYPE_TLSX);
@@ -1476,6 +2049,4 @@
 }
 
-#ifndef NO_WOLFSSL_SERVER
-
 /** Finds a SNI object in the provided list. */
 static SNI* TLSX_SNI_Find(SNI *list, byte type)
@@ -1489,5 +2060,4 @@
 }
 
-
 /** Sets the status of a SNI object. */
 static void TLSX_SNI_SetStatus(TLSX* extensions, byte type, byte status)
@@ -1511,6 +2081,4 @@
     return 0;
 }
-
-#endif /* NO_WOLFSSL_SERVER */
 
 /** Parses a buffer of SNI extensions. */
@@ -1529,25 +2097,42 @@
         extension = TLSX_Find(ssl->ctx->extensions, TLSX_SERVER_NAME);
 
-    (void)isRequest;
-    (void)input;
-
+    if (!isRequest) {
+        #ifndef NO_WOLFSSL_CLIENT
+            if (!extension || !extension->data)
+                return TLSX_HandleUnsupportedExtension(ssl);
+
+            if (length > 0)
+                return BUFFER_ERROR; /* SNI response MUST be empty. */
+
+            /* This call enables wolfSSL_SNI_GetRequest() to be called in the
+             * client side to fetch the used SNI. It will only work if the SNI
+             * was set at the SSL object level. Right now we only support one
+             * name type, WOLFSSL_SNI_HOST_NAME, but in the future, the
+             * inclusion of other name types will turn this method inaccurate,
+             * as the extension response doesn't contains information of which
+             * name was accepted.
+             */
+            TLSX_SNI_SetStatus(ssl->extensions, WOLFSSL_SNI_HOST_NAME,
+                                                        WOLFSSL_SNI_REAL_MATCH);
+
+            return 0;
+        #endif
+    }
+
+#ifndef NO_WOLFSSL_SERVER
     if (!extension || !extension->data) {
 #if defined(WOLFSSL_ALWAYS_KEEP_SNI) && !defined(NO_WOLFSSL_SERVER)
         /* This will keep SNI even though TLSX_UseSNI has not been called.
          * Enable it so that the received sni is available to functions
-         * that use a custom callback when SNI is received */
+            * that use a custom callback when SNI is received.
+            */
+
         cacheOnly = 1;
         WOLFSSL_MSG("Forcing SSL object to store SNI parameter");
 #else
-        return isRequest ? 0             /* not using SNI.           */
-                         : BUFFER_ERROR; /* unexpected SNI response. */
-#endif
-    }
-
-    if (!isRequest)
-        return length ? BUFFER_ERROR /* SNI response MUST be empty. */
-                      : 0;           /* nothing else to do.         */
-
-#ifndef NO_WOLFSSL_SERVER
+            /* Skipping, SNI not enabled at server side. */
+            return 0;
+#endif
+    }
 
     if (OPAQUE16_LEN > length)
@@ -1580,4 +2165,6 @@
             case WOLFSSL_SNI_HOST_NAME: {
                 int matchStat;
+                byte matched;
+
 #ifdef WOLFSSL_TLS13
                 /* Don't process the second ClientHello SNI extension if there
@@ -1587,7 +2174,7 @@
                     break;
 #endif
-                byte matched = cacheOnly ||
-                            ((XSTRLEN(sni->data.host_name) == size)
-                            && (XSTRNCMP(sni->data.host_name,
+                matched = cacheOnly ||
+                    ((XSTRLEN(sni->data.host_name) == size) &&
+                    (XSTRNCMP(sni->data.host_name,
                                        (const char*)input + offset, size) == 0));
 
@@ -1610,5 +2197,5 @@
                     }
 
-                    TLSX_SNI_SetStatus(ssl->extensions, type, matchStat);
+                    TLSX_SNI_SetStatus(ssl->extensions, type, (byte)matchStat);
 
                     if(!cacheOnly)
@@ -1624,5 +2211,6 @@
         }
     }
-
+#else
+    (void)input;
 #endif
 
@@ -1690,4 +2278,5 @@
     if (!extension) {
         int ret = TLSX_Push(extensions, TLSX_SERVER_NAME, (void*)sni, heap);
+
         if (ret != 0) {
             TLSX_SNI_Free(sni, heap);
@@ -1708,6 +2297,7 @@
                 TLSX_SNI_Free(next, heap);
 
-                /* there is no way to occur more than */
-                /* two SNIs of the same type.         */
+                /* there is no way to occur more than
+                 * two SNIs of the same type.
+                 */
                 break;
             }
@@ -1934,10 +2524,17 @@
                                                                  byte isRequest)
 {
-    (void)isRequest;
-
     if (length != ENUM_LEN)
         return BUFFER_ERROR;
 
+#ifdef WOLFSSL_OLD_UNSUPPORTED_EXTENSION
+    (void) isRequest;
+#else
+    if (!isRequest)
+        if (TLSX_CheckUnsupportedExtension(ssl, TLSX_MAX_FRAGMENT_LENGTH))
+            return TLSX_HandleUnsupportedExtension(ssl);
+#endif
+
     switch (*input) {
+        case WOLFSSL_MFL_2_8 : ssl->max_fragment =  256; break;
         case WOLFSSL_MFL_2_9 : ssl->max_fragment =  512; break;
         case WOLFSSL_MFL_2_10: ssl->max_fragment = 1024; break;
@@ -1954,7 +2551,8 @@
 #ifndef NO_WOLFSSL_SERVER
     if (isRequest) {
-        int r = TLSX_UseMaxFragment(&ssl->extensions, *input, ssl->heap);
-
-        if (r != WOLFSSL_SUCCESS) return r; /* throw error */
+        int ret = TLSX_UseMaxFragment(&ssl->extensions, *input, ssl->heap);
+
+        if (ret != WOLFSSL_SUCCESS)
+            return ret; /* throw error */
 
         TLSX_SetResponse(ssl, TLSX_MAX_FRAGMENT_LENGTH);
@@ -1970,18 +2568,15 @@
     int   ret  = 0;
 
-    if (extensions == NULL)
+    if (extensions == NULL || mfl < WOLFSSL_MFL_MIN || mfl > WOLFSSL_MFL_MAX)
         return BAD_FUNC_ARG;
 
-    if (mfl < WOLFSSL_MFL_2_9 || WOLFSSL_MFL_2_13 < mfl)
-        return BAD_FUNC_ARG;
-
-    if ((data = (byte*)XMALLOC(ENUM_LEN, heap, DYNAMIC_TYPE_TLSX)) == NULL)
+    data = (byte*)XMALLOC(ENUM_LEN, heap, DYNAMIC_TYPE_TLSX);
+    if (data == NULL)
         return MEMORY_E;
 
     data[0] = mfl;
 
-    /* push new MFL extension. */
-    if ((ret = TLSX_Push(extensions, TLSX_MAX_FRAGMENT_LENGTH, data, heap))
-                                                                         != 0) {
+    ret = TLSX_Push(extensions, TLSX_MAX_FRAGMENT_LENGTH, data, heap);
+    if (ret != 0) {
         XFREE(data, heap, DYNAMIC_TYPE_TLSX);
         return ret;
@@ -2015,19 +2610,23 @@
                                                                  byte isRequest)
 {
-    (void)isRequest;
-
     if (length != 0 || input == NULL)
         return BUFFER_ERROR;
 
+    if (!isRequest) {
+    #ifndef WOLFSSL_OLD_UNSUPPORTED_EXTENSION
+        if (TLSX_CheckUnsupportedExtension(ssl, TLSX_TRUNCATED_HMAC))
+            return TLSX_HandleUnsupportedExtension(ssl);
+    #endif
+    }
+    else {
 #ifndef NO_WOLFSSL_SERVER
-    if (isRequest) {
-        int r = TLSX_UseTruncatedHMAC(&ssl->extensions, ssl->heap);
-
-        if (r != WOLFSSL_SUCCESS)
-            return r; /* throw error */
+            int ret = TLSX_UseTruncatedHMAC(&ssl->extensions, ssl->heap);
+
+            if (ret != WOLFSSL_SUCCESS)
+                return ret; /* throw error */
 
         TLSX_SetResponse(ssl, TLSX_TRUNCATED_HMAC);
-    }
-#endif
+#endif
+    }
 
     ssl->truncated_hmac = 1;
@@ -2043,5 +2642,6 @@
         return BAD_FUNC_ARG;
 
-    if ((ret = TLSX_Push(extensions, TLSX_TRUNCATED_HMAC, NULL, heap)) != 0)
+    ret = TLSX_Push(extensions, TLSX_TRUNCATED_HMAC, NULL, heap);
+    if (ret != 0)
         return ret;
 
@@ -2092,4 +2692,15 @@
             break;
         }
+    }
+#endif
+#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER)
+    if (!isRequest && csr->ssl->options.tls1_3) {
+        if (csr->response.buffer == NULL) {
+            OcspRequest* request = &csr->request.ocsp;
+            int ret = CreateOcspResponse(csr->ssl, &request, &csr->response);
+            if (ret < 0)
+                return ret;
+        }
+        return OPAQUE8_LEN + OPAQUE24_LEN + csr->response.length;
     }
 #endif
@@ -2134,4 +2745,15 @@
     }
 #endif
+#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER)
+    if (!isRequest && csr->ssl->options.tls1_3) {
+        word16 offset = 0;
+        output[offset++] = csr->status_type;
+        c32to24(csr->response.length, output + offset);
+        offset += OPAQUE24_LEN;
+        XMEMCPY(output + offset, csr->response.buffer, csr->response.length);
+        offset += csr->response.length;
+        return offset;
+    }
+#endif
 
     return 0;
@@ -2157,11 +2779,11 @@
             csr = extension ? (CertificateStatusRequest*)extension->data : NULL;
 
-            if (!csr)
-                return BUFFER_ERROR; /* unexpected extension */
+            if (!csr) /* unexpected extension */
+                return TLSX_HandleUnsupportedExtension(ssl);
 
             /* enable extension at ssl level */
             ret = TLSX_UseCertificateStatusRequest(&ssl->extensions,
-                                     csr->status_type, csr->options, ssl->heap,
-                                     ssl->devId);
+                                     csr->status_type, csr->options, ssl,
+                                     ssl->heap, ssl->devId);
             if (ret != WOLFSSL_SUCCESS)
                 return ret;
@@ -2186,5 +2808,32 @@
         ssl->status_request = 1;
 
-        return length ? BUFFER_ERROR : 0; /* extension_data MUST be empty. */
+    #ifdef WOLFSSL_TLS13
+        if (ssl->options.tls1_3) {
+            word32       resp_length;
+            word32       offset = 0;
+            ret = 0;
+            if (OPAQUE8_LEN + OPAQUE24_LEN > length)
+                ret = BUFFER_ERROR;
+            if (ret == 0 && input[offset++] != WOLFSSL_CSR_OCSP)
+                ret = BAD_CERTIFICATE_STATUS_ERROR;
+            if (ret == 0) {
+                c24to32(input + offset, &resp_length);
+                offset += OPAQUE24_LEN;
+                if (offset + resp_length != length)
+                    ret = BUFFER_ERROR;
+            }
+            if (ret == 0) {
+                csr->response.buffer = input + offset;
+                csr->response.length = resp_length;
+            }
+
+            return ret;
+        }
+        else
+    #endif
+        {
+            /* extension_data MUST be empty. */
+            return length ? BUFFER_ERROR : 0;
+        }
 #endif
     }
@@ -2239,5 +2888,5 @@
         /* accept the first good status_type and return */
         ret = TLSX_UseCertificateStatusRequest(&ssl->extensions, status_type,
-                                                      0, ssl->heap, ssl->devId);
+                                                 0, ssl, ssl->heap, ssl->devId);
         if (ret != WOLFSSL_SUCCESS)
             return ret; /* throw error */
@@ -2245,5 +2894,4 @@
         TLSX_SetResponse(ssl, TLSX_STATUS_REQUEST);
         ssl->status_request = status_type;
-
 #endif
     }
@@ -2323,5 +2971,6 @@
 
 int TLSX_UseCertificateStatusRequest(TLSX** extensions, byte status_type,
-                                           byte options, void* heap, int devId)
+                                         byte options, WOLFSSL* ssl, void* heap,
+                                                                      int devId)
 {
     CertificateStatusRequest* csr = NULL;
@@ -2340,4 +2989,5 @@
     csr->status_type = status_type;
     csr->options     = options;
+    csr->ssl         = ssl;
 
     switch (csr->status_type) {
@@ -2519,11 +3169,12 @@
                         (CertificateStatusRequestItemV2*)extension->data : NULL;
 
-            if (!csr2)
-                return BUFFER_ERROR; /* unexpected extension */
+            if (!csr2) /* unexpected extension */
+                return TLSX_HandleUnsupportedExtension(ssl);
 
             /* enable extension at ssl level */
             for (; csr2; csr2 = csr2->next) {
                 ret = TLSX_UseCertificateStatusRequestV2(&ssl->extensions,
-                       csr2->status_type, csr2->options, ssl->heap, ssl->devId);
+                                    csr2->status_type, csr2->options, ssl->heap,
+                                                                    ssl->devId);
                 if (ret != WOLFSSL_SUCCESS)
                     return ret;
@@ -2566,4 +3217,8 @@
 
         /* list size */
+        if (offset + OPAQUE16_LEN >= length) {
+            return BUFFER_E;
+        }
+
         ato16(input + offset, &request_length);
         offset += OPAQUE16_LEN;
@@ -2819,5 +3474,5 @@
 #ifdef HAVE_SUPPORTED_CURVES
 
-#ifndef HAVE_ECC
+#if !defined(HAVE_ECC) && !defined(HAVE_CURVE25519) && !defined(WOLFSSL_TLS13)
 #error Elliptic Curves Extension requires Elliptic Curve Cryptography. \
        Use --enable-ecc in the configure script or define HAVE_ECC.
@@ -2829,4 +3484,6 @@
     if (curve == NULL)
         return BAD_FUNC_ARG;
+
+    (void)heap;
 
     *curve = (SupportedCurve*)XMALLOC(sizeof(SupportedCurve), heap,
@@ -2846,4 +3503,6 @@
         return BAD_FUNC_ARG;
 
+    (void)heap;
+
     *point = (PointFormat*)XMALLOC(sizeof(PointFormat), heap,
                                                              DYNAMIC_TYPE_TLSX);
@@ -2882,39 +3541,45 @@
                                                                      void* heap)
 {
-    if (list == NULL)
-        return BAD_FUNC_ARG;
-
-    while (1) {
-        if (list->name == name)
-            return 0; /* curve alreay in use */
-
-        if (list->next == NULL)
-            return TLSX_SupportedCurve_New(&list->next, name, heap);
+    int ret = BAD_FUNC_ARG;
+
+    while (list) {
+        if (list->name == name) {
+            ret = 0; /* curve alreay in use */
+            break;
+        }
+
+        if (list->next == NULL) {
+            ret = TLSX_SupportedCurve_New(&list->next, name, heap);
+            break;
+        }
 
         list = list->next;
     }
 
-    return 0;
+    return ret;
 }
 
 static int TLSX_PointFormat_Append(PointFormat* list, byte format, void* heap)
 {
-    if (list == NULL)
-        return BAD_FUNC_ARG;
-
-    while (1) {
-        if (list->format == format)
-            return 0; /* format already in use */
-
-        if (list->next == NULL)
-            return TLSX_PointFormat_New(&list->next, format, heap);
+    int ret = BAD_FUNC_ARG;
+
+    while (list) {
+        if (list->format == format) {
+            ret = 0; /* format already in use */
+            break;
+        }
+
+        if (list->next == NULL) {
+            ret = TLSX_PointFormat_New(&list->next, format, heap);
+            break;
+        }
 
         list = list->next;
     }
 
-    return 0;
-}
-
-#ifndef NO_WOLFSSL_CLIENT
+    return ret;
+}
+
+#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_CLIENT)
 
 static void TLSX_SupportedCurve_ValidateRequest(WOLFSSL* ssl, byte* semaphore)
@@ -2947,4 +3612,5 @@
 
 #endif
+
 #ifndef NO_WOLFSSL_SERVER
 
@@ -3019,10 +3685,11 @@
     }
 
-    output[0] = offset - ENUM_LEN;
+    output[0] = (byte)(offset - ENUM_LEN);
 
     return offset;
 }
 
-#ifndef NO_WOLFSSL_SERVER
+#if !defined(NO_WOLFSSL_SERVER) || (defined(WOLFSSL_TLS13) && \
+                                         !defined(WOLFSSL_NO_SERVER_GROUPS_EXT))
 
 static int TLSX_SupportedCurve_Parse(WOLFSSL* ssl, byte* input, word16 length,
@@ -3033,5 +3700,11 @@
     int ret;
 
-    (void) isRequest; /* shut up compiler! */
+    if(!isRequest && !IsAtLeastTLSv1_3(ssl->version)) {
+#ifdef WOLFSSL_ALLOW_SERVER_SC_EXT
+        return 0;
+#else
+        return BUFFER_ERROR; /* servers doesn't send this extension. */
+#endif
+    }
 
     if (OPAQUE16_LEN > length || length % OPAQUE16_LEN)
@@ -3044,9 +3717,35 @@
         return BUFFER_ERROR;
 
-    for (offset = OPAQUE16_LEN; offset < length; offset += OPAQUE16_LEN) {
+    offset = OPAQUE16_LEN;
+    if (offset == length)
+        return 0;
+
+#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)
+    if (!isRequest) {
+        TLSX* extension;
+        SupportedCurve* curve;
+
+        extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS);
+        if (extension != NULL) {
+            /* Replace client list with server list of supported groups. */
+            curve = (SupportedCurve*)extension->data;
+            extension->data = NULL;
+            TLSX_SupportedCurve_FreeAll(curve, ssl->heap);
+
         ato16(input + offset, &name);
+            offset += OPAQUE16_LEN;
+
+            ret = TLSX_SupportedCurve_New(&curve, name, ssl->heap);
+            if (ret != 0)
+                return ret; /* throw error */
+            extension->data = (void*)curve;
+        }
+    }
+#endif
+
+    for (; offset < length; offset += OPAQUE16_LEN) {
+        ato16(input + offset, &name);
 
         ret = TLSX_UseSupportedCurve(&ssl->extensions, name, ssl->heap);
-
         if (ret != WOLFSSL_SUCCESS)
             return ret; /* throw error */
@@ -3055,4 +3754,90 @@
     return 0;
 }
+
+#endif
+
+#if !defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_TLS13) && \
+                                          !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)
+
+/* Checks the priority of the groups on the server and set the supported groups
+ * response if there is a group not advertised by the client that is preferred.
+ *
+ * ssl  SSL/TLS object.
+ * returns 0 on success, otherwise an error.
+ */
+int TLSX_SupportedCurve_CheckPriority(WOLFSSL* ssl)
+{
+    int ret;
+    TLSX* extension;
+    TLSX* priority = NULL;
+    TLSX* ext = NULL;
+    word16 name;
+    SupportedCurve* curve;
+
+    extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS);
+    /* May be doing PSK with no key exchange. */
+    if (extension == NULL)
+        return 0;
+
+    if ((ret = TLSX_PopulateSupportedGroups(ssl, &priority)) != WOLFSSL_SUCCESS)
+        return ret;
+
+    ext = TLSX_Find(priority, TLSX_SUPPORTED_GROUPS);
+    curve = (SupportedCurve*)ext->data;
+    name = curve->name;
+
+    curve = (SupportedCurve*)extension->data;
+    while (curve != NULL) {
+        if (curve->name == name)
+            break;
+        curve = curve->next;
+    }
+
+    if (curve == NULL) {
+        /* Couldn't find the preferred group in client list. */
+        extension->resp = 1;
+
+        /* Send server list back and free client list. */
+        curve = (SupportedCurve*)extension->data;
+        extension->data = ext->data;
+        ext->data = curve;
+    }
+
+    TLSX_FreeAll(priority, ssl->heap);
+
+    return 0;
+}
+
+#endif
+
+#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)
+/* Return the preferred group.
+ *
+ * ssl             SSL/TLS object.
+ * checkSupported  Whether to check for the first supported group.
+ * returns BAD_FUNC_ARG if no group found, otherwise the group.
+ */
+int TLSX_SupportedCurve_Preferred(WOLFSSL* ssl, int checkSupported)
+{
+    TLSX* extension;
+    SupportedCurve* curve;
+
+    extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS);
+    if (extension == NULL)
+        return BAD_FUNC_ARG;
+
+    curve = (SupportedCurve*)extension->data;
+    while (curve != NULL) {
+        if (!checkSupported || TLSX_KeyShare_IsSupported(curve->name))
+            return curve->name;
+        curve = curve->next;
+    }
+
+    return BAD_FUNC_ARG;
+}
+
+#endif
+
+#ifndef NO_WOLFSSL_SERVER
 
 static int TLSX_PointFormat_Parse(WOLFSSL* ssl, byte* input, word16 length,
@@ -3078,4 +3863,5 @@
 }
 
+#if defined(HAVE_ECC) || defined(HAVE_CURVE25519)
 int TLSX_ValidateSupportedCurves(WOLFSSL* ssl, byte first, byte second) {
     TLSX*          extension = (first == ECC_BYTE || first == CHACHA_BYTE)
@@ -3111,4 +3897,5 @@
         /* find supported curve */
         switch (curve->name) {
+#ifdef HAVE_ECC
     #if defined(HAVE_ECC160) || defined(HAVE_ALL_CURVES)
         #ifndef NO_ECC_SECP
@@ -3166,4 +3953,6 @@
                 break;
         #endif /* !NO_ECC_SECP */
+    #endif /* !NO_ECC256 || HAVE_ALL_CURVES */
+#endif
         #ifdef HAVE_CURVE25519
             case WOLFSSL_ECC_X25519:
@@ -3177,4 +3966,6 @@
                 break;
         #endif /* HAVE_CURVE25519 */
+#ifdef HAVE_ECC
+    #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES)
         #ifdef HAVE_ECC_KOBLITZ
             case WOLFSSL_ECC_SECP256K1:
@@ -3220,7 +4011,9 @@
         #endif /* !NO_ECC_SECP */
     #endif
+#endif
             default: continue; /* unsupported curve */
         }
 
+    #ifdef HAVE_ECC
         /* Set default Oid */
         if (defOid == 0 && ssl->eccTempKeySz <= octets && defSz > octets) {
@@ -3229,4 +4022,5 @@
         }
 
+        /* The eccTempKeySz is the preferred ephemeral key size */
         if (currOid == 0 && ssl->eccTempKeySz == octets)
             currOid = oid;
@@ -3235,4 +4029,17 @@
             nextSz  = octets;
         }
+    #else
+        if (defOid == 0 && defSz > octets) {
+            defOid = oid;
+            defSz = octets;
+        }
+
+        if (currOid == 0)
+            currOid = oid;
+        if (nextOid == 0 || nextSz > octets) {
+            nextOid = oid;
+            nextSz  = octets;
+        }
+    #endif
 
         if (first == ECC_BYTE) {
@@ -3346,5 +4153,10 @@
 
     /* Choose the default if it is at the required strength. */
-    if (ssl->ecdhCurveOID == 0 && defSz == ssl->eccTempKeySz) {
+#ifdef HAVE_ECC
+    if (ssl->ecdhCurveOID == 0 && defSz == ssl->eccTempKeySz)
+#else
+    if (ssl->ecdhCurveOID == 0)
+#endif
+    {
         key = 1;
         ssl->ecdhCurveOID = defOid;
@@ -3367,4 +4179,5 @@
     return sig && key;
 }
+#endif
 
 #endif /* NO_WOLFSSL_SERVER */
@@ -3374,5 +4187,5 @@
     TLSX* extension = NULL;
     SupportedCurve* curve = NULL;
-    int ret = 0;
+    int ret;
 
     if (extensions == NULL)
@@ -3399,7 +4212,5 @@
     }
 
-    return (TLSX_Find(*extensions, TLSX_EC_POINT_FORMATS) == NULL)
-        ? TLSX_UsePointFormat(extensions, WOLFSSL_EC_PF_UNCOMPRESSED, heap)
-        : WOLFSSL_SUCCESS;
+    return WOLFSSL_SUCCESS;
 }
 
@@ -3447,5 +4258,6 @@
 #endif
 
-#ifndef NO_WOLFSSL_SERVER
+#if !defined(NO_WOLFSSL_SERVER) || (defined(WOLFSSL_TLS13) && \
+                                         !defined(WOLFSSL_NO_SERVER_GROUPS_EXT))
 #define EC_PARSE TLSX_SupportedCurve_Parse
 #else
@@ -3496,5 +4308,5 @@
 
     /* data will be NULL for HAVE_SERVER_RENEGOTIATION_INFO only */
-    if (data && data->enabled) {
+    if (data && data->enabled && data->verifySet) {
         /* client sends client_verify_data only */
         length += TLS_FINISHED_SZ;
@@ -3512,6 +4324,5 @@
 {
     word16 offset = OPAQUE8_LEN; /* RenegotiationInfo length */
-
-    if (data && data->enabled) {
+    if (data && data->enabled && data->verifySet) {
         /* client sends client_verify_data only */
         XMEMCPY(output + offset, data->client_verify_data, TLS_FINISHED_SZ);
@@ -3536,37 +4347,37 @@
 
     if (length >= OPAQUE8_LEN) {
-        if (ssl->secure_renegotiation == NULL) {
+        if (isRequest) {
         #ifndef NO_WOLFSSL_SERVER
-            if (isRequest && *input == 0) {
-            #ifdef HAVE_SERVER_RENEGOTIATION_INFO
-                if (length == OPAQUE8_LEN) {
-                    if (TLSX_Find(ssl->extensions,
-                                  TLSX_RENEGOTIATION_INFO) == NULL) {
-                        ret = TLSX_AddEmptyRenegotiationInfo(&ssl->extensions,
-                                                             ssl->heap);
-                        if (ret == WOLFSSL_SUCCESS)
-                            ret = 0;
-
-                    } else {
+            if (ssl->secure_renegotiation == NULL) {
+                /* already in error state */
+                WOLFSSL_MSG("server SCR not available");
+            }
+            else if (!ssl->secure_renegotiation->enabled) {
+                if (*input == 0) {
+                    input++; /* get past size */
+
+                    ssl->secure_renegotiation->enabled = 1;
+                    TLSX_SetResponse(ssl, TLSX_RENEGOTIATION_INFO);
                         ret = 0;
                     }
+                else {
+                    /* already in error state */
+                    WOLFSSL_MSG("SCR client verify data present");
                 }
-            #else
-                ret = 0;  /* don't reply, user didn't enable */
-            #endif /* HAVE_SERVER_RENEGOTIATION_INFO */
             }
-            #ifdef HAVE_SERVER_RENEGOTIATION_INFO
-            else if (!isRequest) {
-                /* don't do anything on client side */
-                ret = 0;
-            }
-            #endif
-        #endif
-        }
-        else if (isRequest) {
-        #ifndef NO_WOLFSSL_SERVER
-            if (*input == TLS_FINISHED_SZ) {
-                /* TODO compare client_verify_data */
-                ret = 0;
+            else if (*input == TLS_FINISHED_SZ) {
+                input++; /* get past size */
+
+                /* validate client verify data */
+                if (XMEMCMP(input,
+                            ssl->secure_renegotiation->client_verify_data,
+                            TLS_FINISHED_SZ) == 0) {
+                    WOLFSSL_MSG("SCR client verify data match");
+                    TLSX_SetResponse(ssl, TLSX_RENEGOTIATION_INFO);
+                    ret = 0;  /* verified */
+                } else {
+                    /* already in error state */
+                    WOLFSSL_MSG("SCR client verify data Failure");
+        }
             }
         #endif
@@ -3632,12 +4443,6 @@
 #ifdef HAVE_SERVER_RENEGOTIATION_INFO
 
-int TLSX_AddEmptyRenegotiationInfo(TLSX** extensions, void* heap)
-{
-    int ret;
-
-    ret = TLSX_Push(extensions, TLSX_RENEGOTIATION_INFO, NULL, heap);
-    if (ret != 0)
-        return ret;
-
+int TLSX_AddEmptyRenegotiationInfo(TLSX** extensions)
+{
     /* send empty renegotiation_info extension */
     TLSX* ext = TLSX_Find(*extensions, TLSX_RENEGOTIATION_INFO);
@@ -3671,5 +4476,5 @@
 #ifdef HAVE_SESSION_TICKET
 
-#ifndef NO_WOLFSSL_CLIENT
+#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_CLIENT)
 static void TLSX_SessionTicket_ValidateRequest(WOLFSSL* ssl)
 {
@@ -3686,5 +4491,5 @@
     }
 }
-#endif /* NO_WOLFSSL_CLIENT */
+#endif /* WLFSSL_TLS13 || !NO_WOLFSSL_CLIENT */
 
 
@@ -3717,5 +4522,7 @@
 
     if (!isRequest) {
-        /* client side */
+        if (TLSX_CheckUnsupportedExtension(ssl, TLSX_SESSION_TICKET))
+            return TLSX_HandleUnsupportedExtension(ssl);
+
         if (length != 0)
             return BUFFER_ERROR;
@@ -4441,16 +5248,22 @@
  *
  * data       The SSL/TLS object.
+ * msgType The type of the message this extension is being written into.
  * returns the length of data that will be in the extension.
  */
-static word16 TLSX_SupportedVersions_GetSize(void* data)
+static int TLSX_SupportedVersions_GetSize(void* data, byte msgType, word16* pSz)
 {
     WOLFSSL* ssl = (WOLFSSL*)data;
 
+    if (msgType == client_hello) {
     /* TLS v1.2 and TLS v1.3  */
     int cnt = 2;
 
 #ifndef NO_OLD_TLS
-    /* TLS v1 and TLS v1.1  */
-    cnt += 2;
+        /* TLS v1.1  */
+        cnt++;
+    #ifdef WOLFSSL_ALLOW_TLSV10
+        /* TLS v1.0  */
+        cnt++;
+    #endif
 #endif
 
@@ -4458,5 +5271,14 @@
        cnt = 1;
 
-    return OPAQUE8_LEN + cnt * OPAQUE16_LEN;
+        *pSz += (word16)(OPAQUE8_LEN + cnt * OPAQUE16_LEN);
+    }
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    else if (msgType == server_hello || msgType == hello_retry_request)
+        *pSz += OPAQUE16_LEN;
+#endif
+    else
+        return SANITY_MSG_E;
+
+    return 0;
 }
 
@@ -4465,17 +5287,27 @@
  * data    The SSL/TLS object.
  * output  The buffer to write the extension into.
+ * msgType The type of the message this extension is being written into.
  * returns the length of data that was written.
  */
-static word16 TLSX_SupportedVersions_Write(void* data, byte* output)
+static int TLSX_SupportedVersions_Write(void* data, byte* output,
+                                           byte msgType, word16* pSz)
 {
     WOLFSSL* ssl = (WOLFSSL*)data;
-    ProtocolVersion pv = ssl->ctx->method->version;
+    ProtocolVersion pv;
     int i;
+    int cnt;
+
+    if (msgType == client_hello) {
+        pv = ssl->ctx->method->version;
     /* TLS v1.2 and TLS v1.3  */
-    int cnt = 2;
+        cnt = 2;
 
 #ifndef NO_OLD_TLS
-    /* TLS v1 and TLS v1.1  */
-    cnt += 2;
+        /* TLS v1.1  */
+        cnt++;
+    #ifdef WOLFSSL_ALLOW_TLSV10
+        /* TLS v1.0  */
+        cnt++;
+    #endif
 #endif
 
@@ -4483,7 +5315,7 @@
        cnt = 1;
 
-    *(output++) = cnt * OPAQUE16_LEN;
+        *(output++) = (byte)(cnt * OPAQUE16_LEN);
     for (i = 0; i < cnt; i++) {
-        /* TODO: [TLS13] Remove code when TLS v1.3 becomes an RFC. */
+#ifdef WOLFSSL_TLS13_DRAFT
         if (pv.minor - i == TLSv1_3_MINOR) {
             /* The TLS draft major number. */
@@ -4493,10 +5325,34 @@
             continue;
         }
+#endif
 
         *(output++) = pv.major;
-        *(output++) = pv.minor - i;
-    }
-
-    return OPAQUE8_LEN + cnt * OPAQUE16_LEN;
+            *(output++) = (byte)(pv.minor - i);
+        }
+
+        *pSz += (word16)(OPAQUE8_LEN + cnt * OPAQUE16_LEN);
+    }
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    else if (msgType == server_hello || msgType == hello_retry_request) {
+    #ifdef WOLFSSL_TLS13_DRAFT
+        if (ssl->version.major == SSLv3_MAJOR &&
+                                          ssl->version.minor == TLSv1_3_MINOR) {
+            output[0] = TLS_DRAFT_MAJOR;
+            output[1] = TLS_DRAFT_MINOR;
+        }
+        else
+    #endif
+        {
+            output[0] = ssl->version.major;
+            output[1] = ssl->version.minor;
+        }
+
+        *pSz += OPAQUE16_LEN;
+    }
+#endif
+    else
+        return SANITY_MSG_E;
+
+    return 0;
 }
 
@@ -4506,15 +5362,17 @@
  * input   The buffer with the extension data.
  * length  The length of the extension data.
+ * msgType The type of the message this extension is being parsed from.
  * returns 0 on success, otherwise failure.
  */
 static int TLSX_SupportedVersions_Parse(WOLFSSL *ssl, byte* input,
-                                        word16 length)
+                                        word16 length, byte msgType)
 {
     ProtocolVersion pv = ssl->ctx->method->version;
     int i;
-    int ret = VERSION_ERROR;
     int len;
     byte major, minor;
-
+    int newMinor = 0;
+
+    if (msgType == client_hello) {
     /* Must contain a length and at least one version. */
     if (length < OPAQUE8_LEN + OPAQUE16_LEN || (length & 1) != 1)
@@ -4534,9 +5392,10 @@
         minor = input[i + OPAQUE8_LEN];
 
-        /* TODO: [TLS13] Remove code when TLS v1.3 becomes an RFC. */
+#ifdef WOLFSSL_TLS13_DRAFT
         if (major == TLS_DRAFT_MAJOR && minor == TLS_DRAFT_MINOR) {
             major = SSLv3_MAJOR;
             minor = TLSv1_3_MINOR;
         }
+#endif
 
         if (major != pv.major)
@@ -4544,29 +5403,88 @@
 
         /* No upgrade allowed. */
-        if (ssl->version.minor > minor)
+            if (minor > ssl->version.minor)
                 continue;
         /* Check downgrade. */
-        if (ssl->version.minor < minor) {
+            if (minor < ssl->version.minor) {
             if (!ssl->options.downgrade)
                 continue;
 
-#ifdef NO_OLD_TLS
-            if (minor < TLSv1_2_MINOR)
+                if (minor < ssl->options.minDowngrade)
                 continue;
-#endif
+
+                if (newMinor == 0 && minor > ssl->options.oldMinor) {
             /* Downgrade the version. */
             ssl->version.minor = minor;
         }
+            }
 
         if (minor >= TLSv1_3_MINOR) {
+                if (!ssl->options.tls1_3) {
             ssl->options.tls1_3 = 1;
-            TLSX_Push(&ssl->extensions, TLSX_SUPPORTED_VERSIONS, input,
+                    TLSX_Push(&ssl->extensions, TLSX_SUPPORTED_VERSIONS, ssl,
                       ssl->heap);
-        }
-        ret = 0;
-        break;
-    }
-
-    return ret;
+#ifndef WOLFSSL_TLS13_DRAFT_18
+                    TLSX_SetResponse(ssl, TLSX_SUPPORTED_VERSIONS);
+#endif
+        }
+                if (minor > newMinor) {
+                    ssl->version.minor = minor;
+                    newMinor = minor;
+                }
+            }
+            else if (minor > ssl->options.oldMinor)
+                ssl->options.oldMinor = minor;
+        }
+    }
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    else if (msgType == server_hello || msgType == hello_retry_request) {
+        /* Must contain one version. */
+        if (length != OPAQUE16_LEN)
+            return BUFFER_ERROR;
+
+        major = input[0];
+        minor = input[OPAQUE8_LEN];
+
+    #ifdef WOLFSSL_TLS13_DRAFT
+        if (major == TLS_DRAFT_MAJOR && minor == TLS_DRAFT_MINOR) {
+            major = SSLv3_MAJOR;
+            minor = TLSv1_3_MINOR;
+        }
+    #endif
+
+        if (major != pv.major)
+            return VERSION_ERROR;
+
+        /* Can't downgrade with this extension below TLS v1.3. */
+        if (minor < TLSv1_3_MINOR)
+            return VERSION_ERROR;
+
+        /* Version is TLS v1.2 to handle downgrading from TLS v1.3+. */
+        if (ssl->options.downgrade && ssl->version.minor == TLSv1_2_MINOR) {
+            /* Set minor version back to TLS v1.3+ */
+            ssl->version.minor = ssl->ctx->method->version.minor;
+    }
+
+        /* No upgrade allowed. */
+        if (ssl->version.minor < minor)
+            return VERSION_ERROR;
+
+        /* Check downgrade. */
+        if (ssl->version.minor > minor) {
+            if (!ssl->options.downgrade)
+                return VERSION_ERROR;
+
+            if (minor < ssl->options.minDowngrade)
+                return VERSION_ERROR;
+
+            /* Downgrade the version. */
+            ssl->version.minor = minor;
+        }
+    }
+#endif
+    else
+        return SANITY_MSG_E;
+
+    return 0;
 }
 
@@ -4593,7 +5511,7 @@
 #else
 
-#define SV_GET_SIZE(a)       0
-#define SV_WRITE(a, b)       0
-#define SV_PARSE(a, b, c)    0
+#define SV_GET_SIZE(a, b, c) 0
+#define SV_WRITE(a, b, c, d) 0
+#define SV_PARSE(a, b, c, d) 0
 
 #endif /* WOLFSSL_TLS13 */
@@ -4625,10 +5543,11 @@
  * returns the number of bytes of the encoded Cookie extension.
  */
-static word16 TLSX_Cookie_GetSize(Cookie* cookie, byte msgType)
+static int TLSX_Cookie_GetSize(Cookie* cookie, byte msgType, word16* pSz)
 {
     if (msgType == client_hello || msgType == hello_retry_request)
-        return OPAQUE16_LEN + cookie->len;
-
+        *pSz += OPAQUE16_LEN + cookie->len;
+    else
     return SANITY_MSG_E;
+    return 0;
 }
 
@@ -4642,5 +5561,5 @@
  * returns the number of bytes written into the buffer.
  */
-static word16 TLSX_Cookie_Write(Cookie* cookie, byte* output, byte msgType)
+static int TLSX_Cookie_Write(Cookie* cookie, byte* output, byte msgType, word16* pSz)
 {
     if (msgType == client_hello || msgType == hello_retry_request) {
@@ -4648,8 +5567,9 @@
         output += OPAQUE16_LEN;
         XMEMCPY(output, &cookie->data, cookie->len);
-        return OPAQUE16_LEN + cookie->len;
-    }
-
+        *pSz += OPAQUE16_LEN + cookie->len;
+    }
+    else
     return SANITY_MSG_E;
+    return 0;
 }
 
@@ -4744,5 +5664,5 @@
 
     extension->data = (void*)cookie;
-    extension->resp = resp;
+    extension->resp = (byte)resp;
 
     return 0;
@@ -4757,6 +5677,6 @@
 
 #define CKE_FREE_ALL(a, b)    0
-#define CKE_GET_SIZE(a, b)    0
-#define CKE_WRITE(a, b, c)    0
+#define CKE_GET_SIZE(a, b, c) 0
+#define CKE_WRITE(a, b, c, d) 0
 #define CKE_PARSE(a, b, c, d) 0
 
@@ -4764,5 +5684,5 @@
 
 /******************************************************************************/
-/* Sugnature Algorithms                                                       */
+/* Signature Algorithms                                                       */
 /******************************************************************************/
 
@@ -4790,5 +5710,5 @@
  */
 static int TLSX_SignatureAlgorithms_MapPss(WOLFSSL *ssl, byte* input,
-                                           word16 length)
+                                                                  word16 length)
 {
     word16 i;
@@ -4834,9 +5754,10 @@
  */
 static int TLSX_SignatureAlgorithms_Parse(WOLFSSL *ssl, byte* input,
-                                          word16 length, Suites* suites)
+                                  word16 length, byte isRequest, Suites* suites)
 {
     word16 len;
 
-    (void)ssl;
+    if (!isRequest)
+        return BUFFER_ERROR;
 
     /* Must contain a length and at least algorithm. */
@@ -4851,11 +5772,16 @@
         return BUFFER_ERROR;
 
-    XMEMCPY(suites->hashSigAlgo, input, len);
+    /* truncate hashSigAlgo list if too long */
     suites->hashSigAlgoSz = len;
+    if (suites->hashSigAlgoSz > WOLFSSL_MAX_SIGALGO) {
+        WOLFSSL_MSG("TLSX SigAlgo list exceeds max, truncating");
+        suites->hashSigAlgoSz = WOLFSSL_MAX_SIGALGO;
+    }
+    XMEMCPY(suites->hashSigAlgo, input, suites->hashSigAlgoSz);
 
     return TLSX_SignatureAlgorithms_MapPss(ssl, input, len);
 }
 
-/* Sets a new SupportedVersions extension into the extension list.
+/* Sets a new SignatureAlgorithms extension into the extension list.
  *
  * extensions  The list of extensions.
@@ -4877,4 +5803,99 @@
 #define SA_PARSE     TLSX_SignatureAlgorithms_Parse
 
+/******************************************************************************/
+/* Signature Algorithms Certificate                                           */
+/******************************************************************************/
+
+#ifdef WOLFSSL_TLS13
+#if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+/* Return the size of the SignatureAlgorithms extension's data.
+ *
+ * data  Unused
+ * returns the length of data that will be in the extension.
+ */
+static word16 TLSX_SignatureAlgorithmsCert_GetSize(void* data)
+{
+    WOLFSSL* ssl = (WOLFSSL*)data;
+
+    return OPAQUE16_LEN + ssl->certHashSigAlgoSz;
+}
+
+/* Writes the SignatureAlgorithmsCert extension into the buffer.
+ *
+ * data    Unused
+ * output  The buffer to write the extension into.
+ * returns the length of data that was written.
+ */
+static word16 TLSX_SignatureAlgorithmsCert_Write(void* data, byte* output)
+{
+    WOLFSSL* ssl = (WOLFSSL*)data;
+
+    c16toa(ssl->certHashSigAlgoSz, output);
+    XMEMCPY(output + OPAQUE16_LEN, ssl->certHashSigAlgo,
+            ssl->certHashSigAlgoSz);
+
+    return OPAQUE16_LEN + ssl->certHashSigAlgoSz;
+}
+
+/* Parse the SignatureAlgorithmsCert extension.
+ *
+ * ssl     The SSL/TLS object.
+ * input   The buffer with the extension data.
+ * length  The length of the extension data.
+ * returns 0 on success, otherwise failure.
+ */
+static int TLSX_SignatureAlgorithmsCert_Parse(WOLFSSL *ssl, byte* input,
+                                              word16 length, byte isRequest)
+{
+    word16 len;
+
+    if (!isRequest)
+        return BUFFER_ERROR;
+
+    /* Must contain a length and at least algorithm. */
+    if (length < OPAQUE16_LEN + OPAQUE16_LEN || (length & 1) != 0)
+        return BUFFER_ERROR;
+
+    ato16(input, &len);
+    input += OPAQUE16_LEN;
+
+    /* Algorithm array must fill rest of data. */
+    if (length != OPAQUE16_LEN + len)
+        return BUFFER_ERROR;
+
+    /* truncate hashSigAlgo list if too long */
+    ssl->certHashSigAlgoSz = len;
+    if (ssl->certHashSigAlgoSz > WOLFSSL_MAX_SIGALGO) {
+        WOLFSSL_MSG("TLSX SigAlgo list exceeds max, truncating");
+        ssl->certHashSigAlgoSz = WOLFSSL_MAX_SIGALGO;
+    }
+    XMEMCPY(ssl->certHashSigAlgo, input, ssl->certHashSigAlgoSz);
+
+    return 0;
+}
+
+/* Sets a new SignatureAlgorithmsCert extension into the extension list.
+ *
+ * extensions  The list of extensions.
+ * data        The extensions specific data.
+ * heap        The heap used for allocation.
+ * returns 0 on success, otherwise failure.
+ */
+static int TLSX_SetSignatureAlgorithmsCert(TLSX** extensions, const void* data,
+                                       void* heap)
+{
+    if (extensions == NULL)
+        return BAD_FUNC_ARG;
+
+    return TLSX_Push(extensions, TLSX_SIGNATURE_ALGORITHMS_CERT, (void *)data,
+                                                                          heap);
+}
+
+#define SAC_GET_SIZE  TLSX_SignatureAlgorithmsCert_GetSize
+#define SAC_WRITE     TLSX_SignatureAlgorithmsCert_Write
+#define SAC_PARSE     TLSX_SignatureAlgorithmsCert_Parse
+#endif /* !WOLFSSL_TLS13_DRAFT_18 && !WOLFSSL_TLS13_DRAFT_22 */
+#endif /* WOLFSSL_TLS13 */
+
 
 /******************************************************************************/
@@ -4883,5 +5904,4 @@
 
 #ifdef WOLFSSL_TLS13
-#ifndef NO_DH
 /* Create a key share entry using named Diffie-Hellman parameters group.
  * Generates a key pair.
@@ -4894,4 +5914,5 @@
 {
     int             ret;
+#ifndef NO_DH
     byte*           keyData;
     void*           key = NULL;
@@ -4899,5 +5920,9 @@
     word32          dataSz;
     const DhParams* params;
-    DhKey dhKey;
+#ifdef WOLFSSL_SMALL_STACK
+    DhKey*          dhKey = NULL;
+#else
+    DhKey           dhKey[1];
+#endif
 
     /* TODO: [TLS13] The key size should come from wolfcrypt. */
@@ -4938,7 +5963,17 @@
     }
 
-    ret = wc_InitDhKey_ex(&dhKey, ssl->heap, ssl->devId);
-    if (ret != 0)
+#ifdef WOLFSSL_SMALL_STACK
+    dhKey = (DhKey*)XMALLOC(sizeof(DhKey), ssl->heap, DYNAMIC_TYPE_DH);
+    if (dhKey == NULL)
+        return MEMORY_E;
+#endif
+
+    ret = wc_InitDhKey_ex(dhKey, ssl->heap, ssl->devId);
+    if (ret != 0) {
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
+    #endif
         return ret;
+    }
 
     /* Allocate space for the public key. */
@@ -4957,5 +5992,5 @@
 
     /* Set key */
-    ret = wc_DhSetKey(&dhKey,
+    ret = wc_DhSetKey(dhKey,
         (byte*)params->p, params->p_len,
         (byte*)params->g, params->g_len);
@@ -4964,10 +5999,10 @@
 
     /* Generate a new key pair. */
-    ret = wc_DhGenerateKeyPair(&dhKey, ssl->rng, (byte*)key, &keySz, keyData,
+    ret = wc_DhGenerateKeyPair(dhKey, ssl->rng, (byte*)key, &keySz, keyData,
                                &dataSz);
 #ifdef WOLFSSL_ASYNC_CRYPT
     /* TODO: Make this function non-blocking */
     if (ret == WC_PENDING_E) {
-        ret = wc_AsyncWait(ret, &dhKey.asyncDev, WC_ASYNC_FLAG_NONE);
+        ret = wc_AsyncWait(ret, &dhKey->asyncDev, WC_ASYNC_FLAG_NONE);
     }
 #endif
@@ -4981,6 +6016,6 @@
     }
 
-    kse->ke = keyData;
-    kse->keLen = params->p_len;
+    kse->pubKey = keyData;
+    kse->pubKeyLen = params->p_len;
     kse->key = key;
     kse->keyLen = keySz;
@@ -4993,5 +6028,8 @@
 end:
 
-    wc_FreeDhKey(&dhKey);
+    wc_FreeDhKey(dhKey);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
+#endif
 
     if (ret != 0) {
@@ -5002,10 +6040,88 @@
             XFREE(key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
     }
+#else
+    (void)ssl;
+    (void)kse;
+
+    ret = NOT_COMPILED_IN;
+#endif
 
     return ret;
 }
-#endif
-
-#ifdef HAVE_ECC
+
+/* Create a key share entry using X25519 parameters group.
+ * Generates a key pair.
+ *
+ * ssl   The SSL/TLS object.
+ * kse   The key share entry object.
+ * returns 0 on success, otherwise failure.
+ */
+static int TLSX_KeyShare_GenX25519Key(WOLFSSL *ssl, KeyShareEntry* kse)
+{
+    int      ret;
+    #ifdef HAVE_CURVE25519
+    byte*           keyData = NULL;
+    word32          dataSize = CURVE25519_KEYSIZE;
+                curve25519_key* key;
+
+                /* Allocate an ECC key to hold private key. */
+                key = (curve25519_key*)XMALLOC(sizeof(curve25519_key),
+                                           ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
+                if (key == NULL) {
+                    WOLFSSL_MSG("EccTempKey Memory error");
+                    return MEMORY_E;
+                }
+
+                /* Make an ECC key. */
+                ret = wc_curve25519_init(key);
+                if (ret != 0)
+                    goto end;
+    ret = wc_curve25519_make_key(ssl->rng, CURVE25519_KEYSIZE, key);
+                if (ret != 0)
+                    goto end;
+
+                /* Allocate space for the public key. */
+    keyData = (byte*)XMALLOC(CURVE25519_KEYSIZE, ssl->heap,
+                                         DYNAMIC_TYPE_PUBLIC_KEY);
+                if (keyData == NULL) {
+                    WOLFSSL_MSG("Key data Memory error");
+                    ret = MEMORY_E;
+                    goto end;
+                }
+
+                /* Export public key. */
+                if (wc_curve25519_export_public_ex(key, keyData, &dataSize,
+                                                  EC25519_LITTLE_ENDIAN) != 0) {
+                    ret = ECC_EXPORT_ERROR;
+                    goto end;
+                }
+
+    kse->pubKey = keyData;
+    kse->pubKeyLen = CURVE25519_KEYSIZE;
+                kse->key = key;
+
+#ifdef WOLFSSL_DEBUG_TLS
+                WOLFSSL_MSG("Public Curve25519 Key");
+                WOLFSSL_BUFFER(keyData, dataSize);
+#endif
+
+end:
+    if (ret != 0) {
+        /* Data owned by key share entry otherwise. */
+        if (keyData != NULL)
+            XFREE(keyData, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+        wc_curve25519_free(key);
+        XFREE(key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
+    }
+#else
+    (void)ssl;
+    (void)kse;
+
+    ret = NOT_COMPILED_IN;
+#endif /* HAVE_CURVE25519 */
+
+    return ret;
+            }
+
 /* Create a key share entry using named elliptic curve parameters group.
  * Generates a key pair.
@@ -5018,8 +6134,10 @@
 {
     int      ret;
+#ifdef HAVE_ECC
     byte*    keyData = NULL;
     word32   dataSize;
+    byte*    keyPtr = NULL;
     word32   keySize;
-    ecc_key* eccKey = NULL;
+    ecc_key* eccKey;
     word16   curveId;
 
@@ -5054,54 +6172,4 @@
         #endif /* !NO_ECC_SECP */
     #endif
-    #ifdef HAVE_CURVE25519
-        case WOLFSSL_ECC_X25519:
-            {
-                curve25519_key* key;
-                /* Allocate an ECC key to hold private key. */
-                key = (curve25519_key*)XMALLOC(sizeof(curve25519_key),
-                                           ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
-                if (key == NULL) {
-                    WOLFSSL_MSG("EccTempKey Memory error");
-                    return MEMORY_E;
-                }
-
-                dataSize = keySize = 32;
-
-                /* Make an ECC key. */
-                ret = wc_curve25519_init(key);
-                if (ret != 0)
-                    goto end;
-                ret = wc_curve25519_make_key(ssl->rng, keySize, key);
-                if (ret != 0)
-                    goto end;
-
-                /* Allocate space for the public key. */
-                keyData = (byte*)XMALLOC(dataSize, ssl->heap,
-                                         DYNAMIC_TYPE_PUBLIC_KEY);
-                if (keyData == NULL) {
-                    WOLFSSL_MSG("Key data Memory error");
-                    ret = MEMORY_E;
-                    goto end;
-                }
-
-                /* Export public key. */
-                if (wc_curve25519_export_public_ex(key, keyData, &dataSize,
-                                                  EC25519_LITTLE_ENDIAN) != 0) {
-                    ret = ECC_EXPORT_ERROR;
-                    goto end;
-                }
-
-                kse->ke = keyData;
-                kse->keLen = dataSize;
-                kse->key = key;
-
-#ifdef WOLFSSL_DEBUG_TLS
-                WOLFSSL_MSG("Public Curve25519 Key");
-                WOLFSSL_BUFFER(keyData, dataSize);
-#endif
-
-                goto end;
-            }
-    #endif
     #ifdef HAVE_X448
         case WOLFSSL_ECC_X448:
@@ -5115,10 +6183,11 @@
 
     /* Allocate an ECC key to hold private key. */
-    eccKey = (ecc_key*)XMALLOC(sizeof(ecc_key), ssl->heap,
+    keyPtr = (byte*)XMALLOC(sizeof(ecc_key), ssl->heap,
                                DYNAMIC_TYPE_PRIVATE_KEY);
-    if (eccKey == NULL) {
+    if (keyPtr == NULL) {
         WOLFSSL_MSG("EccTempKey Memory error");
         return MEMORY_E;
     }
+    eccKey = (ecc_key*)keyPtr;
 
     /* Make an ECC key. */
@@ -5150,7 +6219,7 @@
     }
 
-    kse->ke = keyData;
-    kse->keLen = dataSize;
-    kse->key = eccKey;
+    kse->pubKey = keyData;
+    kse->pubKeyLen = dataSize;
+    kse->key = keyPtr;
 
 #ifdef WOLFSSL_DEBUG_TLS
@@ -5162,12 +6231,18 @@
     if (ret != 0) {
         /* Data owned by key share entry otherwise. */
-        if (eccKey != NULL)
-            XFREE(eccKey, ssl->heap, DYNAMIC_TYPE_TLSX);
+        if (keyPtr != NULL)
+            XFREE(keyPtr, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
         if (keyData != NULL)
-            XFREE(keyData, ssl->heap, DYNAMIC_TYPE_TLSX);
-    }
+            XFREE(keyData, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+    }
+#else
+    (void)ssl;
+    (void)kse;
+
+    ret = NOT_COMPILED_IN;
+#endif /* HAVE_ECC */
+
     return ret;
 }
-#endif /* HAVE_ECC */
 
 /* Generate a secret/key using the key share entry.
@@ -5178,14 +6253,10 @@
 static int TLSX_KeyShare_GenKey(WOLFSSL *ssl, KeyShareEntry *kse)
 {
-#ifndef NO_DH
     /* Named FFHE groups have a bit set to identify them. */
     if ((kse->group & NAMED_DH_MASK) == NAMED_DH_MASK)
         return TLSX_KeyShare_GenDhKey(ssl, kse);
-#endif
-#ifdef HAVE_ECC
+    if (kse->group == WOLFSSL_ECC_X25519)
+        return TLSX_KeyShare_GenX25519Key(ssl, kse);
     return TLSX_KeyShare_GenEccKey(ssl, kse);
-#else
-    return NOT_COMPILED_IN;
-#endif
 }
 
@@ -5204,5 +6275,5 @@
             if (current->group == WOLFSSL_ECC_X25519) {
 #ifdef HAVE_CURVE25519
-
+                wc_curve25519_free((curve25519_key*)current->key);
 #endif
             }
@@ -5213,5 +6284,7 @@
             }
         }
+        if (current->key != NULL)
         XFREE(current->key, heap, DYNAMIC_TYPE_PRIVATE_KEY);
+        XFREE(current->pubKey, heap, DYNAMIC_TYPE_PUBLIC_KEY);
         XFREE(current->ke, heap, DYNAMIC_TYPE_PUBLIC_KEY);
         XFREE(current, heap, DYNAMIC_TYPE_TLSX);
@@ -5246,8 +6319,8 @@
             continue;
 
-        len += OPAQUE16_LEN + OPAQUE16_LEN + current->keLen;
-    }
-
-    return len;
+        len += (int)(KE_GROUP_LEN + OPAQUE16_LEN + current->pubKeyLen);
+    }
+
+    return (word16)len;
 }
 
@@ -5285,8 +6358,8 @@
         c16toa(current->group, &output[i]);
         i += KE_GROUP_LEN;
-        c16toa(current->keLen, &output[i]);
+        c16toa((word16)(current->pubKeyLen), &output[i]);
         i += OPAQUE16_LEN;
-        XMEMCPY(&output[i], current->ke, current->keLen);
-        i += current->keLen;
+        XMEMCPY(&output[i], current->pubKey, current->pubKeyLen);
+        i += (word16)current->pubKeyLen;
     }
     /* Write the length of the list if required. */
@@ -5308,7 +6381,9 @@
     int             ret;
     const DhParams* params;
-    word16          i;
-    byte            b;
-    DhKey           dhKey;
+#ifdef WOLFSSL_SMALL_STACK
+    DhKey*          dhKey = NULL;
+#else
+    DhKey           dhKey[1];
+#endif
 
     switch (keyShareEntry->group) {
@@ -5347,42 +6422,40 @@
 #endif
 
-    if (params->p_len != keyShareEntry->keLen)
-        return BUFFER_ERROR;
-    ssl->options.dhKeySz = params->p_len;
-
-    /* TODO: [TLS13] move this check down into wolfcrypt. */
-    /* Check that public DH key is not 0 or 1. */
-    b = 0;
-    for (i = 0; i < params->p_len - 1; i++)
-        b |= keyShareEntry->ke[i];
-    if (b == 0 && (keyShareEntry->ke[i] == 0x00 ||
-                   keyShareEntry->ke[i] == 0x01)) {
+#ifdef WOLFSSL_SMALL_STACK
+    dhKey = (DhKey*)XMALLOC(sizeof(DhKey), ssl->heap, DYNAMIC_TYPE_DH);
+    if (dhKey == NULL)
+        return MEMORY_E;
+#endif
+
+    ret = wc_InitDhKey_ex(dhKey, ssl->heap, ssl->devId);
+    if (ret != 0) {
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
+    #endif
+        return ret;
+    }
+
+    /* Set key */
+    ret = wc_DhSetKey(dhKey, (byte*)params->p, params->p_len, (byte*)params->g,
+                                                                 params->g_len);
+    if (ret != 0) {
+        wc_FreeDhKey(dhKey);
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
+    #endif
+        return ret;
+    }
+
+    ret = wc_DhCheckPubKey(dhKey, keyShareEntry->ke, keyShareEntry->keLen);
+    if (ret != 0) {
+        wc_FreeDhKey(dhKey);
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
+    #endif
         return PEER_KEY_ERROR;
     }
-    /* Check that public DH key is not mod, mod + 1 or mod - 1. */
-    b = 0;
-    for (i = 0; i < params->p_len - 1; i++)
-        b |= params->p[i] ^ keyShareEntry->ke[i];
-    if (b == 0 && (params->p[i]     == keyShareEntry->ke[i] ||
-                   params->p[i] - 1 == keyShareEntry->ke[i] ||
-                   params->p[i] + 1 == keyShareEntry->ke[i])) {
-        return PEER_KEY_ERROR;
-    }
-
-    ret = wc_InitDhKey_ex(&dhKey, ssl->heap, ssl->devId);
-    if (ret != 0)
-        return ret;
-
-    /* Set key */
-    ret = wc_DhSetKey(&dhKey,
-        (byte*)params->p, params->p_len,
-        (byte*)params->g, params->g_len);
-    if (ret != 0) {
-        wc_FreeDhKey(&dhKey);
-        return ret;
-    }
 
     /* Derive secret from private key and peer's public key. */
-    ret = wc_DhAgree(&dhKey,
+    ret = wc_DhAgree(dhKey,
         ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz,
         (const byte*)keyShareEntry->key, keyShareEntry->keyLen,
@@ -5391,9 +6464,30 @@
     /* TODO: Make this function non-blocking */
     if (ret == WC_PENDING_E) {
-        ret = wc_AsyncWait(ret, &dhKey.asyncDev, WC_ASYNC_FLAG_NONE);
-    }
-#endif
-
-    wc_FreeDhKey(&dhKey);
+        ret = wc_AsyncWait(ret, &dhKey->asyncDev, WC_ASYNC_FLAG_NONE);
+    }
+#endif
+    /* RFC 8446 Section 7.4.1:
+     *     ... left-padded with zeros up to the size of the prime. ...
+     */
+    if (params->p_len > ssl->arrays->preMasterSz) {
+        word32 diff = params->p_len - ssl->arrays->preMasterSz;
+        XMEMMOVE(ssl->arrays->preMasterSecret + diff,
+                        ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz);
+        XMEMSET(ssl->arrays->preMasterSecret, 0, diff);
+        ssl->arrays->preMasterSz = params->p_len;
+    }
+
+    wc_FreeDhKey(dhKey);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
+#endif
+    if (keyShareEntry->key != NULL) {
+        XFREE(keyShareEntry->key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
+        keyShareEntry->key = NULL;
+    }
+    XFREE(keyShareEntry->pubKey, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+    keyShareEntry->pubKey = NULL;
+    XFREE(keyShareEntry->ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+    keyShareEntry->ke = NULL;
 
     return ret;
@@ -5403,4 +6497,76 @@
     return PEER_KEY_ERROR;
 #endif
+}
+
+/* Process the X25519 key share extension on the client side.
+ *
+ * ssl            The SSL/TLS object.
+ * keyShareEntry  The key share entry object to use to calculate shared secret.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_KeyShare_ProcessX25519(WOLFSSL* ssl,
+                                       KeyShareEntry* keyShareEntry)
+{
+    int ret;
+
+#ifdef HAVE_CURVE25519
+    curve25519_key* key = (curve25519_key*)keyShareEntry->key;
+    curve25519_key* peerX25519Key;
+
+#ifdef HAVE_ECC
+    if (ssl->peerEccKey != NULL) {
+        wc_ecc_free(ssl->peerEccKey);
+        ssl->peerEccKey = NULL;
+    }
+#endif
+
+    peerX25519Key = (curve25519_key*)XMALLOC(sizeof(curve25519_key), ssl->heap,
+                                                             DYNAMIC_TYPE_TLSX);
+    if (peerX25519Key == NULL) {
+        WOLFSSL_MSG("PeerEccKey Memory error");
+        return MEMORY_ERROR;
+    }
+    ret = wc_curve25519_init(peerX25519Key);
+    if (ret != 0) {
+        XFREE(peerX25519Key, ssl->heap, DYNAMIC_TYPE_TLSX);
+        return ret;
+    }
+#ifdef WOLFSSL_DEBUG_TLS
+    WOLFSSL_MSG("Peer Curve25519 Key");
+    WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen);
+#endif
+
+    /* Point is validated by import function. */
+    if (wc_curve25519_import_public_ex(keyShareEntry->ke, keyShareEntry->keLen,
+                                                  peerX25519Key,
+                                                  EC25519_LITTLE_ENDIAN) != 0) {
+        ret = ECC_PEERKEY_ERROR;
+    }
+
+    if (ret == 0) {
+        ssl->arrays->preMasterSz = ENCRYPT_LEN;
+        ssl->ecdhCurveOID = ECC_X25519_OID;
+
+        ret = wc_curve25519_shared_secret_ex(key, peerX25519Key,
+                                                   ssl->arrays->preMasterSecret,
+                                                   &ssl->arrays->preMasterSz,
+                                                   EC25519_LITTLE_ENDIAN);
+    }
+
+    wc_curve25519_free(peerX25519Key);
+    XFREE(peerX25519Key, ssl->heap, DYNAMIC_TYPE_TLSX);
+    wc_curve25519_free((curve25519_key*)keyShareEntry->key);
+    if (keyShareEntry->key != NULL) {
+        XFREE(keyShareEntry->key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
+        keyShareEntry->key = NULL;
+    }
+#else
+    (void)ssl;
+    (void)keyShareEntry;
+
+    ret = PEER_KEY_ERROR;
+#endif /* HAVE_CURVE25519 */
+
+    return ret;
 }
 
@@ -5455,44 +6621,4 @@
         #endif /* !NO_ECC_SECP */
     #endif
-    #ifdef HAVE_CURVE25519
-        case WOLFSSL_ECC_X25519:
-            {
-                curve25519_key* key = (curve25519_key*)keyShareEntry->key;
-                curve25519_key* peerEccKey;
-
-                if (ssl->peerEccKey != NULL)
-                    wc_ecc_free(ssl->peerEccKey);
-
-                peerEccKey = (curve25519_key*)XMALLOC(sizeof(curve25519_key),
-                                                  ssl->heap, DYNAMIC_TYPE_TLSX);
-                if (peerEccKey == NULL) {
-                    WOLFSSL_MSG("PeerEccKey Memory error");
-                    return MEMORY_ERROR;
-                }
-                ret = wc_curve25519_init(peerEccKey);
-                if (ret != 0)
-                    return ret;
-#ifdef WOLFSSL_DEBUG_TLS
-                WOLFSSL_MSG("Peer Curve25519 Key");
-                WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen);
-#endif
-
-                /* Point is validated by import function. */
-                if (wc_curve25519_import_public_ex(keyShareEntry->ke,
-                                               keyShareEntry->keLen, peerEccKey,
-                                               EC25519_LITTLE_ENDIAN) != 0) {
-                    return ECC_PEERKEY_ERROR;
-                }
-
-                ssl->arrays->preMasterSz = ENCRYPT_LEN;
-                ret = wc_curve25519_shared_secret_ex(key, peerEccKey,
-                    ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz,
-                    EC25519_LITTLE_ENDIAN);
-                wc_curve25519_free(peerEccKey);
-                XFREE(peerEccKey, ssl->heap, DYNAMIC_TYPE_TLSX);
-                ssl->ecdhCurveOID = ECC_X25519_OID;
-                return ret;
-            }
-    #endif
     #ifdef HAVE_X448
         case WOLFSSL_ECC_X448:
@@ -5532,13 +6658,16 @@
         keyShareEntry->ke, &keyShareEntry->keLen,
         ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz,
-        ssl->options.side,
-    #ifdef HAVE_PK_CALLBACKS
-        ssl->EccSharedSecretCtx
-    #else
-        NULL
-    #endif
+        ssl->options.side
     );
 #endif
 
+    wc_ecc_free(ssl->peerEccKey);
+    XFREE(ssl->peerEccKey, ssl->heap, DYNAMIC_TYPE_ECC);
+    ssl->peerEccKey = NULL;
+    wc_ecc_free((ecc_key*)(keyShareEntry->key));
+    if (keyShareEntry->key != NULL) {
+        XFREE(keyShareEntry->key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
+        keyShareEntry->key = NULL;
+    }
 
 #else
@@ -5563,9 +6692,11 @@
 
 #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
-    ssl->session.namedGroup = keyShareEntry->group;
+    ssl->session.namedGroup = (byte)keyShareEntry->group;
 #endif
     /* Use Key Share Data from server. */
     if (keyShareEntry->group & NAMED_DH_MASK)
         ret = TLSX_KeyShare_ProcessDh(ssl, keyShareEntry);
+    else if (keyShareEntry->group == WOLFSSL_ECC_X25519)
+        ret = TLSX_KeyShare_ProcessX25519(ssl, keyShareEntry);
     else
         ret = TLSX_KeyShare_ProcessEcc(ssl, keyShareEntry);
@@ -5627,6 +6758,6 @@
 /* Searches the groups sent for the specified named group.
  *
- * ssl   The SSL/TLS object.
- * name  The group name to match.
+ * ssl    SSL/TLS object.
+ * name   Group name to match.
  * returns 1 when the extension has the group name and 0 otherwise.
  */
@@ -5637,12 +6768,14 @@
 
     extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
+    if (extension == NULL) {
+        extension = TLSX_Find(ssl->ctx->extensions, TLSX_KEY_SHARE);
     if (extension == NULL)
         return 0;
+    }
 
     list = (KeyShareEntry*)extension->data;
     while (list != NULL) {
-        if (list->group == group) {
+        if (list->group == group)
             return 1;
-        }
         list = list->next;
     }
@@ -5664,6 +6797,11 @@
     SupportedCurve* curve = NULL;
 
-    if ((extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS)) == NULL)
+    if ((extension = TLSX_Find(ssl->extensions,
+                                              TLSX_SUPPORTED_GROUPS)) == NULL) {
+        if ((extension = TLSX_Find(ssl->ctx->extensions,
+                                              TLSX_SUPPORTED_GROUPS)) == NULL) {
         return 0;
+        }
+    }
 
     for (curve = (SupportedCurve*)extension->data; curve; curve = curve->next) {
@@ -5693,9 +6831,20 @@
 {
     int ret;
-    KeyShareEntry *keyShareEntry;
+    KeyShareEntry *keyShareEntry = NULL;
+    word16 group;
 
     if (msgType == client_hello) {
         int offset = 0;
         word16 len;
+        TLSX*  extension;
+
+        /* Add a KeyShare extension if it doesn't exist. */
+        extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
+        if (extension == NULL) {
+            /* Push new KeyShare extension. */
+            ret = TLSX_Push(&ssl->extensions, TLSX_KEY_SHARE, NULL, ssl->heap);
+            if (ret != 0)
+                return ret;
+        }
 
         if (length < OPAQUE16_LEN)
@@ -5722,4 +6871,18 @@
         int len;
 
+        if (length < OPAQUE16_LEN)
+            return BUFFER_ERROR;
+
+        /* The data is the named group the server wants to use. */
+        ato16(input, &group);
+
+        /* Check the selected group was supported by ClientHello extensions. */
+        if (!TLSX_SupportedGroups_Find(ssl, group))
+            return BAD_KEY_SHARE_DATA;
+
+        /* Check if the group was sent. */
+        if (!TLSX_KeyShare_Find(ssl, group))
+            return BAD_KEY_SHARE_DATA;
+
         /* ServerHello contains one key share entry. */
         len = TLSX_KeyShareEntry_Parse(ssl, input, length, &keyShareEntry);
@@ -5728,13 +6891,13 @@
 
         /* Not in list sent if there isn't a private key. */
-        if (keyShareEntry->key == NULL)
+        if (keyShareEntry == NULL || keyShareEntry->key == NULL)
             return BAD_KEY_SHARE_DATA;
 
         /* Process the entry to calculate the secret. */
         ret = TLSX_KeyShare_Process(ssl, keyShareEntry);
+        if (ret == 0)
+            ssl->session.namedGroup = ssl->namedGroup = group;
     }
     else if (msgType == hello_retry_request) {
-        word16 group;
-
         if (length != OPAQUE16_LEN)
             return BUFFER_ERROR;
@@ -5750,4 +6913,9 @@
         if (TLSX_KeyShare_Find(ssl, group))
             return BAD_KEY_SHARE_DATA;
+
+        /* Clear out unusable key shares. */
+        ret = TLSX_KeyShare_Empty(ssl);
+        if (ret != 0)
+            return ret;
 
         /* Try to use the server's group. */
@@ -5781,5 +6949,5 @@
 
     XMEMSET(kse, 0, sizeof(*kse));
-    kse->group = group;
+    kse->group = (word16)group;
 
     /* Add it to the back and maintain the links. */
@@ -5788,4 +6956,6 @@
     *list = kse;
     *keyShareEntry = kse;
+
+    (void)heap;
 
     return 0;
@@ -5839,7 +7009,4 @@
 
     if (data != NULL) {
-        /* Keep the public key data and free when finished. */
-        if (keyShareEntry->ke != NULL)
-            XFREE(keyShareEntry->ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
         keyShareEntry->ke = data;
         keyShareEntry->keLen = len;
@@ -5941,4 +7108,66 @@
 
     return 1;
+}
+
+/* Examines the application specified group ranking and returns the rank of the
+ * group.
+ * If no group ranking set then all groups are rank 0 (highest).
+ *
+ * ssl    The SSL/TLS object.
+ * group  The group to check ranking for.
+ * returns ranking from 0 to MAX_GROUP_COUNT-1 or -1 when group not in list.
+ */
+static int TLSX_KeyShare_GroupRank(WOLFSSL* ssl, int group)
+{
+    byte i;
+
+    if (ssl->numGroups == 0) {
+#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
+    #if !defined(NO_ECC256)  || defined(HAVE_ALL_CURVES)
+        #ifndef NO_ECC_SECP
+            ssl->group[ssl->numGroups++] = WOLFSSL_ECC_SECP256R1;
+        #endif
+    #endif
+#endif
+    #ifndef HAVE_FIPS
+        #if defined(HAVE_CURVE25519)
+            ssl->group[ssl->numGroups++] = WOLFSSL_ECC_X25519;
+        #endif
+    #endif
+#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
+    #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
+        #ifndef NO_ECC_SECP
+            ssl->group[ssl->numGroups++] = WOLFSSL_ECC_SECP384R1;
+        #endif
+    #endif
+    #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)
+        #ifndef NO_ECC_SECP
+            ssl->group[ssl->numGroups++] = WOLFSSL_ECC_SECP521R1;
+        #endif
+    #endif
+#endif
+            /* Add FFDHE supported groups. */
+        #ifdef HAVE_FFDHE_2048
+            ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_2048;
+        #endif
+        #ifdef HAVE_FFDHE_3072
+            ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_3072;
+        #endif
+        #ifdef HAVE_FFDHE_4096
+            ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_4096;
+        #endif
+        #ifdef HAVE_FFDHE_6144
+            ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_6144;
+        #endif
+        #ifdef HAVE_FFDHE_8192
+            ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_8192;
+        #endif
+    }
+
+    for (i = 0; i < ssl->numGroups; i++)
+        if (ssl->group[i] == group)
+            return i;
+
+    return -1;
 }
 
@@ -5955,15 +7184,26 @@
     TLSX*          extension;
     SupportedCurve* curve = NULL;
-
-    /* Use SupportedGroup's order. */
+    SupportedCurve* preferredCurve = NULL;
+    int             preferredRank = WOLFSSL_MAX_GROUP_COUNT;
+    int             rank;
+
     extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS);
     if (extension != NULL)
         curve = (SupportedCurve*)extension->data;
+    /* Use server's preference order. */
     for (; curve != NULL; curve = curve->next) {
-        if (TLSX_KeyShare_IsSupported(curve->name) &&
-                !TLSX_KeyShare_Find(ssl, curve->name)) {
-            break;
-        }
-    }
+        if (!TLSX_KeyShare_IsSupported(curve->name))
+            continue;
+
+        rank = TLSX_KeyShare_GroupRank(ssl, curve->name);
+        if (rank == -1)
+            continue;
+        if (rank < preferredRank) {
+            preferredCurve = curve;
+            preferredRank = rank;
+        }
+    }
+    curve = preferredCurve;
+
     if (curve == NULL)
         return BAD_KEY_SHARE_DATA;
@@ -5993,5 +7233,5 @@
 }
 
-/* Establish the secret based on the key shares received from the client.
+/* Ensure there is a key pair that can be used for key exchange.
  *
  * ssl  The SSL/TLS object.
@@ -6005,6 +7245,7 @@
     KeyShareEntry* serverKSE;
     KeyShareEntry* list = NULL;
-    byte*          ke;
-    word16         keLen;
+    KeyShareEntry* preferredKSE = NULL;
+    int preferredRank = WOLFSSL_MAX_GROUP_COUNT;
+    int rank;
 
     /* Find the KeyShare extension if it exists. */
@@ -6016,7 +7257,9 @@
         return 0;
 
-    /* TODO: [TLS13] Server's preference and sending back SupportedGroups */
-    /* Use client's preference. */
+    /* Use server's preference order. */
     for (clientKSE = list; clientKSE != NULL; clientKSE = clientKSE->next) {
+        if (clientKSE->ke == NULL)
+            continue;
+
         /* Check consistency now - extensions in any order. */
         if (!TLSX_SupportedGroups_Find(ssl, clientKSE->group))
@@ -6024,11 +7267,23 @@
 
     #ifdef OPENSSL_EXTRA
+        if ((clientKSE->group & NAMED_DH_MASK) == 0) {
         /* Check if server supports group. */
         if (ssl->ctx->disabledCurves & (1 << clientKSE->group))
             continue;
-    #endif
-        if (TLSX_KeyShare_IsSupported(clientKSE->group))
-            break;
-    }
+        }
+    #endif
+        if (!TLSX_KeyShare_IsSupported(clientKSE->group))
+            continue;
+
+        rank = TLSX_KeyShare_GroupRank(ssl, clientKSE->group);
+        if (rank == -1)
+            continue;
+        if (rank < preferredRank) {
+            preferredKSE = clientKSE;
+            preferredRank = rank;
+    }
+    }
+    clientKSE = preferredKSE;
+
     /* No supported group found - send HelloRetryRequest. */
     if (clientKSE == NULL) {
@@ -6045,34 +7300,56 @@
     if (ret != 0)
         return ret;
-    ret = TLSX_KeyShare_GenKey(ssl, serverKSE);
+
+    if (clientKSE->key == NULL) {
+        ret = TLSX_KeyShare_GenKey(ssl, serverKSE);
     if (ret != 0)
         return ret;
-
-    /* Move private key to client entry. */
-    if (clientKSE->key != NULL)
-        XFREE(clientKSE->key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
-    clientKSE->key = serverKSE->key;
-    serverKSE->key = NULL;
-    clientKSE->keyLen = serverKSE->keyLen;
+    }
+    else {
+        serverKSE->key = clientKSE->key;
+        serverKSE->keyLen = clientKSE->keyLen;
+        serverKSE->pubKey = clientKSE->pubKey;
+        serverKSE->pubKeyLen = clientKSE->pubKeyLen;
+        clientKSE->key = NULL;
+        clientKSE->pubKey = NULL;
+    }
+    serverKSE->ke = clientKSE->ke;
+    serverKSE->keLen = clientKSE->keLen;
+    clientKSE->ke = NULL;
+    clientKSE->keLen = 0;
+
+    TLSX_KeyShare_FreeAll((KeyShareEntry*)extension->data, ssl->heap);
+    extension->data = (void *)serverKSE;
+
+    extension->resp = 1;
+
+    return 0;
+}
+
+/* Derive the shared secret of the key exchange.
+ *
+ * ssl  The SSL/TLS object.
+ * returns 0 on success and other values indicate failure.
+ */
+int TLSX_KeyShare_DeriveSecret(WOLFSSL *ssl)
+{
+    int            ret;
+    TLSX*          extension;
+    KeyShareEntry* list = NULL;
+
+    /* Find the KeyShare extension if it exists. */
+    extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
+    if (extension != NULL)
+        list = (KeyShareEntry*)extension->data;
+
+    if (list == NULL)
+        return KEY_SHARE_ERROR;
 
     /* Calculate secret. */
-    ret = TLSX_KeyShare_Process(ssl, clientKSE);
+    ret = TLSX_KeyShare_Process(ssl, list);
     if (ret != 0)
         return ret;
 
-    /* Swap public keys for sending to client. */
-    ke = serverKSE->ke;
-    keLen = serverKSE->keLen;
-    serverKSE->ke = clientKSE->ke;
-    serverKSE->keLen = clientKSE->keLen;
-    clientKSE->ke = ke;
-    clientKSE->keLen = keLen;
-
-    extension->resp = 1;
-
-    /* Dispose of temporary server extension. */
-    TLSX_KeyShare_FreeAll(list, ssl->heap);
-
-    return 0;
+    return ret;
 }
 
@@ -6291,4 +7568,6 @@
         word16 idx = 0;
 
+        TLSX_Remove(&ssl->extensions, TLSX_PRE_SHARED_KEY, ssl->heap);
+
         /* Length of identities and of binders. */
         if (length - idx < OPAQUE16_LEN + OPAQUE16_LEN)
@@ -6348,5 +7627,5 @@
             list->binderLen = input[idx++];
             if (list->binderLen < WC_SHA256_DIGEST_SIZE ||
-                    list->binderLen > MAX_DIGEST_SIZE)
+                    list->binderLen > WC_MAX_DIGEST_SIZE)
                 return BUFFER_E;
             if (len < OPAQUE8_LEN + list->binderLen)
@@ -6376,4 +7655,8 @@
             return BUFFER_E;
         ato16(input, &idx);
+
+    #ifdef WOLFSSL_EARLY_DATA
+        ssl->options.pskIdIndex = idx + 1;
+    #endif
 
         /* Find the list of identities sent to server. */
@@ -6395,14 +7678,10 @@
            if (ssl->options.cipherSuite0  != ssl->session.cipherSuite0 ||
                ssl->options.cipherSuite   != ssl->session.cipherSuite  ||
-               ssl->session.version.major != ssl->version.major        ||
-               ssl->session.version.minor != ssl->version.minor        ) {
+               ssl->session.version.major != ssl->ctx->method->version.major ||
+               ssl->session.version.minor != ssl->ctx->method->version.minor) {
                return PSK_KEY_ERROR;
            }
         }
     #endif
-        /* TODO: [TLS13] More checks of consistency.
-         * the "key_share", and "signature_algorithms" extensions are
-         * consistent with the indicated ke_modes and auth_modes values
-         */
 
         return 0;
@@ -6450,5 +7729,5 @@
 }
 
-static INLINE byte GetHmacLength(int hmac)
+static WC_INLINE byte GetHmacLength(int hmac)
 {
     switch (hmac) {
@@ -6457,9 +7736,9 @@
             return WC_SHA256_DIGEST_SIZE;
     #endif
-    #ifndef NO_SHA384
+    #ifdef WOLFSSL_SHA384
         case sha384_mac:
             return WC_SHA384_DIGEST_SIZE;
     #endif
-    #ifndef NO_SHA512
+    #ifdef WOLFSSL_SHA512
         case sha512_mac:
             return WC_SHA512_DIGEST_SIZE;
@@ -6713,5 +7992,5 @@
 {
     if (msgType == client_hello)
-        return OPAQUE8_LEN;
+        return 0;
 
     return SANITY_MSG_E;
@@ -6728,8 +8007,8 @@
 static word16 TLSX_PostHandAuth_Write(byte* output, byte msgType)
 {
-    if (msgType == client_hello) {
-        *output = 0;
-        return OPAQUE8_LEN;
-    }
+    (void)output;
+
+    if (msgType == client_hello)
+        return 0;
 
     return SANITY_MSG_E;
@@ -6748,13 +8027,9 @@
                                  byte msgType)
 {
-    byte len;
+    (void)input;
 
     if (msgType == client_hello) {
-        /* Ensure length byte exists. */
-        if (length < OPAQUE8_LEN)
-            return BUFFER_E;
-
-        len = input[0];
-        if (length - OPAQUE8_LEN != len || len != 0)
+        /* Ensure extension is empty. */
+        if (length != 0)
             return BUFFER_E;
 
@@ -6866,4 +8141,10 @@
             return BUFFER_E;
 
+        /* Ensure the index of PSK identity chosen by server is 0.
+         * Index is plus one to handle 'not set' value of 0.
+         */
+        if (ssl->options.pskIdIndex != 1)
+            return PSK_KEY_ERROR;
+
         return TLSX_EarlyData_Use(ssl, 1);
     }
@@ -6939,4 +8220,22 @@
 }
 
+/** Remove an extension. */
+void TLSX_Remove(TLSX** list, TLSX_Type type, void* heap)
+{
+    TLSX* extension = *list;
+    TLSX** next = list;
+
+    while (extension && extension->type != type) {
+        next = &extension->next;
+        extension = extension->next;
+    }
+
+    if (extension) {
+        *next = extension->next;
+        extension->next = NULL;
+        TLSX_FreeAll(extension, heap);
+    }
+}
+
 /** Releases all extensions in the provided list. */
 void TLSX_FreeAll(TLSX* list, void* heap)
@@ -7005,8 +8304,4 @@
                 break;
 
-            case TLSX_KEY_SHARE:
-                KS_FREE_ALL((KeyShareEntry*)extension->data, heap);
-                break;
-
     #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
             case TLSX_PRE_SHARED_KEY:
@@ -7027,4 +8322,13 @@
                 break;
     #endif
+
+    #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+            case TLSX_SIGNATURE_ALGORITHMS_CERT:
+                break;
+    #endif
+
+            case TLSX_KEY_SHARE:
+                KS_FREE_ALL((KeyShareEntry*)extension->data, heap);
+                break;
 #endif
         }
@@ -7042,6 +8346,7 @@
 
 /** Tells the buffered size of the extensions in a list. */
-static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType)
-{
+static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType, word16* pLength)
+{
+    int    ret = 0;
     TLSX*  extension;
     word16 length = 0;
@@ -7123,13 +8428,9 @@
 #ifdef WOLFSSL_TLS13
             case TLSX_SUPPORTED_VERSIONS:
-                length += SV_GET_SIZE(extension->data);
+                ret = SV_GET_SIZE(extension->data, msgType, &length);
                 break;
 
             case TLSX_COOKIE:
-                length += CKE_GET_SIZE((Cookie*)extension->data, msgType);
-                break;
-
-            case TLSX_KEY_SHARE:
-                length += KS_GET_SIZE((KeyShareEntry*)extension->data, msgType);
+                ret = CKE_GET_SIZE((Cookie*)extension->data, msgType, &length);
                 break;
 
@@ -7155,4 +8456,14 @@
                 break;
     #endif
+
+    #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+            case TLSX_SIGNATURE_ALGORITHMS_CERT:
+                length += SAC_GET_SIZE(extension->data);
+                break;
+    #endif
+
+            case TLSX_KEY_SHARE:
+                length += KS_GET_SIZE((KeyShareEntry*)extension->data, msgType);
+                break;
 #endif
         }
@@ -7163,11 +8474,14 @@
     }
 
-    return length;
+    *pLength += length;
+
+    return ret;
 }
 
 /** Writes the extensions of a list in a buffer. */
-static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore,
-                         byte msgType)
-{
+static int TLSX_Write(TLSX* list, byte* output, byte* semaphore,
+                         byte msgType, word16* pOffset)
+{
+    int    ret = 0;
     TLSX* extension;
     word16 offset = 0;
@@ -7212,5 +8526,5 @@
 
             case TLSX_SUPPORTED_GROUPS:
-                WOLFSSL_MSG("Elliptic Curves extension to write");
+                WOLFSSL_MSG("Supported Groups extension to write");
                 offset += EC_WRITE((SupportedCurve*)extension->data,
                                     output + offset);
@@ -7270,17 +8584,11 @@
             case TLSX_SUPPORTED_VERSIONS:
                 WOLFSSL_MSG("Supported Versions extension to write");
-                offset += SV_WRITE(extension->data, output + offset);
+                ret = SV_WRITE(extension->data, output + offset, msgType, &offset);
                 break;
 
             case TLSX_COOKIE:
                 WOLFSSL_MSG("Cookie extension to write");
-                offset += CKE_WRITE((Cookie*)extension->data, output + offset,
-                                    msgType);
-                break;
-
-            case TLSX_KEY_SHARE:
-                WOLFSSL_MSG("Key Share extension to write");
-                offset += KS_WRITE((KeyShareEntry*)extension->data,
-                                   output + offset, msgType);
+                ret = CKE_WRITE((Cookie*)extension->data, output + offset,
+                                msgType, &offset);
                 break;
 
@@ -7311,4 +8619,17 @@
                 break;
     #endif
+
+    #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+            case TLSX_SIGNATURE_ALGORITHMS_CERT:
+                WOLFSSL_MSG("Signature Algorithms extension to write");
+                offset += SAC_WRITE(extension->data, output + offset);
+                break;
+    #endif
+
+            case TLSX_KEY_SHARE:
+                WOLFSSL_MSG("Key Share extension to write");
+                offset += KS_WRITE((KeyShareEntry*)extension->data,
+                                   output + offset, msgType);
+                break;
 #endif
         }
@@ -7322,5 +8643,7 @@
     }
 
-    return offset;
+    *pOffset += offset;
+
+    return ret;
 }
 
@@ -7516,4 +8839,181 @@
 #endif /* HAVE_QSH */
 
+#if (!defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_TLS13) && \
+        !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)) || \
+    (defined(WOLFSSL_TLS13) && !defined(HAVE_ECC) && \
+        !defined(HAVE_CURVE25519) && defined(HAVE_SUPPORTED_CURVES)) || \
+    ((defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \
+        defined(HAVE_SUPPORTED_CURVES))
+
+/* Populates the default supported groups / curves */
+static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions)
+{
+    int ret = WOLFSSL_SUCCESS;
+#ifdef WOLFSSL_TLS13
+    int i;
+
+#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+    if (ssl->options.resuming && ssl->session.namedGroup != 0) {
+        return TLSX_UseSupportedCurve(extensions, ssl->session.namedGroup,
+                                                                     ssl->heap);
+        }
+#endif
+
+    if (ssl->numGroups != 0) {
+        for (i = 0; i < ssl->numGroups; i++) {
+            ret = TLSX_UseSupportedCurve(extensions, ssl->group[i], ssl->heap);
+            if (ret != WOLFSSL_SUCCESS)
+                        return ret;
+            }
+        return WOLFSSL_SUCCESS;
+        }
+#endif /* WOLFSSL_TLS13 */
+
+#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
+        /* list in order by strength, since not all servers choose by strength */
+        #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)
+            #ifndef NO_ECC_SECP
+                ret = TLSX_UseSupportedCurve(extensions,
+                                              WOLFSSL_ECC_SECP521R1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+        #endif
+        #if defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES)
+            #ifdef HAVE_ECC_BRAINPOOL
+                ret = TLSX_UseSupportedCurve(extensions,
+                                        WOLFSSL_ECC_BRAINPOOLP512R1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+        #endif
+        #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
+            #ifndef NO_ECC_SECP
+                ret = TLSX_UseSupportedCurve(extensions,
+                                              WOLFSSL_ECC_SECP384R1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+            #ifdef HAVE_ECC_BRAINPOOL
+                ret = TLSX_UseSupportedCurve(extensions,
+                                        WOLFSSL_ECC_BRAINPOOLP384R1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+        #endif
+        #endif
+        #if !defined(NO_ECC256)  || defined(HAVE_ALL_CURVES)
+            #ifndef NO_ECC_SECP
+                ret = TLSX_UseSupportedCurve(extensions,
+                                              WOLFSSL_ECC_SECP256R1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+            #ifdef HAVE_ECC_KOBLITZ
+                ret = TLSX_UseSupportedCurve(extensions,
+                                              WOLFSSL_ECC_SECP256K1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+            #ifdef HAVE_ECC_BRAINPOOL
+                ret = TLSX_UseSupportedCurve(extensions,
+                                        WOLFSSL_ECC_BRAINPOOLP256R1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+        #endif
+#endif /* HAVE_ECC && HAVE_SUPPORTED_CURVES */
+
+        #ifndef HAVE_FIPS
+            #if defined(HAVE_CURVE25519)
+                ret = TLSX_UseSupportedCurve(extensions,
+                                                 WOLFSSL_ECC_X25519, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+    #endif
+        #endif /* HAVE_FIPS */
+
+#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
+        #if defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES)
+            #ifndef NO_ECC_SECP
+                ret = TLSX_UseSupportedCurve(extensions,
+                                              WOLFSSL_ECC_SECP224R1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+            #ifdef HAVE_ECC_KOBLITZ
+                ret = TLSX_UseSupportedCurve(extensions,
+                                              WOLFSSL_ECC_SECP224K1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+        #endif
+
+    #ifndef HAVE_FIPS
+        #if defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES)
+            #ifndef NO_ECC_SECP
+                ret = TLSX_UseSupportedCurve(extensions,
+                                              WOLFSSL_ECC_SECP192R1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+            #ifdef HAVE_ECC_KOBLITZ
+                ret = TLSX_UseSupportedCurve(extensions,
+                                              WOLFSSL_ECC_SECP192K1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+        #endif
+        #if defined(HAVE_ECC160) || defined(HAVE_ALL_CURVES)
+            #ifndef NO_ECC_SECP
+                ret = TLSX_UseSupportedCurve(extensions,
+                                              WOLFSSL_ECC_SECP160R1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+            #ifdef HAVE_ECC_SECPR2
+                ret = TLSX_UseSupportedCurve(extensions,
+                                              WOLFSSL_ECC_SECP160R2, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+            #ifdef HAVE_ECC_KOBLITZ
+                ret = TLSX_UseSupportedCurve(extensions,
+                                              WOLFSSL_ECC_SECP160K1, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS) return ret;
+            #endif
+        #endif
+    #endif /* HAVE_FIPS */
+#endif /* HAVE_ECC && HAVE_SUPPORTED_CURVES */
+
+    #ifdef WOLFSSL_TLS13
+        if (IsAtLeastTLSv1_3(ssl->version)) {
+                /* Add FFDHE supported groups. */
+        #ifdef HAVE_FFDHE_8192
+                ret = TLSX_UseSupportedCurve(extensions,
+                                             WOLFSSL_FFDHE_8192, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS)
+                    return ret;
+        #endif
+        #ifdef HAVE_FFDHE_6144
+                ret = TLSX_UseSupportedCurve(extensions,
+                                             WOLFSSL_FFDHE_6144, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS)
+                    return ret;
+        #endif
+        #ifdef HAVE_FFDHE_4096
+                ret = TLSX_UseSupportedCurve(extensions,
+                                             WOLFSSL_FFDHE_4096, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS)
+                    return ret;
+        #endif
+        #ifdef HAVE_FFDHE_3072
+                ret = TLSX_UseSupportedCurve(extensions,
+                                             WOLFSSL_FFDHE_3072, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS)
+                    return ret;
+        #endif
+        #ifdef HAVE_FFDHE_2048
+                ret = TLSX_UseSupportedCurve(extensions,
+                                             WOLFSSL_FFDHE_2048, ssl->heap);
+                if (ret != WOLFSSL_SUCCESS)
+                    return ret;
+        #endif
+        }
+    #endif /* WOLFSSL_TLS13 */
+
+    (void)ssl;
+    (void)extensions;
+
+    return ret;
+}
+
+#endif
+
 int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer)
 {
@@ -7531,5 +9031,5 @@
     /* add supported QSHSchemes */
     WOLFSSL_MSG("Adding supported QSH Schemes");
-#endif
+            #endif
 
     /* server will add extension depending on whats parsed from client */
@@ -7605,103 +9105,25 @@
             }
         }
-#endif
-
-#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
-        if (!ssl->options.userCurves && !ssl->ctx->userCurves &&
-               TLSX_Find(ssl->ctx->extensions, TLSX_SUPPORTED_GROUPS) == NULL) {
-
-    #ifndef HAVE_FIPS
-        #if defined(HAVE_ECC160) || defined(HAVE_ALL_CURVES)
-            #ifndef NO_ECC_SECP
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                              WOLFSSL_ECC_SECP160R1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-            #ifdef HAVE_ECC_SECPR2
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                              WOLFSSL_ECC_SECP160R2, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-            #ifdef HAVE_ECC_KOBLITZ
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                              WOLFSSL_ECC_SECP160K1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
         #endif
-        #if defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES)
-            #ifndef NO_ECC_SECP
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                              WOLFSSL_ECC_SECP192R1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-            #ifdef HAVE_ECC_KOBLITZ
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                              WOLFSSL_ECC_SECP192K1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-        #endif
-    #endif
-        #if defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES)
-            #ifndef NO_ECC_SECP
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                              WOLFSSL_ECC_SECP224R1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-            #ifdef HAVE_ECC_KOBLITZ
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                              WOLFSSL_ECC_SECP224K1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-        #endif
-        #if !defined(NO_ECC256)  || defined(HAVE_ALL_CURVES)
-            #ifndef NO_ECC_SECP
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                              WOLFSSL_ECC_SECP256R1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-            #if defined(HAVE_CURVE25519)
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                                 WOLFSSL_ECC_X25519, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-            #ifdef HAVE_ECC_KOBLITZ
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                              WOLFSSL_ECC_SECP256K1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-            #ifdef HAVE_ECC_BRAINPOOL
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                        WOLFSSL_ECC_BRAINPOOLP256R1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-        #endif
-        #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
-            #ifndef NO_ECC_SECP
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                              WOLFSSL_ECC_SECP384R1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-            #ifdef HAVE_ECC_BRAINPOOL
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                        WOLFSSL_ECC_BRAINPOOLP384R1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-        #endif
-        #if defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES)
-            #ifdef HAVE_ECC_BRAINPOOL
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                        WOLFSSL_ECC_BRAINPOOLP512R1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-        #endif
-        #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)
-            #ifndef NO_ECC_SECP
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                              WOLFSSL_ECC_SECP521R1, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS) return ret;
-            #endif
-        #endif
-        }
-#endif /* HAVE_ECC && HAVE_SUPPORTED_CURVES */
+
+#if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \
+                                                  defined(HAVE_SUPPORTED_CURVES)
+        if (!ssl->options.userCurves && !ssl->ctx->userCurves) {
+            if (TLSX_Find(ssl->ctx->extensions,
+                                               TLSX_SUPPORTED_GROUPS) == NULL) {
+                ret = TLSX_PopulateSupportedGroups(ssl, &ssl->extensions);
+                if (ret != WOLFSSL_SUCCESS)
+                    return ret;
+        }
+        }
+        if ((!IsAtLeastTLSv1_3(ssl->version) || ssl->options.downgrade) &&
+               TLSX_Find(ssl->ctx->extensions, TLSX_EC_POINT_FORMATS) == NULL &&
+               TLSX_Find(ssl->extensions, TLSX_EC_POINT_FORMATS) == NULL) {
+             ret = TLSX_UsePointFormat(&ssl->extensions,
+                                         WOLFSSL_EC_PF_UNCOMPRESSED, ssl->heap);
+             if (ret != WOLFSSL_SUCCESS)
+                 return ret;
+        }
+#endif /* (HAVE_ECC || HAVE_CURVE25519) && HAVE_SUPPORTED_CURVES */
     } /* is not server */
 
@@ -7717,80 +9139,73 @@
             WOLFSSL_MSG("Adding supported versions extension");
             if ((ret = TLSX_SetSupportedVersions(&ssl->extensions, ssl,
-                                                 ssl->heap)) != 0)
+                                                             ssl->heap)) != 0) {
                 return ret;
-
-#ifdef HAVE_SUPPORTED_CURVES
-            if (!ssl->options.userCurves && !ssl->ctx->userCurves &&
-                TLSX_Find(ssl->ctx->extensions, TLSX_SUPPORTED_GROUPS)
-                                                                      == NULL) {
-                /* Add FFDHE supported groups. */
-        #ifdef HAVE_FFDHE_2048
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                             WOLFSSL_FFDHE_2048, ssl->heap);
+            }
+
+    #if !defined(HAVE_ECC) && !defined(HAVE_CURVE25519) && \
+                                                  defined(HAVE_SUPPORTED_CURVES)
+        if (TLSX_Find(ssl->ctx->extensions, TLSX_SUPPORTED_GROUPS) == NULL) {
+            /* Put in DH groups for TLS 1.3 only. */
+            ret = TLSX_PopulateSupportedGroups(ssl, &ssl->extensions);
                 if (ret != WOLFSSL_SUCCESS)
                     return ret;
-        #endif
-        #ifdef HAVE_FFDHE_3072
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                             WOLFSSL_FFDHE_3072, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS)
-                    return ret;
-        #endif
-        #ifdef HAVE_FFDHE_4096
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                             WOLFSSL_FFDHE_4096, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS)
-                    return ret;
-        #endif
-        #ifdef HAVE_FFDHE_6144
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                             WOLFSSL_FFDHE_6144, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS)
-                    return ret;
-        #endif
-        #ifdef HAVE_FFDHE_8192
-                ret = TLSX_UseSupportedCurve(&ssl->extensions,
-                                             WOLFSSL_FFDHE_8192, ssl->heap);
-                if (ret != WOLFSSL_SUCCESS)
-                    return ret;
-        #endif
                 ret = 0;
             }
-#endif
+    #endif /* !HAVE_ECC && !HAVE_CURVE25519 && HAVE_SUPPORTED_CURVES */
+
+        #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+            if (ssl->certHashSigAlgoSz > 0) {
+                WOLFSSL_MSG("Adding signature algorithms cert extension");
+                if ((ret = TLSX_SetSignatureAlgorithmsCert(&ssl->extensions,
+                                                        ssl, ssl->heap)) != 0) {
+                    return ret;
+                }
+            }
+        #endif /* !WOLFSSL_TLS13_DRAFT_18 && !WOLFSSL_TLS13_DRAFT_22 */
 
             if (TLSX_Find(ssl->extensions, TLSX_KEY_SHARE) == NULL) {
-        #if (!defined(NO_ECC256)  || defined(HAVE_ALL_CURVES)) && \
-            !defined(NO_ECC_SECP)
-                ret = TLSX_KeyShare_Use(ssl, WOLFSSL_ECC_SECP256R1, 0, NULL,
-                                        NULL);
+                word16 namedGroup;
+
+        #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+                if (ssl->options.resuming && ssl->session.namedGroup != 0)
+                    namedGroup = ssl->session.namedGroup;
+                else
+        #endif
+                {
+        #if defined(HAVE_ECC) && (!defined(NO_ECC256) || \
+                              defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP)
+                    namedGroup = WOLFSSL_ECC_SECP256R1;
         #elif defined(HAVE_CURVE25519)
-                ret = TLSX_KeyShare_Use(ssl, WOLFSSL_ECC_X25519, 0, NULL, NULL);
-        #elif (!defined(NO_ECC384)  || defined(HAVE_ALL_CURVES)) && \
-              !defined(NO_ECC_SECP)
-                ret = TLSX_KeyShare_Use(ssl, WOLFSSL_ECC_SECP384R1, 0, NULL,
-                                        NULL);
-        #elif (!defined(NO_ECC521)  || defined(HAVE_ALL_CURVES)) && \
-              !defined(NO_ECC_SECP)
-                ret = TLSX_KeyShare_Use(ssl, WOLFSSL_ECC_SECP521R1, 0, NULL,
-                                        NULL);
+                    namedGroup = WOLFSSL_ECC_X25519;
+        #elif defined(HAVE_ECC) && (!defined(NO_ECC384) || \
+                              defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP)
+                    namedGroup = WOLFSSL_ECC_SECP384R1;
+        #elif defined(HAVE_ECC) && (!defined(NO_ECC521) || \
+                              defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP)
+                    namedGroup = WOLFSSL_ECC_SECP521R1;
         #elif defined(HAVE_FFDHE_2048)
-                ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_2048, 0, NULL, NULL);
+                    namedGroup = WOLFSSL_FFDHE_2048;
         #elif defined(HAVE_FFDHE_3072)
-                ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_3072, 0, NULL, NULL);
+                    namedGroup = WOLFSSL_FFDHE_3072;
         #elif defined(HAVE_FFDHE_4096)
-                ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_4096, 0, NULL, NULL);
+                    namedGroup = WOLFSSL_FFDHE_4096;
         #elif defined(HAVE_FFDHE_6144)
-                ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_6144, 0, NULL, NULL);
+                    namedGroup = WOLFSSL_FFDHE_6144;
         #elif defined(HAVE_FFDHE_8192)
-                ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_8192, 0, NULL, NULL);
+                    namedGroup = WOLFSSL_FFDHE_8192;
         #else
-                ret = KEY_SHARE_ERROR;
+                    return KEY_SHARE_ERROR;
         #endif
+                }
+                ret = TLSX_KeyShare_Use(ssl, namedGroup, 0, NULL, NULL);
                 if (ret != 0)
                     return ret;
             }
 
+        #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+            TLSX_Remove(&ssl->extensions, TLSX_PRE_SHARED_KEY, ssl->heap);
+        #endif
         #if defined(HAVE_SESSION_TICKET)
-            if (ssl->options.resuming) {
+            if (ssl->options.resuming && ssl->session.ticketLen > 0) {
                 WOLFSSL_SESSION* sess = &ssl->session;
                 word32           milli;
@@ -7839,5 +9254,5 @@
                 ret = TLSX_PreSharedKey_Use(ssl,
                                           (byte*)ssl->arrays->client_identity,
-                                          XSTRLEN(ssl->arrays->client_identity),
+                                  (word16)XSTRLEN(ssl->arrays->client_identity),
                                           0, ssl->specs.mac_algorithm,
                                           cipherSuite0, cipherSuite, 0,
@@ -7855,5 +9270,5 @@
                 /* Pre-shared key modes: mandatory extension for resumption. */
                 modes = 1 << PSK_KE;
-            #if !defined(NO_DH) || defined(HAVE_ECC)
+            #if !defined(NO_DH) || defined(HAVE_ECC) || defined(HAVE_CURVE25519)
                 if (!ssl->options.noPskDheKe)
                     modes |= 1 << PSK_DHE_KE;
@@ -7880,16 +9295,14 @@
     (void)ssl;
 
-    if (ret == WOLFSSL_SUCCESS)
-        ret = 0;
-
     return ret;
 }
 
 
-#ifndef NO_WOLFSSL_CLIENT
+#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_CLIENT)
 
 /** Tells the buffered size of extensions to be sent into the client hello. */
-word16 TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType)
-{
+int TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType, word16* pLength)
+{
+    int ret = 0;
     word16 length = 0;
     byte semaphore[SEMAPHORE_SIZE] = {0};
@@ -7921,4 +9334,16 @@
     #endif
         }
+    #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+        if (IsAtLeastTLSv1_3(ssl->version) && ssl->options.noPskDheKe) {
+        #if !defined(NO_PSK)
+            if (ssl->options.havePSK)
+                TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+        #endif
+        #if defined(HAVE_SESSION_TICKET)
+            if (ssl->options.resuming)
+                TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+        #endif
+        }
+    #endif
 #endif
     #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \
@@ -7936,7 +9361,7 @@
         XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
         TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
-        TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
         /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP,
          *       TLSX_CERTIFICATE_AUTHORITIES, OID_FILTERS
+         *       TLSX_STATUS_REQUEST
          */
     }
@@ -7945,11 +9370,11 @@
 
     if (ssl->extensions)
-        length += TLSX_GetSize(ssl->extensions, semaphore, msgType);
+        ret = TLSX_GetSize(ssl->extensions, semaphore, msgType, &length);
     if (ssl->ctx && ssl->ctx->extensions)
-        length += TLSX_GetSize(ssl->ctx->extensions, semaphore, msgType);
+        ret = TLSX_GetSize(ssl->ctx->extensions, semaphore, msgType, &length);
 
 #ifdef HAVE_EXTENDED_MASTER
     if (msgType == client_hello && ssl->options.haveEMS &&
-                                              !IsAtLeastTLSv1_3(ssl->version)) {
+                  (!IsAtLeastTLSv1_3(ssl->version) || ssl->options.downgrade)) {
         length += HELLO_EXT_SZ;
     }
@@ -7959,10 +9384,13 @@
         length += OPAQUE16_LEN; /* for total length storage. */
 
-    return length;
+    *pLength += length;
+
+    return ret;
 }
 
 /** Writes the extensions to be sent into the client hello. */
-word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output, byte msgType)
-{
+int TLSX_WriteRequest(WOLFSSL* ssl, byte* output, byte msgType, word16* pOffset)
+{
+    int ret = 0;
     word16 offset = 0;
     byte semaphore[SEMAPHORE_SIZE] = {0};
@@ -7997,4 +9425,16 @@
         }
     #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+        if (IsAtLeastTLSv1_3(ssl->version) && ssl->options.noPskDheKe) {
+        #if !defined(NO_PSK)
+            if (ssl->options.havePSK)
+                TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+        #endif
+        #if defined(HAVE_SESSION_TICKET)
+            if (ssl->options.resuming)
+                TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+        #endif
+        }
+    #endif
+    #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
         /* Must write Pre-shared Key extension at the end in TLS v1.3.
          * Must not write out Pre-shared Key extension in earlier versions of
@@ -8018,7 +9458,7 @@
         XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
         TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
-        TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
         /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP,
          *       TLSX_CERTIFICATE_AUTHORITIES, TLSX_OID_FILTERS
+         *       TLSX_STATUS_REQUEST
          */
     }
@@ -8027,15 +9467,16 @@
 
     if (ssl->extensions) {
-        offset += TLSX_Write(ssl->extensions, output + offset, semaphore,
-                             msgType);
+        ret = TLSX_Write(ssl->extensions, output + offset, semaphore,
+                         msgType, &offset);
     }
     if (ssl->ctx && ssl->ctx->extensions) {
-        offset += TLSX_Write(ssl->ctx->extensions, output + offset, semaphore,
-                             msgType);
+        ret = TLSX_Write(ssl->ctx->extensions, output + offset, semaphore,
+                         msgType, &offset);
     }
 
 #ifdef HAVE_EXTENDED_MASTER
     if (msgType == client_hello && ssl->options.haveEMS &&
-                                              !IsAtLeastTLSv1_3(ssl->version)) {
+                  (!IsAtLeastTLSv1_3(ssl->version) || ssl->options.downgrade)) {
+        WOLFSSL_MSG("EMS extension to write");
         c16toa(HELLO_EXT_EXTMS, output + offset);
         offset += HELLO_EXT_TYPE_SZ;
@@ -8050,6 +9491,6 @@
         /* Write out what we can of Pre-shared key extension.  */
         TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
-        offset += TLSX_Write(ssl->extensions, output + offset, semaphore,
-                             client_hello);
+        ret = TLSX_Write(ssl->extensions, output + offset, semaphore,
+                         client_hello, &offset);
     }
     #endif
@@ -8059,18 +9500,22 @@
         c16toa(offset - OPAQUE16_LEN, output); /* extensions length */
 
-    return offset;
-}
-
-#endif /* NO_WOLFSSL_CLIENT */
-
-#ifndef NO_WOLFSSL_SERVER
+     *pOffset += offset;
+
+    return ret;
+}
+
+#endif /* WOLFSSL_TLS13 || !NO_WOLFSSL_CLIENT */
+
+#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_SERVER)
 
 /** Tells the buffered size of extensions to be sent into the server hello. */
-word16 TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType)
-{
+int TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType, word16* pLength)
+{
+    int ret = 0;
     word16 length = 0;
     byte semaphore[SEMAPHORE_SIZE] = {0};
 
     switch (msgType) {
+#ifndef NO_WOLFSSL_SERVER
         case server_hello:
             PF_VALIDATE_RESPONSE(ssl, semaphore);
@@ -8078,4 +9523,9 @@
                 if (ssl->options.tls1_3) {
                     XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+        #ifndef WOLFSSL_TLS13_DRAFT_18
+                    TURN_OFF(semaphore,
+                                     TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
+        #endif
+                    if (!ssl->options.noPskDheKe)
                     TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
     #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
@@ -8083,15 +9533,29 @@
     #endif
                 }
+                else {
+                    TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+        #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+                    TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
+        #endif
+                }
 #endif
             break;
+
 #ifdef WOLFSSL_TLS13
         case hello_retry_request:
             XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+        #ifndef WOLFSSL_TLS13_DRAFT_18
+                TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
+        #endif
+            if (!ssl->options.noPskDheKe)
             TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
             TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_COOKIE));
-#endif
             break;
+    #endif
+
 #ifdef WOLFSSL_TLS13
         case encrypted_extensions:
+            TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS));
+            TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET));
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
@@ -8099,5 +9563,9 @@
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
     #endif
+        #ifdef HAVE_CERTIFICATE_STATUS_REQUEST
+            TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
+        #endif
             break;
+
     #ifdef WOLFSSL_EARLY_DATA
         case session_ticket:
@@ -8108,4 +9576,8 @@
             break;
     #endif
+    #endif
+#endif
+
+#ifdef WOLFSSL_TLS13
     #ifndef NO_CERT
         case certificate:
@@ -8130,10 +9602,12 @@
 
 #ifdef HAVE_EXTENDED_MASTER
-    if (ssl->options.haveEMS && msgType == server_hello)
+    if (ssl->options.haveEMS && msgType == server_hello &&
+                                              !IsAtLeastTLSv1_3(ssl->version)) {
         length += HELLO_EXT_SZ;
+    }
 #endif
 
     if (TLSX_SupportExtensions(ssl))
-        length += TLSX_GetSize(ssl->extensions, semaphore, msgType);
+        ret = TLSX_GetSize(ssl->extensions, semaphore, msgType, &length);
 
     /* All the response data is set at the ssl object only, so no ctx here. */
@@ -8142,10 +9616,13 @@
         length += OPAQUE16_LEN; /* for total length storage. */
 
-    return length;
+    *pLength += length;
+
+    return ret;
 }
 
 /** Writes the server hello extensions into a buffer. */
-word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType)
-{
+int TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType, word16* pOffset)
+{
+    int ret = 0;
     word16 offset = 0;
 
@@ -8154,4 +9631,5 @@
 
         switch (msgType) {
+#ifndef NO_WOLFSSL_SERVER
             case server_hello:
                 PF_VALIDATE_RESPONSE(ssl, semaphore);
@@ -8159,4 +9637,9 @@
                 if (ssl->options.tls1_3) {
                     XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+        #ifndef WOLFSSL_TLS13_DRAFT_18
+                    TURN_OFF(semaphore,
+                                     TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
+        #endif
+                    if (!ssl->options.noPskDheKe)
                     TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
     #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
@@ -8164,14 +9647,29 @@
     #endif
                 }
-#endif
-                break;
+                else {
+                    TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+        #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+                    TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
+        #endif
+                }
+#endif
+                break;
+
 #ifdef WOLFSSL_TLS13
             case hello_retry_request:
                 XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
-                TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
-#endif
-                break;
+        #ifndef WOLFSSL_TLS13_DRAFT_18
+                TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
+#endif
+                if (!ssl->options.noPskDheKe)
+                    TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+                /* Cookie is written below as last extension. */
+                break;
+    #endif
+
 #ifdef WOLFSSL_TLS13
             case encrypted_extensions:
+                TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS));
+                TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
                 TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET));
                 TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
@@ -8179,5 +9677,21 @@
                 TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
     #endif
-                break;
+        #ifdef HAVE_CERTIFICATE_STATUS_REQUEST
+                TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
+        #endif
+                break;
+
+        #ifdef WOLFSSL_EARLY_DATA
+            case session_ticket:
+                if (ssl->options.tls1_3) {
+                    XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+                    TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA));
+                }
+                break;
+        #endif
+    #endif
+#endif
+
+    #ifdef WOLFSSL_TLS13
     #ifndef NO_CERTS
             case certificate:
@@ -8189,12 +9703,4 @@
                 break;
     #endif
-    #ifdef WOLFSSL_EARLY_DATA
-            case session_ticket:
-                if (ssl->options.tls1_3) {
-                    XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
-                    TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA));
-                }
-                break;
-    #endif
 #endif
         }
@@ -8202,6 +9708,6 @@
         offset += OPAQUE16_LEN; /* extensions length */
 
-        offset += TLSX_Write(ssl->extensions, output + offset, semaphore,
-                             msgType);
+        ret = TLSX_Write(ssl->extensions, output + offset, semaphore,
+                         msgType, &offset);
 
 #ifdef WOLFSSL_TLS13
@@ -8209,11 +9715,13 @@
             XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
             TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_COOKIE));
-            offset += TLSX_Write(ssl->extensions, output + offset, semaphore,
-                                 msgType);
+            ret = TLSX_Write(ssl->extensions, output + offset, semaphore,
+                             msgType, &offset);
         }
 #endif
 
 #ifdef HAVE_EXTENDED_MASTER
-        if (ssl->options.haveEMS && msgType == server_hello) {
+        if (ssl->options.haveEMS && msgType == server_hello &&
+                                              !IsAtLeastTLSv1_3(ssl->version)) {
+            WOLFSSL_MSG("EMS extension to write");
             c16toa(HELLO_EXT_EXTMS, output + offset);
             offset += HELLO_EXT_TYPE_SZ;
@@ -8227,8 +9735,11 @@
     }
 
-    return offset;
-}
-
-#endif /* NO_WOLFSSL_SERVER */
+    if (pOffset)
+        *pOffset += offset;
+
+    return ret;
+}
+
+#endif /* WOLFSSL_TLS13 || !NO_WOLFSSL_SERVER */
 
 /** Parses a buffer of TLS extensions. */
@@ -8240,6 +9751,10 @@
     byte isRequest = (msgType == client_hello ||
                       msgType == certificate_request);
+
 #ifdef HAVE_EXTENDED_MASTER
     byte pendingEMS = 0;
+#endif
+#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK))
+    int pskDone = 0;
 #endif
 
@@ -8251,4 +9766,9 @@
         word16 size;
 
+#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK))
+        if (msgType == client_hello && pskDone)
+            return PSK_KEY_ERROR;
+#endif
+
         if (length - offset < HELLO_EXT_TYPE_SZ + OPAQUE16_LEN)
             return BUFFER_ERROR;
@@ -8268,9 +9788,13 @@
 
 #ifdef WOLFSSL_TLS13
-                if (IsAtLeastTLSv1_3(ssl->version) &&
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
                         msgType != client_hello &&
                         msgType != encrypted_extensions) {
                     return EXT_NOT_ALLOWED;
                 }
+                else if (!IsAtLeastTLSv1_3(ssl->version) &&
+                         msgType == encrypted_extensions) {
+                    return EXT_NOT_ALLOWED;
+                }
 #endif
                 ret = SNI_PARSE(ssl, input + offset, size, isRequest);
@@ -8281,9 +9805,13 @@
 
 #ifdef WOLFSSL_TLS13
-                if (IsAtLeastTLSv1_3(ssl->version) &&
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
                         msgType != client_hello &&
                         msgType != encrypted_extensions) {
                     return EXT_NOT_ALLOWED;
                 }
+                else if (!IsAtLeastTLSv1_3(ssl->version) &&
+                         msgType == encrypted_extensions) {
+                    return EXT_NOT_ALLOWED;
+                }
 #endif
                 ret = MFL_PARSE(ssl, input + offset, size, isRequest);
@@ -8294,6 +9822,8 @@
 
 #ifdef WOLFSSL_TLS13
-                if (IsAtLeastTLSv1_3(ssl->version))
-                    return EXT_NOT_ALLOWED;
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
+                        !ssl->options.downgrade) {
+                    break;
+                }
 #endif
                 ret = THM_PARSE(ssl, input + offset, size, isRequest);
@@ -8301,12 +9831,16 @@
 
             case TLSX_SUPPORTED_GROUPS:
-                WOLFSSL_MSG("Elliptic Curves extension received");
+                WOLFSSL_MSG("Supported Groups extension received");
 
 #ifdef WOLFSSL_TLS13
-                if (IsAtLeastTLSv1_3(ssl->version) &&
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
                         msgType != client_hello &&
                         msgType != encrypted_extensions) {
                     return EXT_NOT_ALLOWED;
                 }
+                else if (!IsAtLeastTLSv1_3(ssl->version) &&
+                         msgType == encrypted_extensions) {
+                    return EXT_NOT_ALLOWED;
+                }
 #endif
                 ret = EC_PARSE(ssl, input + offset, size, isRequest);
@@ -8317,8 +9851,7 @@
 
 #ifdef WOLFSSL_TLS13
-                if (IsAtLeastTLSv1_3(ssl->version) &&
-                        msgType != client_hello &&
-                        msgType != encrypted_extensions) {
-                    return EXT_NOT_ALLOWED;
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
+                        !ssl->options.downgrade) {
+                    break;
                 }
 #endif
@@ -8330,8 +9863,7 @@
 
 #ifdef WOLFSSL_TLS13
-                if (IsAtLeastTLSv1_3(ssl->version) &&
-                        msgType != client_hello &&
-                        msgType != encrypted_extensions) {
-                    return EXT_NOT_ALLOWED;
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
+                        !ssl->options.downgrade) {
+                    break;
                 }
 #endif
@@ -8343,7 +9875,8 @@
 
 #ifdef WOLFSSL_TLS13
-                if (IsAtLeastTLSv1_3(ssl->version) &&
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
                         msgType != client_hello &&
-                        msgType != encrypted_extensions) {
+                        msgType != certificate_request &&
+                        msgType != certificate) {
                     return EXT_NOT_ALLOWED;
                 }
@@ -8355,4 +9888,33 @@
             case HELLO_EXT_EXTMS:
                 WOLFSSL_MSG("Extended Master Secret extension received");
+
+#ifdef WOLFSSL_TLS13
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
+                        !ssl->options.downgrade) {
+                    break;
+                }
+#endif
+#ifndef NO_WOLFSSL_SERVER
+                if (isRequest)
+                    ssl->options.haveEMS = 1;
+#endif
+                pendingEMS = 1;
+                break;
+#endif
+
+            case TLSX_RENEGOTIATION_INFO:
+                WOLFSSL_MSG("Secure Renegotiation extension received");
+
+#ifdef WOLFSSL_TLS13
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
+                        !ssl->options.downgrade) {
+                    break;
+                }
+#endif
+                ret = SCR_PARSE(ssl, input + offset, size, isRequest);
+                break;
+
+            case TLSX_SESSION_TICKET:
+                WOLFSSL_MSG("Session Ticket extension received");
 
 #ifdef WOLFSSL_TLS13
@@ -8362,27 +9924,4 @@
                 }
 #endif
-#ifndef NO_WOLFSSL_SERVER
-                if (isRequest && !IsAtLeastTLSv1_3(ssl->version))
-                    ssl->options.haveEMS = 1;
-#endif
-                pendingEMS = 1;
-                break;
-#endif
-
-            case TLSX_RENEGOTIATION_INFO:
-                WOLFSSL_MSG("Secure Renegotiation extension received");
-
-                ret = SCR_PARSE(ssl, input + offset, size, isRequest);
-                break;
-
-            case TLSX_SESSION_TICKET:
-                WOLFSSL_MSG("Session Ticket extension received");
-
-#ifdef WOLFSSL_TLS13
-                if (IsAtLeastTLSv1_3(ssl->version) &&
-                        msgType != client_hello) {
-                    return EXT_NOT_ALLOWED;
-                }
-#endif
                 ret = WOLF_STK_PARSE(ssl, input + offset, size, isRequest);
                 break;
@@ -8392,6 +9931,8 @@
 
 #ifdef WOLFSSL_TLS13
-                if (IsAtLeastTLSv1_3(ssl->version))
-                    return EXT_NOT_ALLOWED;
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
+                        !ssl->options.downgrade) {
+                    break;
+                }
 #endif
                 ret = QSH_PARSE(ssl, input + offset, size, isRequest);
@@ -8402,9 +9943,14 @@
 
 #ifdef WOLFSSL_TLS13
-                if (IsAtLeastTLSv1_3(ssl->version) &&
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
                         msgType != client_hello &&
+                        msgType != server_hello &&
                         msgType != encrypted_extensions) {
                     return EXT_NOT_ALLOWED;
                 }
+                else if (!IsAtLeastTLSv1_3(ssl->version) &&
+                         msgType == encrypted_extensions) {
+                    return EXT_NOT_ALLOWED;
+                }
 #endif
                 ret = ALPN_PARSE(ssl, input + offset, size, isRequest);
@@ -8417,10 +9963,12 @@
                     break;
 
-                if (IsAtLeastTLSv1_3(ssl->version) &&
+#ifdef WOLFSSL_TLS13
+                if (IsAtLeastTLSv1_3(ssl->ctx->method->version) &&
                         msgType != client_hello &&
                         msgType != certificate_request) {
                     return EXT_NOT_ALLOWED;
                 }
-                ret = SA_PARSE(ssl, input + offset, size, suites);
+#endif
+                ret = SA_PARSE(ssl, input + offset, size, isRequest, suites);
                 break;
 
@@ -8429,9 +9977,19 @@
                 WOLFSSL_MSG("Supported Versions extension received");
 
-                if (IsAtLeastTLSv1_3(ssl->version) &&
-                        msgType != client_hello) {
+                if (!IsAtLeastTLSv1_3(ssl->ctx->method->version))
+                    break;
+
+                if (
+    #ifdef WOLFSSL_TLS13_DRAFT_18
+                        msgType != client_hello
+    #else
+                        msgType != client_hello &&
+                        msgType != server_hello &&
+                        msgType != hello_retry_request
+    #endif
+                   ) {
                     return EXT_NOT_ALLOWED;
                 }
-                ret = SV_PARSE(ssl, input + offset, size);
+                ret = SV_PARSE(ssl, input + offset, size, msgType);
                 break;
 
@@ -8439,23 +9997,103 @@
                 WOLFSSL_MSG("Cookie extension received");
 
-                if (!IsAtLeastTLSv1_3(ssl->version))
+                if (!IsAtLeastTLSv1_3(ssl->ctx->method->version))
                     break;
 
-                if (IsAtLeastTLSv1_3(ssl->version) &&
-                        msgType != client_hello &&
+                if (msgType != client_hello &&
                         msgType != hello_retry_request) {
                     return EXT_NOT_ALLOWED;
                 }
+
                 ret = CKE_PARSE(ssl, input + offset, size, msgType);
                 break;
+
+    #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+            case TLSX_PRE_SHARED_KEY:
+                WOLFSSL_MSG("Pre-Shared Key extension received");
+
+                if (!IsAtLeastTLSv1_3(ssl->ctx->method->version))
+                    break;
+
+                if (msgType != client_hello && msgType != server_hello)
+                    return EXT_NOT_ALLOWED;
+
+                ret = PSK_PARSE(ssl, input + offset, size, msgType);
+                pskDone = 1;
+                break;
+
+            case TLSX_PSK_KEY_EXCHANGE_MODES:
+                WOLFSSL_MSG("PSK Key Exchange Modes extension received");
+
+                if (!IsAtLeastTLSv1_3(ssl->ctx->method->version))
+                    break;
+
+                if (msgType != client_hello)
+                    return EXT_NOT_ALLOWED;
+
+                ret = PKM_PARSE(ssl, input + offset, size, msgType);
+                break;
+    #endif
+
+    #ifdef WOLFSSL_EARLY_DATA
+            case TLSX_EARLY_DATA:
+                WOLFSSL_MSG("Early Data extension received");
+
+                if (!IsAtLeastTLSv1_3(ssl->ctx->method->version))
+                    break;
+
+                if (msgType != client_hello && msgType != session_ticket &&
+                         msgType != encrypted_extensions) {
+                    return EXT_NOT_ALLOWED;
+                }
+                if (!IsAtLeastTLSv1_3(ssl->version) &&
+                        (msgType == session_ticket ||
+                         msgType == encrypted_extensions)) {
+                    return EXT_NOT_ALLOWED;
+                }
+                ret = EDI_PARSE(ssl, input + offset, size, msgType);
+                break;
+    #endif
+
+    #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
+            case TLSX_POST_HANDSHAKE_AUTH:
+                WOLFSSL_MSG("Post Handshake Authentication extension received");
+
+                if (!IsAtLeastTLSv1_3(ssl->ctx->method->version))
+                    break;
+
+                if (msgType != client_hello)
+                    return EXT_NOT_ALLOWED;
+
+                ret = PHA_PARSE(ssl, input + offset, size, msgType);
+                break;
+    #endif
+
+    #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+            case TLSX_SIGNATURE_ALGORITHMS_CERT:
+                WOLFSSL_MSG("Signature Algorithms extension received");
+
+                if (!IsAtLeastTLSv1_3(ssl->ctx->method->version))
+                    break;
+
+                if (msgType != client_hello &&
+                        msgType != certificate_request) {
+                    return EXT_NOT_ALLOWED;
+                }
+                if (!IsAtLeastTLSv1_3(ssl->version) &&
+                        msgType == certificate_request) {
+                    return EXT_NOT_ALLOWED;
+                }
+
+                ret = SAC_PARSE(ssl, input + offset, size, isRequest);
+                break;
+    #endif
 
             case TLSX_KEY_SHARE:
                 WOLFSSL_MSG("Key Share extension received");
 
-                if (!IsAtLeastTLSv1_3(ssl->version))
+                if (!IsAtLeastTLSv1_3(ssl->ctx->method->version))
                     break;
 
-                if (IsAtLeastTLSv1_3(ssl->version) &&
-                        msgType != client_hello && msgType != server_hello &&
+                if (msgType != client_hello && msgType != server_hello &&
                         msgType != hello_retry_request) {
                     return EXT_NOT_ALLOWED;
@@ -8463,63 +10101,4 @@
                 ret = KS_PARSE(ssl, input + offset, size, msgType);
                 break;
-
-    #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
-            case TLSX_PRE_SHARED_KEY:
-                WOLFSSL_MSG("Pre-Shared Key extension received");
-
-                if (!IsAtLeastTLSv1_3(ssl->version))
-                    break;
-
-                if (IsAtLeastTLSv1_3(ssl->version) &&
-                        msgType != client_hello && msgType != server_hello) {
-                    return EXT_NOT_ALLOWED;
-                }
-                ret = PSK_PARSE(ssl, input + offset, size, msgType);
-                break;
-
-            case TLSX_PSK_KEY_EXCHANGE_MODES:
-                WOLFSSL_MSG("PSK Key Exchange Modes extension received");
-
-                if (!IsAtLeastTLSv1_3(ssl->version))
-                    break;
-
-                if (IsAtLeastTLSv1_3(ssl->version) &&
-                        msgType != client_hello) {
-                    return EXT_NOT_ALLOWED;
-                }
-                ret = PKM_PARSE(ssl, input + offset, size, msgType);
-                break;
-    #endif
-
-    #ifdef WOLFSSL_EARLY_DATA
-            case TLSX_EARLY_DATA:
-                WOLFSSL_MSG("Early Data extension received");
-
-                if (!IsAtLeastTLSv1_3(ssl->version))
-                    break;
-
-                if (IsAtLeastTLSv1_3(ssl->version) &&
-                         msgType != client_hello && msgType != session_ticket &&
-                         msgType != encrypted_extensions) {
-                    return EXT_NOT_ALLOWED;
-                }
-                ret = EDI_PARSE(ssl, input + offset, size, msgType);
-                break;
-    #endif
-
-    #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
-            case TLSX_POST_HANDSHAKE_AUTH:
-                WOLFSSL_MSG("PSK Key Exchange Modes extension received");
-
-                if (!IsAtLeastTLSv1_3(ssl->version))
-                    break;
-
-                if (IsAtLeastTLSv1_3(ssl->version) &&
-                        msgType != client_hello) {
-                    return EXT_NOT_ALLOWED;
-                }
-                ret = PHA_PARSE(ssl, input + offset, size, msgType);
-                break;
-    #endif
 #endif
         }
@@ -8550,16 +10129,9 @@
 
 #ifndef NO_OLD_TLS
-
+    #ifdef WOLFSSL_ALLOW_TLSV10
     WOLFSSL_METHOD* wolfTLSv1_client_method(void)
     {
         return wolfTLSv1_client_method_ex(NULL);
     }
-
-
-    WOLFSSL_METHOD* wolfTLSv1_1_client_method(void)
-    {
-        return wolfTLSv1_1_client_method_ex(NULL);
-    }
-
     WOLFSSL_METHOD* wolfTLSv1_client_method_ex(void* heap)
     {
@@ -8567,10 +10139,16 @@
                              (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
                                                      heap, DYNAMIC_TYPE_METHOD);
+        (void)heap;
+        WOLFSSL_ENTER("TLSv1_client_method_ex");
         if (method)
             InitSSL_Method(method, MakeTLSv1());
         return method;
     }
-
-
+    #endif /* WOLFSSL_ALLOW_TLSV10 */
+
+    WOLFSSL_METHOD* wolfTLSv1_1_client_method(void)
+    {
+        return wolfTLSv1_1_client_method_ex(NULL);
+    }
     WOLFSSL_METHOD* wolfTLSv1_1_client_method_ex(void* heap)
     {
@@ -8578,17 +10156,17 @@
                               (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
                                                      heap, DYNAMIC_TYPE_METHOD);
+        (void)heap;
+        WOLFSSL_ENTER("TLSv1_1_client_method_ex");
         if (method)
             InitSSL_Method(method, MakeTLSv1_1());
         return method;
     }
-
 #endif /* !NO_OLD_TLS */
 
-
+#ifndef WOLFSSL_NO_TLS12
     WOLFSSL_METHOD* wolfTLSv1_2_client_method(void)
     {
         return wolfTLSv1_2_client_method_ex(NULL);
     }
-
     WOLFSSL_METHOD* wolfTLSv1_2_client_method_ex(void* heap)
     {
@@ -8597,8 +10175,10 @@
                                                      heap, DYNAMIC_TYPE_METHOD);
         (void)heap;
+        WOLFSSL_ENTER("TLSv1_2_client_method_ex");
         if (method)
             InitSSL_Method(method, MakeTLSv1_2());
         return method;
     }
+#endif /* WOLFSSL_NO_TLS12 */
 
 #ifdef WOLFSSL_TLS13
@@ -8623,4 +10203,5 @@
                                          DYNAMIC_TYPE_METHOD);
         (void)heap;
+        WOLFSSL_ENTER("TLSv1_3_client_method_ex");
         if (method)
             InitSSL_Method(method, MakeTLSv1_3());
@@ -8629,12 +10210,11 @@
 #endif /* WOLFSSL_TLS13 */
 
-
-    WOLFSSL_METHOD* wolfSSLv23_client_method(void)
+#ifdef WOLFSSL_DTLS
+
+    WOLFSSL_METHOD* wolfDTLS_client_method(void)
     {
-        return wolfSSLv23_client_method_ex(NULL);
-    }
-
-
-    WOLFSSL_METHOD* wolfSSLv23_client_method_ex(void* heap)
+        return wolfDTLS_client_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfDTLS_client_method_ex(void* heap)
     {
         WOLFSSL_METHOD* method =
@@ -8642,25 +10222,201 @@
                                                      heap, DYNAMIC_TYPE_METHOD);
         (void)heap;
+        WOLFSSL_ENTER("DTLS_client_method_ex");
         if (method) {
-#if !defined(NO_SHA256) || defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512)
-#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NGINX)
-            InitSSL_Method(method, MakeTLSv1_3());
+        #if !defined(WOLFSSL_NO_TLS12)
+            InitSSL_Method(method, MakeDTLSv1_2());
+        #elif !defined(NO_OLD_TLS)
+            InitSSL_Method(method, MakeDTLSv1());
 #else
-            InitSSL_Method(method, MakeTLSv1_2());
-#endif
-#else
+            #error No DTLS version enabled!
+    #endif
+
+            method->downgrade = 1;
+            method->side      = WOLFSSL_CLIENT_END;
+        }
+        return method;
+    }
+
     #ifndef NO_OLD_TLS
-            InitSSL_Method(method, MakeTLSv1_1());
-    #endif
-#endif
+    WOLFSSL_METHOD* wolfDTLSv1_client_method(void)
+    {
+        return wolfDTLSv1_client_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfDTLSv1_client_method_ex(void* heap)
+    {
+        WOLFSSL_METHOD* method =
+                          (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+                                                 heap, DYNAMIC_TYPE_METHOD);
+        (void)heap;
+        WOLFSSL_ENTER("DTLSv1_client_method_ex");
+        if (method)
+            InitSSL_Method(method, MakeDTLSv1());
+        return method;
+    }
+    #endif  /* NO_OLD_TLS */
+
+    #ifndef WOLFSSL_NO_TLS12
+    WOLFSSL_METHOD* wolfDTLSv1_2_client_method(void)
+    {
+        return wolfDTLSv1_2_client_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfDTLSv1_2_client_method_ex(void* heap)
+    {
+        WOLFSSL_METHOD* method =
+                          (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+                                                 heap, DYNAMIC_TYPE_METHOD);
+        (void)heap;
+        WOLFSSL_ENTER("DTLSv1_2_client_method_ex");
+        if (method)
+            InitSSL_Method(method, MakeDTLSv1_2());
+        (void)heap;
+        return method;
+    }
+    #endif /* !WOLFSSL_NO_TLS12 */
+#endif /* WOLFSSL_DTLS */
+
+#endif /* NO_WOLFSSL_CLIENT */
+
+
+/* EITHER SIDE METHODS */
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
 #ifndef NO_OLD_TLS
-            method->downgrade = 1;
-#endif
-        }
-        return method;
-    }
-
-#endif /* NO_WOLFSSL_CLIENT */
-
+    #ifdef WOLFSSL_ALLOW_TLSV10
+    /* Gets a WOLFSL_METHOD type that is not set as client or server
+     *
+     * Returns a pointer to a WOLFSSL_METHOD struct
+     */
+    WOLFSSL_METHOD* wolfTLSv1_method(void)
+    {
+        return wolfTLSv1_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfTLSv1_method_ex(void* heap)
+    {
+        WOLFSSL_METHOD* m;
+        WOLFSSL_ENTER("TLSv1_method");
+    #ifndef NO_WOLFSSL_CLIENT
+        m = wolfTLSv1_client_method_ex(heap);
+    #else
+        m = wolfTLSv1_server_method_ex(heap);
+    #endif
+        if (m != NULL) {
+            m->side = WOLFSSL_NEITHER_END;
+        }
+
+        return m;
+    }
+    #endif /* WOLFSSL_ALLOW_TLSV10 */
+
+    /* Gets a WOLFSL_METHOD type that is not set as client or server
+     *
+     * Returns a pointer to a WOLFSSL_METHOD struct
+     */
+    WOLFSSL_METHOD* wolfTLSv1_1_method(void)
+    {
+        return wolfTLSv1_1_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfTLSv1_1_method_ex(void* heap)
+    {
+        WOLFSSL_METHOD* m;
+        WOLFSSL_ENTER("TLSv1_1_method");
+    #ifndef NO_WOLFSSL_CLIENT
+        m = wolfTLSv1_1_client_method_ex(heap);
+    #else
+        m = wolfTLSv1_1_server_method_ex(heap);
+    #endif
+        if (m != NULL) {
+            m->side = WOLFSSL_NEITHER_END;
+        }
+        return m;
+    }
+    #endif /* !NO_OLD_TLS */
+
+    #ifndef WOLFSSL_NO_TLS12
+    /* Gets a WOLFSL_METHOD type that is not set as client or server
+     *
+     * Returns a pointer to a WOLFSSL_METHOD struct
+     */
+    WOLFSSL_METHOD* wolfTLSv1_2_method(void)
+    {
+        return wolfTLSv1_2_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfTLSv1_2_method_ex(void* heap)
+    {
+        WOLFSSL_METHOD* m;
+        WOLFSSL_ENTER("TLSv1_2_method");
+    #ifndef NO_WOLFSSL_CLIENT
+        m = wolfTLSv1_2_client_method_ex(heap);
+    #else
+        m = wolfTLSv1_2_server_method_ex(heap);
+    #endif
+        if (m != NULL) {
+            m->side = WOLFSSL_NEITHER_END;
+    }
+        return m;
+    }
+    #endif /* !WOLFSSL_NO_TLS12 */
+
+#ifdef WOLFSSL_DTLS
+    WOLFSSL_METHOD* wolfDTLS_method(void)
+    {
+        return wolfDTLS_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfDTLS_method_ex(void* heap)
+    {
+        WOLFSSL_METHOD* m;
+        WOLFSSL_ENTER("DTLS_method_ex");
+    #ifndef NO_WOLFSSL_CLIENT
+        m = wolfDTLS_client_method_ex(heap);
+    #else
+        m = wolfDTLS_server_method_ex(heap);
+    #endif
+        if (m != NULL) {
+            m->side = WOLFSSL_NEITHER_END;
+        }
+        return m;
+    }
+
+    #ifndef NO_OLD_TLS
+    WOLFSSL_METHOD* wolfDTLSv1_method(void)
+    {
+        return wolfDTLSv1_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfDTLSv1_method_ex(void* heap)
+    {
+        WOLFSSL_METHOD* m;
+        WOLFSSL_ENTER("DTLSv1_method_ex");
+    #ifndef NO_WOLFSSL_CLIENT
+        m = wolfDTLSv1_client_method_ex(heap);
+    #else
+        m = wolfDTLSv1_server_method_ex(heap);
+    #endif
+        if (m != NULL) {
+            m->side = WOLFSSL_NEITHER_END;
+        }
+        return m;
+    }
+    #endif /* !NO_OLD_TLS */
+    #ifndef WOLFSSL_NO_TLS12
+    WOLFSSL_METHOD* wolfDTLSv1_2_method(void)
+    {
+        return wolfDTLSv1_2_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfDTLSv1_2_method_ex(void* heap)
+    {
+        WOLFSSL_METHOD* m;
+        WOLFSSL_ENTER("DTLSv1_2_method");
+    #ifndef NO_WOLFSSL_CLIENT
+        m = wolfDTLSv1_2_client_method_ex(heap);
+    #else
+        m = wolfDTLSv1_2_server_method_ex(heap);
+    #endif
+        if (m != NULL) {
+            m->side = WOLFSSL_NEITHER_END;
+        }
+        return m;
+    }
+    #endif /* !WOLFSSL_NO_TLS12 */
+#endif /* WOLFSSL_DTLS */
+#endif /* OPENSSL_EXTRA || WOLFSSL_EITHER_SIDE */
 
 
@@ -8668,16 +10424,9 @@
 
 #ifndef NO_OLD_TLS
-
+    #ifdef WOLFSSL_ALLOW_TLSV10
     WOLFSSL_METHOD* wolfTLSv1_server_method(void)
     {
         return wolfTLSv1_server_method_ex(NULL);
     }
-
-
-    WOLFSSL_METHOD* wolfTLSv1_1_server_method(void)
-    {
-        return wolfTLSv1_1_server_method_ex(NULL);
-    }
-
     WOLFSSL_METHOD* wolfTLSv1_server_method_ex(void* heap)
     {
@@ -8685,4 +10434,6 @@
                               (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
                                                      heap, DYNAMIC_TYPE_METHOD);
+        (void)heap;
+        WOLFSSL_ENTER("TLSv1_server_method_ex");
         if (method) {
             InitSSL_Method(method, MakeTLSv1());
@@ -8691,6 +10442,10 @@
         return method;
     }
-
-
+    #endif /* WOLFSSL_ALLOW_TLSV10 */
+
+    WOLFSSL_METHOD* wolfTLSv1_1_server_method(void)
+    {
+        return wolfTLSv1_1_server_method_ex(NULL);
+    }
     WOLFSSL_METHOD* wolfTLSv1_1_server_method_ex(void* heap)
     {
@@ -8698,4 +10453,6 @@
                               (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
                                                      heap, DYNAMIC_TYPE_METHOD);
+        (void)heap;
+        WOLFSSL_ENTER("TLSv1_1_server_method_ex");
         if (method) {
             InitSSL_Method(method, MakeTLSv1_1());
@@ -8707,9 +10464,9 @@
 
 
+#ifndef WOLFSSL_NO_TLS12
     WOLFSSL_METHOD* wolfTLSv1_2_server_method(void)
     {
         return wolfTLSv1_2_server_method_ex(NULL);
     }
-
     WOLFSSL_METHOD* wolfTLSv1_2_server_method_ex(void* heap)
     {
@@ -8718,4 +10475,5 @@
                                                      heap, DYNAMIC_TYPE_METHOD);
         (void)heap;
+        WOLFSSL_ENTER("TLSv1_2_server_method_ex");
         if (method) {
             InitSSL_Method(method, MakeTLSv1_2());
@@ -8724,4 +10482,5 @@
         return method;
     }
+#endif /* !WOLFSSL_NO_TLS12 */
 
 #ifdef WOLFSSL_TLS13
@@ -8746,4 +10505,5 @@
                                                      heap, DYNAMIC_TYPE_METHOD);
         (void)heap;
+        WOLFSSL_ENTER("TLSv1_3_server_method_ex");
         if (method) {
             InitSSL_Method(method, MakeTLSv1_3());
@@ -8754,10 +10514,10 @@
 #endif /* WOLFSSL_TLS13 */
 
-    WOLFSSL_METHOD* wolfSSLv23_server_method(void)
+#ifdef WOLFSSL_DTLS
+    WOLFSSL_METHOD* wolfDTLS_server_method(void)
     {
-        return wolfSSLv23_server_method_ex(NULL);
-    }
-
-    WOLFSSL_METHOD* wolfSSLv23_server_method_ex(void* heap)
+        return wolfDTLS_server_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfDTLS_server_method_ex(void* heap)
     {
         WOLFSSL_METHOD* method =
@@ -8765,28 +10525,64 @@
                                                      heap, DYNAMIC_TYPE_METHOD);
         (void)heap;
+        WOLFSSL_ENTER("DTLS_server_method_ex");
         if (method) {
-#if !defined(NO_SHA256) || defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512)
-#ifdef WOLFSSL_TLS13
-            InitSSL_Method(method, MakeTLSv1_3());
-#else
-            InitSSL_Method(method, MakeTLSv1_2());
-#endif
-#else
+        #if !defined(WOLFSSL_NO_TLS12)
+            InitSSL_Method(method, MakeDTLSv1_2());
+        #elif !defined(NO_OLD_TLS)
+            InitSSL_Method(method, MakeDTLSv1());
+    #else
+            #error No DTLS version enabled!
+    #endif
+
+            method->downgrade = 1;
+            method->side      = WOLFSSL_SERVER_END;
+        }
+        return method;
+    }
+
     #ifndef NO_OLD_TLS
-            InitSSL_Method(method, MakeTLSv1_1());
-    #else
-            #error Must have SHA256, SHA384 or SHA512 enabled for TLS 1.2
-    #endif
-#endif
-#ifndef NO_OLD_TLS
-            method->downgrade = 1;
-#endif
-            method->side      = WOLFSSL_SERVER_END;
+    WOLFSSL_METHOD* wolfDTLSv1_server_method(void)
+    {
+        return wolfDTLSv1_server_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfDTLSv1_server_method_ex(void* heap)
+    {
+        WOLFSSL_METHOD* method =
+                          (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+                                                 heap, DYNAMIC_TYPE_METHOD);
+        (void)heap;
+        WOLFSSL_ENTER("DTLSv1_server_method_ex");
+        if (method) {
+            InitSSL_Method(method, MakeDTLSv1());
+            method->side = WOLFSSL_SERVER_END;
         }
         return method;
     }
-
+    #endif /* !NO_OLD_TLS */
+
+    #ifndef WOLFSSL_NO_TLS12
+    WOLFSSL_METHOD* wolfDTLSv1_2_server_method(void)
+    {
+        return wolfDTLSv1_2_server_method_ex(NULL);
+    }
+    WOLFSSL_METHOD* wolfDTLSv1_2_server_method_ex(void* heap)
+    {
+        WOLFSSL_METHOD* method =
+                          (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+                                                 heap, DYNAMIC_TYPE_METHOD);
+        WOLFSSL_ENTER("DTLSv1_2_server_method_ex");
+        (void)heap;
+        if (method) {
+            InitSSL_Method(method, MakeDTLSv1_2());
+            method->side = WOLFSSL_SERVER_END;
+        }
+        (void)heap;
+        return method;
+    }
+    #endif /* !WOLFSSL_NO_TLS12 */
+#endif /* WOLFSSL_DTLS */
 
 #endif /* NO_WOLFSSL_SERVER */
+
 #endif /* NO_TLS */
 #endif /* WOLFCRYPT_ONLY */
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/tls13.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/tls13.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/tls13.c	(revision 372)
@@ -22,18 +22,55 @@
 
 /*
- * WOLFSSL_TLS13_DRAFT_18
- *    Conform with Draft 18 of the TLS v1.3 specification.
+ * BUILD_GCM
+ *    Enables AES-GCM ciphersuites.
+ * HAVE_AESCCM
+ *    Enables AES-CCM ciphersuites.
+ * HAVE_SESSION_TICKET
+ *    Enables session tickets - required for TLS 1.3 resumption.
+ * NO_PSK
+ *    Do not enable Pre-Shared Keys.
+ * TLS13_SUPPORTS_EXPORTERS
+ *    Gaurd to compile out any code for exporter keys.
+ *    Feature not supported yet.
+ * WOLFSSL_ASYNC_CRYPT
+ *    Enables the use of asynchornous cryptographic operations.
+ *    This is available for ciphers and certificates.
+ * HAVE_CHACHA && HAVE_POLY1305
+ *    Enables use of CHACHA20-POLY1305 ciphersuites.
+ * WOLFSSL_DEBUG_TLS
+ *    Writes out details of TLS 1.3 protocol including hanshake message buffers
+ *    and key generation input and output.
  * WOLFSSL_EARLY_DATA
  *    Allow 0-RTT Handshake using Early Data extensions and handshake message
+ * WOLFSSL_EARLY_DATA_GROUP
+ *    Group EarlyData message with ClientHello when sending
+ * WOLFSSL_NO_SERVER_GROUPS_EXT
+ *    Do not send the server's groups in an extension when the server's top
+ *    preference is not in client's list.
  * WOLFSSL_POST_HANDSHAKE_AUTH
  *    Allow TLS v1.3 code to perform post-handshake authentication of the
  *    client.
+ * WOLFSSL_SEND_HRR_COOKIE
+ *    Send a cookie in hello_retry_request message to enable stateless tracking
+ *    of ClientHello replies.
+ * WOLFSSL_TLS13
+ *    Enable TLS 1.3 protocol implementation.
+ * WOLFSSL_TLS13_DRAFT_18
+ *    Conform with Draft 18 of the TLS v1.3 specification.
+ * WOLFSSL_TLS13_DRAFT_22
+ *    Conform with Draft 22 of the TLS v1.3 specification.
+ * WOLFSSL_TLS13_DRAFT_23
+ *    Conform with Draft 23 of the TLS v1.3 specification.
+ * WOLFSSL_TLS13_MIDDLEBOX_COMPAT
+ *    Enable middlebox compatability in the TLS 1.3 handshake.
+ *    This includes sending ChangeCipherSpec before encrypted messages and
+ *    including a session id.
+ * WOLFSSL_TLS13_SHA512
+ *    Allow generation of SHA-512 digests in handshake - no ciphersuite
+ *    requires SHA-512 at this time.
  * WOLFSSL_TLS13_TICKET_BEFORE_FINISHED
  *    Allow a NewSessionTicket message to be sent by server before Client's
  *    Finished message.
- *    See TLS v.13 specification, Section 4.6.1, Paragraph 4 (Note).
- * TLS13_SUPPORTS_EXPORTERS
- *    Gaurd to compile out any code for exporter keys.
- *    Feature not supported yet.
+ *    See TLS v1.3 specification, Section 4.6.1, Paragraph 4 (Note).
  */
 
@@ -46,5 +83,5 @@
 #ifdef WOLFSSL_TLS13
 #ifdef HAVE_SESSION_TICKET
-    #include <sys/time.h>
+    #include <wolfssl/wolfcrypt/wc_port.h>
 #endif
 
@@ -94,4 +131,9 @@
 #endif
 
+#ifndef HAVE_HKDF
+    #error The build option HAVE_HKDF is required for TLS 1.3
+#endif
+
+
 /* Set ret to error value and jump to label.
  *
@@ -135,5 +177,5 @@
         #endif
 
-        #ifdef WOLFSSL_TLS13_TLS13_SHA512
+        #ifdef WOLFSSL_TLS13_SHA512
         case sha512_mac:
             hash = WC_SHA512;
@@ -170,4 +212,5 @@
  *
  * okm          The generated pseudorandom key - output key material.
+ * okmLen       The length of generated pseudorandom key - output key material.
  * prk          The salt - pseudo-random key.
  * prkLen       The length of the salt - pseudo-random key.
@@ -191,8 +234,8 @@
 
     /* Output length. */
-    data[idx++] = okmLen >> 8;
-    data[idx++] = okmLen;
+    data[idx++] = (byte)(okmLen >> 8);
+    data[idx++] = (byte)okmLen;
     /* Length of protocol | label. */
-    data[idx++] = protocolLen + labelLen;
+    data[idx++] = (byte)(protocolLen + labelLen);
     /* Protocol */
     XMEMCPY(&data[idx], protocol, protocolLen);
@@ -202,5 +245,5 @@
     idx += labelLen;
     /* Length of hash of messages */
-    data[idx++] = infoLen;
+    data[idx++] = (byte)infoLen;
     /* Hash of messages */
     XMEMCPY(&data[idx], info, infoLen);
@@ -257,10 +300,10 @@
                         byte* msg, int msgLen, int hashAlgo)
 {
-    byte        hash[MAX_DIGEST_SIZE];
+    byte        hash[WC_MAX_DIGEST_SIZE];
     Digest      digest;
     word32      hashSz = 0;
     const byte* protocol;
     word32      protocolLen;
-    int         digestAlg;
+    int         digestAlg = -1;
     int         ret = BAD_FUNC_ARG;
 
@@ -305,5 +348,11 @@
             break;
 #endif
-    }
+        default:
+            digestAlg = -1;
+            break;
+    }
+
+    if (digestAlg < 0)
+        return HASH_TYPE_E;
 
     if (ret != 0)
@@ -345,5 +394,5 @@
 {
     int         ret = 0;
-    byte        hash[MAX_DIGEST_SIZE];
+    byte        hash[WC_MAX_DIGEST_SIZE];
     word32      hashSz = 0;
     word32      hashOutSz = 0;
@@ -808,4 +857,60 @@
 #endif
 }
+
+#ifndef WOLFSSL_TLS13_DRAFT_18
+#if defined(HAVE_SESSION_TICKET)
+/* Length of the resumption label. */
+#define RESUMPTION_LABEL_SZ         10
+/* Resumption label for generating PSK assocated with the ticket. */
+static const byte resumptionLabel[RESUMPTION_LABEL_SZ+1] = "resumption";
+/* Derive the PSK assocated with the ticket.
+ *
+ * ssl       The SSL/TLS object.
+ * nonce     The nonce to derive with.
+ * nonceLen  The length of the nonce to derive with.
+ * secret    The derived secret.
+ * returns 0 on success, otherwise failure.
+ */
+static int DeriveResumptionPSK(WOLFSSL* ssl, byte* nonce, byte nonceLen,
+                               byte* secret)
+{
+    int         digestAlg;
+    /* Only one protocol version defined at this time. */
+    const byte* protocol    = tls13ProtocolLabel;
+    word32      protocolLen = TLS13_PROTOCOL_LABEL_SZ;
+
+    WOLFSSL_MSG("Derive Resumption PSK");
+
+    switch (ssl->specs.mac_algorithm) {
+        #ifndef NO_SHA256
+        case sha256_mac:
+            digestAlg = WC_SHA256;
+            break;
+        #endif
+
+        #ifdef WOLFSSL_SHA384
+        case sha384_mac:
+            digestAlg = WC_SHA384;
+            break;
+        #endif
+
+        #ifdef WOLFSSL_TLS13_SHA512
+        case sha512_mac:
+            digestAlg = WC_SHA512;
+            break;
+        #endif
+
+        default:
+            return BAD_FUNC_ARG;
+    }
+
+    return HKDF_Expand_Label(secret, ssl->specs.hash_size,
+                             ssl->session.masterSecret, ssl->specs.hash_size,
+                             protocol, protocolLen, resumptionLabel,
+                             RESUMPTION_LABEL_SZ, nonce, nonceLen, digestAlg);
+}
+#endif /* HAVE_SESSION_TICKET */
+#endif /* WOLFSSL_TLS13_DRAFT_18 */
+
 
 /* Calculate the HMAC of message data to this point.
@@ -897,5 +1002,5 @@
 static int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store)
 {
-    int   ret;
+    int   ret = BAD_FUNC_ARG; /* Assume failure */
     int   i = 0;
 #ifdef WOLFSSL_SMALL_STACK
@@ -925,5 +1030,5 @@
 #ifdef WOLFSSL_EARLY_DATA
         case early_data_key:
-            ret = DeriveEarlyTrafficSecret(ssl, ssl->arrays->clientSecret);
+            ret = DeriveEarlyTrafficSecret(ssl, ssl->clientSecret);
             if (ret != 0)
                 goto end;
@@ -934,5 +1039,5 @@
             if (provision & PROVISION_CLIENT) {
                 ret = DeriveClientHandshakeSecret(ssl,
-                                                  ssl->arrays->clientSecret);
+                                                  ssl->clientSecret);
                 if (ret != 0)
                     goto end;
@@ -940,5 +1045,5 @@
             if (provision & PROVISION_SERVER) {
                 ret = DeriveServerHandshakeSecret(ssl,
-                                                  ssl->arrays->serverSecret);
+                                                  ssl->serverSecret);
                 if (ret != 0)
                     goto end;
@@ -948,10 +1053,10 @@
         case traffic_key:
             if (provision & PROVISION_CLIENT) {
-                ret = DeriveClientTrafficSecret(ssl, ssl->arrays->clientSecret);
+                ret = DeriveClientTrafficSecret(ssl, ssl->clientSecret);
                 if (ret != 0)
                     goto end;
             }
             if (provision & PROVISION_SERVER) {
-                ret = DeriveServerTrafficSecret(ssl, ssl->arrays->serverSecret);
+                ret = DeriveServerTrafficSecret(ssl, ssl->serverSecret);
                 if (ret != 0)
                     goto end;
@@ -961,10 +1066,10 @@
         case update_traffic_key:
             if (provision & PROVISION_CLIENT) {
-                ret = DeriveTrafficSecret(ssl, ssl->arrays->clientSecret);
+                ret = DeriveTrafficSecret(ssl, ssl->clientSecret);
                 if (ret != 0)
                     goto end;
             }
             if (provision & PROVISION_SERVER) {
-                ret = DeriveTrafficSecret(ssl, ssl->arrays->serverSecret);
+                ret = DeriveTrafficSecret(ssl, ssl->serverSecret);
                 if (ret != 0)
                     goto end;
@@ -982,5 +1087,5 @@
         WOLFSSL_MSG("Derive Client Key");
         ret = DeriveKey(ssl, &key_dig[i], ssl->specs.key_size,
-                        ssl->arrays->clientSecret, writeKeyLabel,
+                        ssl->clientSecret, writeKeyLabel,
                         WRITE_KEY_LABEL_SZ, ssl->specs.mac_algorithm, 0);
         if (ret != 0)
@@ -993,5 +1098,5 @@
         WOLFSSL_MSG("Derive Server Key");
         ret = DeriveKey(ssl, &key_dig[i], ssl->specs.key_size,
-                        ssl->arrays->serverSecret, writeKeyLabel,
+                        ssl->serverSecret, writeKeyLabel,
                         WRITE_KEY_LABEL_SZ, ssl->specs.mac_algorithm, 0);
         if (ret != 0)
@@ -1004,5 +1109,5 @@
         WOLFSSL_MSG("Derive Client IV");
         ret = DeriveKey(ssl, &key_dig[i], ssl->specs.iv_size,
-                        ssl->arrays->clientSecret, writeIVLabel,
+                        ssl->clientSecret, writeIVLabel,
                         WRITE_IV_LABEL_SZ, ssl->specs.mac_algorithm, 0);
         if (ret != 0)
@@ -1015,5 +1120,5 @@
         WOLFSSL_MSG("Derive Server IV");
         ret = DeriveKey(ssl, &key_dig[i], ssl->specs.iv_size,
-                        ssl->arrays->serverSecret, writeIVLabel,
+                        ssl->serverSecret, writeIVLabel,
                         WRITE_IV_LABEL_SZ, ssl->specs.mac_algorithm, 0);
         if (ret != 0)
@@ -1311,5 +1416,10 @@
     rl->type    = type;
     rl->pvMajor = ssl->version.major;
+#ifdef WOLFSSL_TLS13_DRAFT_18
     rl->pvMinor = TLSv1_MINOR;
+#else
+    /* NOTE: May be TLSv1_MINOR when sending first ClientHello. */
+    rl->pvMinor = TLSv1_2_MINOR;
+#endif
     c16toa((word16)length, rl->length);
 }
@@ -1388,5 +1498,5 @@
  * out          The buffer to write into.
  */
-static INLINE void WriteSEQ(WOLFSSL* ssl, int verifyOrder, byte* out)
+static WC_INLINE void WriteSEQ(WOLFSSL* ssl, int verifyOrder, byte* out)
 {
     word32 seq[2] = {0, 0};
@@ -1418,5 +1528,5 @@
  * order  The side on which the message is to be or was sent.
  */
-static INLINE void BuildTls13Nonce(WOLFSSL* ssl, byte* nonce, const byte* iv,
+static WC_INLINE void BuildTls13Nonce(WOLFSSL* ssl, byte* nonce, const byte* iv,
                                    int order)
 {
@@ -1431,5 +1541,5 @@
 }
 
-#ifdef HAVE_CHACHA
+#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
 /* Encrypt with ChaCha20 and create authenication tag with Poly1305.
  *
@@ -1440,4 +1550,6 @@
  * sz      The number of bytes to encrypt.
  * nonce   The nonce to use with ChaCha20.
+ * aad     The additional authentication data.
+ * aadSz   The size of the addition authentication data.
  * tag     The authentication tag buffer.
  * returns 0 on success, otherwise failure.
@@ -1445,5 +1557,5 @@
 static int ChaCha20Poly1305_Encrypt(WOLFSSL* ssl, byte* output,
                                     const byte* input, word16 sz, byte* nonce,
-                                    byte* tag)
+                                    const byte* aad, word16 aadSz, byte* tag)
 {
     int    ret    = 0;
@@ -1474,6 +1586,6 @@
         return ret;
     /* Add authentication code of encrypted data to end. */
-    ret = wc_Poly1305_MAC(ssl->auth.poly1305, NULL, 0, output, sz, tag,
-                          POLY1305_AUTH_SZ);
+    ret = wc_Poly1305_MAC(ssl->auth.poly1305, (byte*)aad, aadSz, output, sz,
+                          tag, POLY1305_AUTH_SZ);
 
     return ret;
@@ -1486,11 +1598,13 @@
  * output  The buffer to write encrypted data and authentication tag into.
  *         May be the same pointer as input.
- * input   The data to encrypt.
+ * input   The record header and data to encrypt.
  * sz      The number of bytes to encrypt.
+ * aad     The additional authentication data.
+ * aadSz   The size of the addition authentication data.
  * asyncOkay If non-zero can return WC_PENDING_E, otherwise blocks on crypto
  * returns 0 on success, otherwise failure.
  */
 static int EncryptTls13(WOLFSSL* ssl, byte* output, const byte* input,
-                        word16 sz, int asyncOkay)
+                        word16 sz, const byte* aad, word16 aadSz, int asyncOkay)
 {
     int    ret    = 0;
@@ -1525,4 +1639,9 @@
             WOLFSSL_MSG("Data to encrypt");
             WOLFSSL_BUFFER(input, dataSz);
+#if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22) && \
+                                        !defined(WOLFSSL_TLS13_DRAFT_23)
+            WOLFSSL_MSG("Additional Authentication Data");
+            WOLFSSL_BUFFER(aad, aadSz);
+#endif
         #endif
 
@@ -1547,5 +1666,5 @@
                 case wolfssl_aes_gcm:
                 #ifdef WOLFSSL_ASYNC_CRYPT
-                    /* intialize event */
+                    /* initialize event */
                     asyncDev = &ssl->encrypt.aes->asyncDev;
                     ret = wolfSSL_AsyncInit(ssl, asyncDev, event_flags);
@@ -1557,5 +1676,5 @@
                     ret = wc_AesGcmEncrypt(ssl->encrypt.aes, output, input,
                         dataSz, ssl->encrypt.nonce, nonceSz,
-                        output + dataSz, macSz, NULL, 0);
+                        output + dataSz, macSz, aad, aadSz);
                     break;
             #endif
@@ -1564,5 +1683,5 @@
                 case wolfssl_aes_ccm:
                 #ifdef WOLFSSL_ASYNC_CRYPT
-                    /* intialize event */
+                    /* initialize event */
                     asyncDev = &ssl->encrypt.aes->asyncDev;
                     ret = wolfSSL_AsyncInit(ssl, asyncDev, event_flags);
@@ -1574,5 +1693,5 @@
                     ret = wc_AesCcmEncrypt(ssl->encrypt.aes, output, input,
                         dataSz, ssl->encrypt.nonce, nonceSz,
-                        output + dataSz, macSz, NULL, 0);
+                        output + dataSz, macSz, aad, aadSz);
                     break;
             #endif
@@ -1581,5 +1700,5 @@
                 case wolfssl_chacha:
                     ret = ChaCha20Poly1305_Encrypt(ssl, output, input, dataSz,
-                        ssl->encrypt.nonce, output + dataSz);
+                        ssl->encrypt.nonce, aad, aadSz, output + dataSz);
                     break;
             #endif
@@ -1631,5 +1750,5 @@
 }
 
-#ifdef HAVE_CHACHA
+#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
 /* Decrypt with ChaCha20 and check authenication tag with Poly1305.
  *
@@ -1640,4 +1759,6 @@
  * sz      The number of bytes to decrypt.
  * nonce   The nonce to use with ChaCha20.
+ * aad     The additional authentication data.
+ * aadSz   The size of the addition authentication data.
  * tagIn   The authentication tag data from packet.
  * returns 0 on success, otherwise failure.
@@ -1645,4 +1766,5 @@
 static int ChaCha20Poly1305_Decrypt(WOLFSSL* ssl, byte* output,
                                     const byte* input, word16 sz, byte* nonce,
+                                    const byte* aad, word16 aadSz,
                                     const byte* tagIn)
 {
@@ -1669,6 +1791,6 @@
         return ret;
     /* Generate authentication tag for encrypted data. */
-    if ((ret = wc_Poly1305_MAC(ssl->auth.poly1305, NULL, 0, (byte*)input, sz,
-                               tag, sizeof(tag))) != 0) {
+    if ((ret = wc_Poly1305_MAC(ssl->auth.poly1305, (byte*)aad, aadSz,
+                                    (byte*)input, sz, tag, sizeof(tag))) != 0) {
         return ret;
     }
@@ -1692,9 +1814,12 @@
  * output  The buffer to write decrypted data into.
  *         May be the same pointer as input.
- * input   The data to encrypt and authentication tag.
+ * input   The data to decrypt and authentication tag.
  * sz      The length of the encrypted data plus authentication tag.
+ * aad     The additional authentication data.
+ * aadSz   The size of the addition authentication data.
  * returns 0 on success, otherwise failure.
  */
-int DecryptTls13(WOLFSSL* ssl, byte* output, const byte* input, word16 sz)
+int DecryptTls13(WOLFSSL* ssl, byte* output, const byte* input, word16 sz,
+                 const byte* aad, word16 aadSz)
 {
     int    ret    = 0;
@@ -1737,4 +1862,9 @@
             WOLFSSL_MSG("Data to decrypt");
             WOLFSSL_BUFFER(input, dataSz);
+#if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22) && \
+                                        !defined(WOLFSSL_TLS13_DRAFT_23)
+            WOLFSSL_MSG("Additional Authentication Data");
+            WOLFSSL_BUFFER(aad, aadSz);
+#endif
             WOLFSSL_MSG("Authentication tag");
             WOLFSSL_BUFFER(input + dataSz, macSz);
@@ -1761,5 +1891,5 @@
                 case wolfssl_aes_gcm:
                 #ifdef WOLFSSL_ASYNC_CRYPT
-                    /* intialize event */
+                    /* initialize event */
                     ret = wolfSSL_AsyncInit(ssl, &ssl->decrypt.aes->asyncDev,
                         WC_ASYNC_FLAG_CALL_AGAIN);
@@ -1771,5 +1901,5 @@
                     ret = wc_AesGcmDecrypt(ssl->decrypt.aes, output, input,
                         dataSz, ssl->decrypt.nonce, nonceSz,
-                        input + dataSz, macSz, NULL, 0);
+                        input + dataSz, macSz, aad, aadSz);
                 #ifdef WOLFSSL_ASYNC_CRYPT
                     if (ret == WC_PENDING_E) {
@@ -1784,5 +1914,5 @@
                 case wolfssl_aes_ccm:
                 #ifdef WOLFSSL_ASYNC_CRYPT
-                    /* intialize event */
+                    /* initialize event */
                     ret = wolfSSL_AsyncInit(ssl, &ssl->decrypt.aes->asyncDev,
                         WC_ASYNC_FLAG_CALL_AGAIN);
@@ -1794,5 +1924,5 @@
                     ret = wc_AesCcmDecrypt(ssl->decrypt.aes, output, input,
                         dataSz, ssl->decrypt.nonce, nonceSz,
-                        input + dataSz, macSz, NULL, 0);
+                        input + dataSz, macSz, aad, aadSz);
                 #ifdef WOLFSSL_ASYNC_CRYPT
                     if (ret == WC_PENDING_E) {
@@ -1807,5 +1937,5 @@
                 case wolfssl_chacha:
                     ret = ChaCha20Poly1305_Decrypt(ssl, output, input, dataSz,
-                        ssl->decrypt.nonce, input + dataSz);
+                        ssl->decrypt.nonce, aad, aadSz, input + dataSz);
                     break;
             #endif
@@ -1932,10 +2062,13 @@
         case BUILD_MSG_BEGIN:
         {
-            if (output == NULL || input == NULL)
-                return BAD_FUNC_ARG;
             /* catch mistaken sizeOnly parameter */
-            if (sizeOnly && (output || input)) {
-                WOLFSSL_MSG("BuildTls13Message with sizeOnly doesn't need "
-                            "input or output");
+            if (sizeOnly) {
+                if (output || input) {
+                    WOLFSSL_MSG("BuildTls13Message with sizeOnly "
+                                "doesn't need input or output");
+                    return BAD_FUNC_ARG;
+                }
+            }
+            else if (output == NULL || input == NULL) {
                 return BAD_FUNC_ARG;
             }
@@ -1986,5 +2119,5 @@
         {
             /* The real record content type goes at the end of the data. */
-            output[args->idx++] = type;
+            output[args->idx++] = (byte)type;
 
         #ifdef ATOMIC_USER
@@ -2000,6 +2133,15 @@
         #endif
             {
+#if defined(WOLFSSL_TLS13_DRAFT_18) || defined(WOLFSSL_TLS13_DRAFT_22) || \
+                                       defined(WOLFSSL_TLS13_DRAFT_23)
                 output += args->headerSz;
-                ret = EncryptTls13(ssl, output, output, args->size, asyncOkay);
+                ret = EncryptTls13(ssl, output, output, args->size, NULL, 0,
+                                                                     asyncOkay);
+#else
+                const byte* aad = output;
+                output += args->headerSz;
+                ret = EncryptTls13(ssl, output, output, args->size, aad,
+                                   RECORD_HEADER_SZ, asyncOkay);
+#endif
             }
             break;
@@ -2030,279 +2172,28 @@
 }
 
-#ifndef NO_WOLFSSL_CLIENT
 #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
-/* Setup pre-shared key based on the details in the extension data.
- *
- * ssl  SSL/TLS object.
- * psk  Pre-shared key extension data.
- * returns 0 on success, PSK_KEY_ERROR when the client PSK callback fails and
- * other negative value on failure.
- */
-static int SetupPskKey(WOLFSSL* ssl, PreSharedKey* psk)
-{
-    int ret;
-
-    ssl->options.cipherSuite0 = psk->cipherSuite0;
-    ssl->options.cipherSuite  = psk->cipherSuite;
-    if ((ret = SetCipherSpecs(ssl)) != 0)
-        return ret;
-
-#ifdef HAVE_SESSION_TICKET
-    if (psk->resumption) {
-    #ifdef WOLFSSL_EARLY_DATA
-        if (ssl->session.maxEarlyDataSz == 0)
-            ssl->earlyData = 0;
-    #endif
-        /* Resumption PSK is master secret. */
-        ssl->arrays->psk_keySz = ssl->specs.hash_size;
-        XMEMCPY(ssl->arrays->psk_key, ssl->session.masterSecret,
-                ssl->arrays->psk_keySz);
-    }
-#endif
-#ifndef NO_PSK
-    if (!psk->resumption) {
-        /* Get the pre-shared key. */
-        ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl,
-                (char *)psk->identity, ssl->arrays->client_identity,
-                MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN);
-        if (ssl->arrays->psk_keySz == 0 ||
-                                 ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) {
-            return PSK_KEY_ERROR;
+/* Find the cipher suite in the suites set in the SSL.
+ *
+ * ssl    SSL/TLS object.
+ * suite  Cipher suite to look for.
+ * returns 1 when suite is found in SSL/TLS object's list and 0 otherwise.
+ */
+static int FindSuite(WOLFSSL* ssl, byte* suite)
+{
+    int i;
+
+    for (i = 0; i < ssl->suites->suiteSz; i += 2) {
+        if (ssl->suites->suites[i+0] == suite[0] &&
+            ssl->suites->suites[i+1] == suite[1]) {
+            return 1;
         }
     }
-#endif
-
-    /* Derive the early secret using the PSK. */
-    return DeriveEarlySecret(ssl);
-}
-
-/* Derive and write the binders into the ClientHello in space left when
- * writing the Pre-Shared Key extension.
- *
- * ssl     The SSL/TLS object.
- * output  The buffer containing the ClientHello.
- * idx     The index at the end of the completed ClientHello.
- * returns 0 on success and otherwise failure.
- */
-static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx)
-{
-    int           ret;
-    TLSX*         ext;
-    PreSharedKey* current;
-    byte          binderKey[MAX_DIGEST_SIZE];
-    word16        len;
-
-    ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY);
-    if (ext == NULL)
-        return SANITY_MSG_E;
-
-    /* Get the size of the binders to determine where to write binders. */
-    idx -= TLSX_PreSharedKey_GetSizeBinders((PreSharedKey*)ext->data,
-                                            client_hello);
-
-    /* Hash truncated ClientHello - up to binders. */
-    ret = HashOutput(ssl, output, idx, 0);
-    if (ret != 0)
-        return ret;
-
-    current = (PreSharedKey*)ext->data;
-    /* Calculate the binder for each identity based on previous handshake data.
-     */
-    while (current != NULL) {
-        if ((ret = SetupPskKey(ssl, current)) != 0)
-            return ret;
-
-    #ifdef HAVE_SESSION_TICKET
-        if (current->resumption)
-            ret = DeriveBinderKeyResume(ssl, binderKey);
-    #endif
-    #ifndef NO_PSK
-        if (!current->resumption)
-            ret = DeriveBinderKey(ssl, binderKey);
-    #endif
-        if (ret != 0)
-            return ret;
-
-        /* Derive the Finished message secret. */
-        ret = DeriveFinishedSecret(ssl, binderKey,
-                                             ssl->keys.client_write_MAC_secret);
-        if (ret != 0)
-            return ret;
-
-        /* Build the HMAC of the handshake message data = binder. */
-        ret = BuildTls13HandshakeHmac(ssl, ssl->keys.client_write_MAC_secret,
-            current->binder, &current->binderLen);
-        if (ret != 0)
-            return ret;
-
-        current = current->next;
-    }
-
-    /* Data entered into extension, now write to message. */
-    len = TLSX_PreSharedKey_WriteBinders((PreSharedKey*)ext->data, output + idx,
-                                         client_hello);
-
-    /* Hash binders to complete the hash of the ClientHello. */
-    ret = HashOutputRaw(ssl, output + idx, len);
-    if (ret < 0)
-        return ret;
-
-    #ifdef WOLFSSL_EARLY_DATA
-    if (ssl->earlyData) {
-        if ((ret = SetupPskKey(ssl, (PreSharedKey*)ext->data)) != 0)
-            return ret;
-
-        /* Derive early data encryption key. */
-        ret = DeriveTls13Keys(ssl, early_data_key, ENCRYPT_SIDE_ONLY, 1);
-        if (ret != 0)
-            return ret;
-        if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0)
-            return ret;
-    }
-    #endif
-    return ret;
-}
-#endif
-
-/* Send a ClientHello message to the server.
- * Include the information required to start a handshake with servers using
- * protocol versions less than TLS v1.3.
- * Only a client will send this message.
- *
- * ssl  The SSL/TLS object.
- * returns 0 on success and otherwise failure.
- */
-int SendTls13ClientHello(WOLFSSL* ssl)
-{
-    byte*  output;
-    word32 length;
-    word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
-    int    sendSz;
-    int    ret;
-
-    WOLFSSL_ENTER("SendTls13ClientHello");
-
-#ifdef HAVE_SESSION_TICKET
-    if (ssl->options.resuming &&
-            (ssl->session.version.major != ssl->version.major ||
-             ssl->session.version.minor != ssl->version.minor)) {
-        /* Cannot resume with a different protocol version - new handshake. */
-        ssl->options.resuming = 0;
-        ssl->version.major = ssl->session.version.major;
-        ssl->version.minor = ssl->session.version.minor;
-        return SendClientHello(ssl);
-    }
-#endif
-
-    if (ssl->suites == NULL) {
-        WOLFSSL_MSG("Bad suites pointer in SendTls13ClientHello");
-        return SUITES_ERROR;
-    }
-
-    /* Version | Random | Session Id | Cipher Suites | Compression | Ext  */
-    length = VERSION_SZ + RAN_LEN + ENUM_LEN + ssl->suites->suiteSz +
-             SUITE_LEN + COMP_LEN + ENUM_LEN;
-
-    /* Auto populate extensions supported unless user defined. */
-    if ((ret = TLSX_PopulateExtensions(ssl, 0)) != 0)
-        return ret;
-#ifdef WOLFSSL_EARLY_DATA
-    #ifndef NO_PSK
-        if (!ssl->options.resuming && ssl->options.client_psk_cb == NULL)
-    #else
-        if (!ssl->options.resuming)
-    #endif
-            ssl->earlyData = 0;
-    if (ssl->earlyData && (ret = TLSX_EarlyData_Use(ssl, 0)) < 0)
-        return ret;
-#endif
-#ifdef HAVE_QSH
-    if (QSH_Init(ssl) != 0)
-        return MEMORY_E;
-#endif
-    /* Include length of TLS extensions. */
-    length += TLSX_GetRequestSize(ssl, client_hello);
-
-    /* Total message size. */
-    sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
-
-    /* Check buffers are big enough and grow if needed. */
-    if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
-        return ret;
-
-    /* Get position in output buffer to write new message to. */
-    output = ssl->buffers.outputBuffer.buffer +
-             ssl->buffers.outputBuffer.length;
-
-    /* Put the record and handshake headers on. */
-    AddTls13Headers(output, length, client_hello, ssl);
-
-    /* Protocol version. */
-    output[idx++] = SSLv3_MAJOR;
-    output[idx++] = TLSv1_2_MINOR;
-    ssl->chVersion = ssl->version;
-
-    /* Client Random */
-    if (ssl->options.connectState == CONNECT_BEGIN) {
-        ret = wc_RNG_GenerateBlock(ssl->rng, output + idx, RAN_LEN);
-        if (ret != 0)
-            return ret;
-
-        /* Store random for possible second ClientHello. */
-        XMEMCPY(ssl->arrays->clientRandom, output + idx, RAN_LEN);
-    }
-    else
-        XMEMCPY(output + idx, ssl->arrays->clientRandom, RAN_LEN);
-    idx += RAN_LEN;
-
-    /* TLS v1.3 does not use session id - 0 length. */
-    output[idx++] = 0;
-
-    /* Cipher suites */
-    c16toa(ssl->suites->suiteSz, output + idx);
-    idx += OPAQUE16_LEN;
-    XMEMCPY(output + idx, &ssl->suites->suites, ssl->suites->suiteSz);
-    idx += ssl->suites->suiteSz;
-
-    /* Compression not supported in TLS v1.3. */
-    output[idx++] = COMP_LEN;
-    output[idx++] = NO_COMPRESSION;
-
-    /* Write out extensions for a request. */
-    idx += TLSX_WriteRequest(ssl, output + idx, client_hello);
-
-#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
-    /* Resumption has a specific set of extensions and binder is calculated
-     * for each identity.
-     */
-    if (TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY))
-        ret = WritePSKBinders(ssl, output, idx);
-    else
-#endif
-        ret = HashOutput(ssl, output, idx, 0);
-    if (ret != 0)
-        return ret;
-
-    ssl->options.clientState = CLIENT_HELLO_COMPLETE;
-
-#ifdef WOLFSSL_CALLBACKS
-    if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo);
-    if (ssl->toInfoOn) {
-        AddPacketInfo("ClientHello", &ssl->timeoutInfo, output, sendSz,
-                      ssl->heap);
-    }
-#endif
-
-    ssl->buffers.outputBuffer.length += sendSz;
-
-    ret = SendBuffered(ssl);
-
-    WOLFSSL_LEAVE("SendTls13ClientHello", ret);
-
-    return ret;
-}
+
+    return 0;
+}
+#endif
 
 #ifndef WOLFSSL_TLS13_DRAFT_18
-#ifdef WOLFSSL_SEND_HRR_COOKIE
+#if defined(WOLFSSL_SEND_HRR_COOKIE) && !defined(NO_WOLFSSL_SERVER)
 /* Create Cookie extension using the hash of the first ClientHello.
  *
@@ -2315,5 +2206,5 @@
 {
     int  ret;
-    byte mac[MAX_DIGEST_SIZE];
+    byte mac[WC_MAX_DIGEST_SIZE];
     Hmac cookieHmac;
     byte cookieType;
@@ -2383,7 +2274,7 @@
     WOLFSSL_BUFFER(hash, hashSz);
 
-#ifdef WOLFSSL_SEND_HRR_COOKIE
+#if defined(WOLFSSL_SEND_HRR_COOKIE) && !defined(NO_WOLFSSL_SERVER)
     if (ssl->options.sendCookie) {
-        byte   cookie[OPAQUE8_LEN + MAX_DIGEST_SIZE + OPAQUE16_LEN * 2];
+        byte   cookie[OPAQUE8_LEN + WC_MAX_DIGEST_SIZE + OPAQUE16_LEN * 2];
         TLSX*  ext;
         word32 idx = 0;
@@ -2412,6 +2303,388 @@
     return HashOutputRaw(ssl, hash, hashSz);
 }
-#endif
-
+
+/* The value in the random field of a ServerHello to indicate
+ * HelloRetryRequest.
+ */
+static byte helloRetryRequestRandom[] = {
+    0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11,
+    0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91,
+    0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E,
+    0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C
+};
+#endif /* WOLFSSL_TLS13_DRAFT_18 */
+
+#ifndef NO_WOLFSSL_CLIENT
+#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+/* Setup pre-shared key based on the details in the extension data.
+ *
+ * ssl  SSL/TLS object.
+ * psk  Pre-shared key extension data.
+ * returns 0 on success, PSK_KEY_ERROR when the client PSK callback fails and
+ * other negative value on failure.
+ */
+static int SetupPskKey(WOLFSSL* ssl, PreSharedKey* psk)
+{
+    int ret;
+    byte suite[2];
+
+    if (ssl->options.noPskDheKe && ssl->arrays->preMasterSz != 0)
+        return PSK_KEY_ERROR;
+
+    suite[0] = psk->cipherSuite0;
+    suite[1] = psk->cipherSuite;
+    if (!FindSuite(ssl, suite))
+        return PSK_KEY_ERROR;
+
+    ssl->options.cipherSuite0 = psk->cipherSuite0;
+    ssl->options.cipherSuite  = psk->cipherSuite;
+    if ((ret = SetCipherSpecs(ssl)) != 0)
+        return ret;
+
+#ifdef HAVE_SESSION_TICKET
+    if (psk->resumption) {
+    #ifdef WOLFSSL_EARLY_DATA
+        if (ssl->session.maxEarlyDataSz == 0)
+            ssl->earlyData = no_early_data;
+    #endif
+        /* Resumption PSK is master secret. */
+        ssl->arrays->psk_keySz = ssl->specs.hash_size;
+#ifdef WOLFSSL_TLS13_DRAFT_18
+        XMEMCPY(ssl->arrays->psk_key, ssl->session.masterSecret,
+                ssl->arrays->psk_keySz);
+#else
+        if ((ret = DeriveResumptionPSK(ssl, ssl->session.ticketNonce.data,
+                    ssl->session.ticketNonce.len, ssl->arrays->psk_key)) != 0) {
+            return ret;
+        }
+#endif
+    }
+#endif
+#ifndef NO_PSK
+    if (!psk->resumption) {
+        const char* cipherName = NULL;
+        byte cipherSuite0 = TLS13_BYTE, cipherSuite = WOLFSSL_DEF_PSK_CIPHER;
+
+        /* Get the pre-shared key. */
+        if (ssl->options.client_psk_tls13_cb != NULL) {
+            ssl->arrays->psk_keySz = ssl->options.client_psk_tls13_cb(ssl,
+                    (char *)psk->identity, ssl->arrays->client_identity,
+                    MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN,
+                    &cipherName);
+            if (GetCipherSuiteFromName(cipherName, &cipherSuite0,
+                                                           &cipherSuite) != 0) {
+                return PSK_KEY_ERROR;
+            }
+        }
+        else {
+        ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl,
+                (char *)psk->identity, ssl->arrays->client_identity,
+                MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN);
+        }
+        if (ssl->arrays->psk_keySz == 0 ||
+                                 ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) {
+            return PSK_KEY_ERROR;
+        }
+
+        if (psk->cipherSuite0 != cipherSuite0 ||
+                                              psk->cipherSuite != cipherSuite) {
+            return PSK_KEY_ERROR;
+        }
+    }
+#endif
+
+    /* Derive the early secret using the PSK. */
+    return DeriveEarlySecret(ssl);
+}
+
+/* Derive and write the binders into the ClientHello in space left when
+ * writing the Pre-Shared Key extension.
+ *
+ * ssl     The SSL/TLS object.
+ * output  The buffer containing the ClientHello.
+ * idx     The index at the end of the completed ClientHello.
+ * returns 0 on success and otherwise failure.
+ */
+static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx)
+{
+    int           ret;
+    TLSX*         ext;
+    PreSharedKey* current;
+    byte          binderKey[WC_MAX_DIGEST_SIZE];
+    word16        len;
+
+    WOLFSSL_ENTER("WritePSKBinders");
+
+    ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY);
+    if (ext == NULL)
+        return SANITY_MSG_E;
+
+    /* Get the size of the binders to determine where to write binders. */
+    idx -= TLSX_PreSharedKey_GetSizeBinders((PreSharedKey*)ext->data,
+                                            client_hello);
+
+    /* Hash truncated ClientHello - up to binders. */
+    ret = HashOutput(ssl, output, idx, 0);
+    if (ret != 0)
+        return ret;
+
+    current = (PreSharedKey*)ext->data;
+    /* Calculate the binder for each identity based on previous handshake data.
+     */
+    while (current != NULL) {
+        if ((ret = SetupPskKey(ssl, current)) != 0)
+            return ret;
+
+    #ifdef HAVE_SESSION_TICKET
+        if (current->resumption)
+            ret = DeriveBinderKeyResume(ssl, binderKey);
+    #endif
+    #ifndef NO_PSK
+        if (!current->resumption)
+            ret = DeriveBinderKey(ssl, binderKey);
+    #endif
+        if (ret != 0)
+            return ret;
+
+        /* Derive the Finished message secret. */
+        ret = DeriveFinishedSecret(ssl, binderKey,
+                                             ssl->keys.client_write_MAC_secret);
+        if (ret != 0)
+            return ret;
+
+        /* Build the HMAC of the handshake message data = binder. */
+        ret = BuildTls13HandshakeHmac(ssl, ssl->keys.client_write_MAC_secret,
+            current->binder, &current->binderLen);
+        if (ret != 0)
+            return ret;
+
+        current = current->next;
+    }
+
+    /* Data entered into extension, now write to message. */
+    len = TLSX_PreSharedKey_WriteBinders((PreSharedKey*)ext->data, output + idx,
+                                         client_hello);
+
+    /* Hash binders to complete the hash of the ClientHello. */
+    ret = HashOutputRaw(ssl, output + idx, len);
+    if (ret < 0)
+        return ret;
+
+    #ifdef WOLFSSL_EARLY_DATA
+    if (ssl->earlyData != no_early_data) {
+        if ((ret = SetupPskKey(ssl, (PreSharedKey*)ext->data)) != 0)
+            return ret;
+
+        /* Derive early data encryption key. */
+        ret = DeriveTls13Keys(ssl, early_data_key, ENCRYPT_SIDE_ONLY, 1);
+        if (ret != 0)
+            return ret;
+        if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0)
+            return ret;
+    }
+    #endif
+
+    WOLFSSL_LEAVE("WritePSKBinders", ret);
+
+    return ret;
+}
+#endif
+
+/* handle generation of TLS 1.3 client_hello (1) */
+/* Send a ClientHello message to the server.
+ * Include the information required to start a handshake with servers using
+ * protocol versions less than TLS v1.3.
+ * Only a client will send this message.
+ *
+ * ssl  The SSL/TLS object.
+ * returns 0 on success and otherwise failure.
+ */
+int SendTls13ClientHello(WOLFSSL* ssl)
+{
+    byte*  output;
+    word16 length;
+    word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+    int    sendSz;
+    int    ret;
+
+    WOLFSSL_START(WC_FUNC_CLIENT_HELLO_SEND);
+    WOLFSSL_ENTER("SendTls13ClientHello");
+
+#ifdef HAVE_SESSION_TICKET
+    if (ssl->options.resuming &&
+            (ssl->session.version.major != ssl->version.major ||
+             ssl->session.version.minor != ssl->version.minor)) {
+    #ifndef WOLFSSL_NO_TLS12
+        if (ssl->session.version.major == ssl->version.major &&
+            ssl->session.version.minor < ssl->version.minor) {
+            /* Cannot resume with a different protocol version. */
+        ssl->options.resuming = 0;
+        ssl->version.major = ssl->session.version.major;
+        ssl->version.minor = ssl->session.version.minor;
+        return SendClientHello(ssl);
+    }
+        else
+    #endif
+            return VERSION_ERROR;
+    }
+#endif
+
+    if (ssl->suites == NULL) {
+        WOLFSSL_MSG("Bad suites pointer in SendTls13ClientHello");
+        return SUITES_ERROR;
+    }
+
+    /* Version | Random | Session Id | Cipher Suites | Compression */
+    length = VERSION_SZ + RAN_LEN + ENUM_LEN + ssl->suites->suiteSz +
+             SUITE_LEN + COMP_LEN + ENUM_LEN;
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    #if defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
+    length += ID_LEN;
+    #else
+    if (ssl->session.sessionIDSz > 0)
+        length += ssl->session.sessionIDSz;
+    #endif
+#endif
+
+    /* Auto populate extensions supported unless user defined. */
+    if ((ret = TLSX_PopulateExtensions(ssl, 0)) != 0)
+        return ret;
+#ifdef WOLFSSL_EARLY_DATA
+    #ifndef NO_PSK
+        if (!ssl->options.resuming &&
+                                     ssl->options.client_psk_tls13_cb == NULL &&
+                                     ssl->options.client_psk_cb == NULL)
+    #else
+        if (!ssl->options.resuming)
+    #endif
+            ssl->earlyData = no_early_data;
+    if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST_COMPLETE)
+        ssl->earlyData = no_early_data;
+    if (ssl->earlyData == no_early_data)
+        TLSX_Remove(&ssl->extensions, TLSX_EARLY_DATA, ssl->heap);
+    if (ssl->earlyData != no_early_data &&
+                                       (ret = TLSX_EarlyData_Use(ssl, 0)) < 0) {
+        return ret;
+    }
+#endif
+#ifdef HAVE_QSH
+    if (QSH_Init(ssl) != 0)
+        return MEMORY_E;
+#endif
+    /* Include length of TLS extensions. */
+    ret = TLSX_GetRequestSize(ssl, client_hello, &length);
+    if (ret != 0)
+        return ret;
+
+    /* Total message size. */
+    sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+
+    /* Check buffers are big enough and grow if needed. */
+    if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
+        return ret;
+
+    /* Get position in output buffer to write new message to. */
+    output = ssl->buffers.outputBuffer.buffer +
+             ssl->buffers.outputBuffer.length;
+
+    /* Put the record and handshake headers on. */
+    AddTls13Headers(output, length, client_hello, ssl);
+
+    /* Protocol version - negotiation now in extension: supported_versions. */
+    output[idx++] = SSLv3_MAJOR;
+    output[idx++] = TLSv1_2_MINOR;
+    /* Keep for downgrade. */
+    ssl->chVersion = ssl->version;
+
+    /* Client Random */
+    if (ssl->options.connectState == CONNECT_BEGIN) {
+        ret = wc_RNG_GenerateBlock(ssl->rng, output + idx, RAN_LEN);
+        if (ret != 0)
+            return ret;
+
+        /* Store random for possible second ClientHello. */
+        XMEMCPY(ssl->arrays->clientRandom, output + idx, RAN_LEN);
+    }
+    else
+        XMEMCPY(output + idx, ssl->arrays->clientRandom, RAN_LEN);
+    idx += RAN_LEN;
+
+#ifdef WOLFSSL_TLS13_DRAFT_18
+    /* TLS v1.3 does not use session id - 0 length. */
+    output[idx++] = 0;
+#else
+    if (ssl->session.sessionIDSz > 0) {
+        /* Session resumption for old versions of protocol. */
+        output[idx++] = ID_LEN;
+        XMEMCPY(output + idx, ssl->session.sessionID, ssl->session.sessionIDSz);
+        idx += ID_LEN;
+    }
+    else {
+    #ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT
+        output[idx++] = ID_LEN;
+        XMEMCPY(output + idx, ssl->arrays->clientRandom, ID_LEN);
+        idx += ID_LEN;
+    #else
+    /* TLS v1.3 does not use session id - 0 length. */
+    output[idx++] = 0;
+    #endif /* WOLFSSL_TLS13_MIDDLEBOX_COMPAT */
+    }
+#endif /* WOLFSSL_TLS13_DRAFT_18 */
+
+    /* Cipher suites */
+    c16toa(ssl->suites->suiteSz, output + idx);
+    idx += OPAQUE16_LEN;
+    XMEMCPY(output + idx, &ssl->suites->suites, ssl->suites->suiteSz);
+    idx += ssl->suites->suiteSz;
+
+    /* Compression not supported in TLS v1.3. */
+    output[idx++] = COMP_LEN;
+    output[idx++] = NO_COMPRESSION;
+
+    /* Write out extensions for a request. */
+    length = 0;
+    ret = TLSX_WriteRequest(ssl, output + idx, client_hello, &length);
+    if (ret != 0)
+        return ret;
+    idx += length;
+
+#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+    /* Resumption has a specific set of extensions and binder is calculated
+     * for each identity.
+     */
+    if (TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY))
+        ret = WritePSKBinders(ssl, output, idx);
+    else
+#endif
+        ret = HashOutput(ssl, output, idx, 0);
+    if (ret != 0)
+        return ret;
+
+    ssl->options.clientState = CLIENT_HELLO_COMPLETE;
+
+#ifdef WOLFSSL_CALLBACKS
+    if (ssl->hsInfoOn) AddPacketName(ssl, "ClientHello");
+    if (ssl->toInfoOn) {
+        AddPacketInfo(ssl, "ClientHello", handshake, output, sendSz,
+                      WRITE_PROTO, ssl->heap);
+    }
+#endif
+
+    ssl->buffers.outputBuffer.length += sendSz;
+
+#ifdef WOLFSSL_EARLY_DATA_GROUP
+    if (ssl->earlyData == no_early_data)
+#endif
+    ret = SendBuffered(ssl);
+
+
+    WOLFSSL_LEAVE("SendTls13ClientHello", ret);
+    WOLFSSL_END(WC_FUNC_CLIENT_HELLO_SEND);
+
+    return ret;
+}
+
+#ifdef WOLFSSL_TLS13_DRAFT_18
+/* handle rocessing of TLS 1.3 hello_retry_request (6) */
 /* Parse and handle a HelloRetryRequest message.
  * Only a client will receive this message.
@@ -2437,5 +2710,5 @@
 
 #ifdef WOLFSSL_CALLBACKS
-    if (ssl->hsInfoOn) AddPacketName("HelloRetryRequest", &ssl->handShakeInfo);
+    if (ssl->hsInfoOn) AddPacketName(ssl, "HelloRetryRequest");
     if (ssl->toInfoOn) AddLateName("HelloRetryRequest", &ssl->timeoutInfo);
 #endif
@@ -2451,14 +2724,4 @@
     if (ret != 0)
         return ret;
-
-#ifndef WOLFSSL_TLS13_DRAFT_18
-    /* Set the cipher suite from the message. */
-    ssl->options.cipherSuite0 = input[i++];
-    ssl->options.cipherSuite  = input[i++];
-
-    ret = SetCipherSpecs(ssl);
-    if (ret != 0)
-        return ret;
-#endif
 
     /* Length of extension data. */
@@ -2482,9 +2745,5 @@
 
     ssl->options.tls1_3 = 1;
-    ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST;
-
-#ifndef WOLFSSL_TLS13_DRAFT_18
-    ret = RestartHandshakeHash(ssl);
-#endif
+    ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE;
 
     WOLFSSL_LEAVE("DoTls13HelloRetryRequest", ret);
@@ -2492,5 +2751,8 @@
     return ret;
 }
-
+#endif
+
+
+/* handle processing of TLS 1.3 server_hello (2) and hello_retry_request (6) */
 /* Handle the ServerHello message from the server.
  * Only a client will receive this message.
@@ -2504,5 +2766,5 @@
  */
 int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
-                       word32 helloSz)
+                       word32 helloSz, byte* extMsgType)
 {
     ProtocolVersion pv;
@@ -2510,4 +2772,9 @@
     word32          begin = i;
     int             ret;
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    byte            sessIdSz;
+    const byte*     sessId;
+    byte            b;
+#endif
     word16          totalExtSz;
 #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
@@ -2516,8 +2783,9 @@
 #endif
 
+    WOLFSSL_START(WC_FUNC_SERVER_HELLO_DO);
     WOLFSSL_ENTER("DoTls13ServerHello");
 
 #ifdef WOLFSSL_CALLBACKS
-    if (ssl->hsInfoOn) AddPacketName("ServerHello", &ssl->handShakeInfo);
+    if (ssl->hsInfoOn) AddPacketName(ssl, "ServerHello");
     if (ssl->toInfoOn) AddLateName("ServerHello", &ssl->timeoutInfo);
 #endif
@@ -2530,20 +2798,45 @@
     XMEMCPY(&pv, input + i, OPAQUE16_LEN);
     i += OPAQUE16_LEN;
+#ifdef WOLFSSL_TLS13_DRAFT_18
     ret = CheckVersion(ssl, pv);
     if (ret != 0)
         return ret;
     if (!IsAtLeastTLSv1_3(pv) && pv.major != TLS_DRAFT_MAJOR) {
+#ifndef WOLFSSL_NO_TLS12
         if (ssl->options.downgrade) {
             ssl->version = pv;
             return DoServerHello(ssl, input, inOutIdx, helloSz);
         }
-
-        WOLFSSL_MSG("CLient using higher version, fatal error");
+#endif
+
+        WOLFSSL_MSG("Client using higher version, fatal error");
         return VERSION_ERROR;
     }
-
-    /* Random, cipher suite and extensions length check. */
-    if ((i - begin) + RAN_LEN + OPAQUE16_LEN + OPAQUE16_LEN > helloSz)
+#else
+#ifndef WOLFSSL_NO_TLS12
+    if (pv.major == ssl->version.major  && pv.minor < TLSv1_2_MINOR &&
+                                                       ssl->options.downgrade) {
+        /* Force client hello version 1.2 to work for static RSA. */
+        ssl->chVersion.minor = TLSv1_2_MINOR;
+        ssl->version.minor = TLSv1_2_MINOR;
+        return DoServerHello(ssl, input, inOutIdx, helloSz);
+    }
+#endif
+    if (pv.major != ssl->version.major || pv.minor != TLSv1_2_MINOR)
+        return VERSION_ERROR;
+#endif
+
+#ifdef WOLFSSL_TLS13_DRAFT_18
+    /* Random length check */
+    if ((i - begin) + RAN_LEN > helloSz)
         return BUFFER_ERROR;
+#else
+    /* Random and session id length check */
+    if ((i - begin) + RAN_LEN + ENUM_LEN > helloSz)
+        return BUFFER_ERROR;
+
+    if (XMEMCMP(input + i, helloRetryRequestRandom, RAN_LEN) == 0)
+        *extMsgType = hello_retry_request;
+#endif
 
     /* Server random - keep for debugging. */
@@ -2551,9 +2844,52 @@
     i += RAN_LEN;
 
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    /* Session id */
+    sessIdSz = input[i++];
+    if ((i - begin) + sessIdSz > helloSz)
+        return BUFFER_ERROR;
+    sessId = input + i;
+    i += sessIdSz;
+#endif /* WOLFSSL_TLS13_DRAFT_18 */
+    ssl->options.haveSessionId = 1;
+
+#ifdef WOLFSSL_TLS13_DRAFT_18
+    /* Ciphersuite check */
+    if ((i - begin) + OPAQUE16_LEN + OPAQUE16_LEN > helloSz)
+        return BUFFER_ERROR;
+#else
+    /* Ciphersuite and compression check */
+    if ((i - begin) + OPAQUE16_LEN + OPAQUE8_LEN > helloSz)
+        return BUFFER_ERROR;
+#endif
+
     /* Set the cipher suite from the message. */
     ssl->options.cipherSuite0 = input[i++];
     ssl->options.cipherSuite  = input[i++];
 
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    /* Compression */
+    b = input[i++];
+    if (b != 0) {
+        WOLFSSL_MSG("Must be no compression types in list");
+        return INVALID_PARAMETER;
+    }
+#endif
+
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    if ((i - begin) + OPAQUE16_LEN > helloSz) {
+        if (!ssl->options.downgrade)
+            return BUFFER_ERROR;
+#ifndef WOLFSSL_NO_TLS12
+        ssl->version.minor = TLSv1_2_MINOR;
+#endif
+        ssl->options.haveEMS = 0;
+    }
+    if ((i - begin) < helloSz)
+#endif
+    {
     /* Get extension length and length check. */
+        if ((i - begin) + OPAQUE16_LEN > helloSz)
+            return BUFFER_ERROR;
     ato16(&input[i], &totalExtSz);
     i += OPAQUE16_LEN;
@@ -2561,10 +2897,16 @@
         return BUFFER_ERROR;
 
+#ifndef WOLFSSL_TLS13_DRAFT_18
+        if (ssl->options.downgrade)
+            ssl->version.minor = TLSv1_2_MINOR;
+#endif
     /* Parse and handle extensions. */
-    ret = TLSX_Parse(ssl, (byte *) input + i, totalExtSz, server_hello, NULL);
+        ret = TLSX_Parse(ssl, (byte *) input + i, totalExtSz, *extMsgType,
+                                                                          NULL);
     if (ret != 0)
         return ret;
 
     i += totalExtSz;
+    }
     *inOutIdx = i;
 
@@ -2581,4 +2923,56 @@
 #endif /* HAVE_SECRET_CALLBACK */
 
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    /* Version only negotiated in extensions for TLS v1.3.
+     * Only now do we know how to deal with session id.
+     */
+    if (!IsAtLeastTLSv1_3(ssl->version)) {
+#ifndef WOLFSSL_NO_TLS12
+        ssl->arrays->sessionIDSz = sessIdSz;
+
+        if (ssl->arrays->sessionIDSz > ID_LEN) {
+            WOLFSSL_MSG("Invalid session ID size");
+            ssl->arrays->sessionIDSz = 0;
+            return BUFFER_ERROR;
+        }
+        else if (ssl->arrays->sessionIDSz) {
+            XMEMCPY(ssl->arrays->sessionID, sessId, ssl->arrays->sessionIDSz);
+            ssl->options.haveSessionId = 1;
+        }
+
+        /* Force client hello version 1.2 to work for static RSA. */
+        ssl->chVersion.minor = TLSv1_2_MINOR;
+        /* Complete TLS v1.2 processing of ServerHello. */
+        ret = CompleteServerHello(ssl);
+#else
+        WOLFSSL_MSG("Client using higher version, fatal error");
+        ret = VERSION_ERROR;
+#endif
+
+        WOLFSSL_LEAVE("DoTls13ServerHello", ret);
+
+        return ret;
+    }
+
+    #ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT
+    if (sessIdSz == 0)
+        return INVALID_PARAMETER;
+    if (ssl->session.sessionIDSz != 0) {
+        if (ssl->session.sessionIDSz != sessIdSz ||
+                   XMEMCMP(ssl->session.sessionID, sessId, sessIdSz) != 0) {
+            return INVALID_PARAMETER;
+        }
+    }
+    else if (XMEMCMP(ssl->arrays->clientRandom, sessId, sessIdSz) != 0)
+        return INVALID_PARAMETER;
+    #else
+    if (sessIdSz != ssl->session.sessionIDSz || (sessIdSz > 0 &&
+                  XMEMCMP(ssl->session.sessionID, sessId, sessIdSz) != 0)) {
+        WOLFSSL_MSG("Server sent different session id");
+        return INVALID_PARAMETER;
+    }
+    #endif /* WOLFSSL_TLS13_MIDDLEBOX_COMPAT */
+#endif
+
     ret = SetCipherSpecs(ssl);
     if (ret != 0)
@@ -2586,4 +2980,8 @@
 
 #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    if (*extMsgType == server_hello)
+#endif
+    {
     ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY);
     if (ext != NULL)
@@ -2598,13 +2996,29 @@
     else if ((ret = SetupPskKey(ssl, psk)) != 0)
         return ret;
-#endif
-
+    }
+#endif
+
+#ifdef WOLFSSL_TLS13_DRAFT_18
     ssl->keys.encryptionOn = 1;
+#else
+    if (*extMsgType == server_hello) {
+    ssl->keys.encryptionOn = 1;
+        ssl->options.serverState = SERVER_HELLO_COMPLETE;
+    }
+    else {
+        ssl->options.tls1_3 = 1;
+        ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE;
+
+        ret = RestartHandshakeHash(ssl);
+    }
+#endif
 
     WOLFSSL_LEAVE("DoTls13ServerHello", ret);
+    WOLFSSL_END(WC_FUNC_SERVER_HELLO_DO);
 
     return ret;
 }
 
+/* handle processing TLS 1.3 encrypted_extensions (8) */
 /* Parse and handle an EncryptedExtensions message.
  * Only a client will receive this message.
@@ -2627,9 +3041,9 @@
     word16 totalExtSz;
 
+    WOLFSSL_START(WC_FUNC_ENCRYPTED_EXTENSIONS_DO);
     WOLFSSL_ENTER("DoTls13EncryptedExtensions");
 
 #ifdef WOLFSSL_CALLBACKS
-    if (ssl->hsInfoOn) AddPacketName("EncryptedExtensions",
-                                     &ssl->handShakeInfo);
+    if (ssl->hsInfoOn) AddPacketName(ssl, "EncryptedExtensions");
     if (ssl->toInfoOn) AddLateName("EncryptedExtensions", &ssl->timeoutInfo);
 #endif
@@ -2655,16 +3069,28 @@
 
 #ifdef WOLFSSL_EARLY_DATA
-    if (ssl->earlyData) {
+    if (ssl->earlyData != no_early_data) {
         TLSX* ext = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA);
         if (ext == NULL || !ext->val)
-            ssl->earlyData = 0;
-    }
-#endif
+            ssl->earlyData = no_early_data;
+    }
+#endif
+
+#ifdef WOLFSSL_EARLY_DATA
+    if (ssl->earlyData == no_early_data) {
+        ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY);
+        if (ret != 0)
+            return ret;
+    }
+#endif
+
+    ssl->options.serverState = SERVER_ENCRYPTED_EXTENSIONS_COMPLETE;
 
     WOLFSSL_LEAVE("DoTls13EncryptedExtensions", ret);
+    WOLFSSL_END(WC_FUNC_ENCRYPTED_EXTENSIONS_DO);
 
     return ret;
 }
 
+/* handle processing TLS v1.3 certificate_request (13) */
 /* Handle a TLS v1.3 CertificateRequest message.
  * This message is always encrypted.
@@ -2691,8 +3117,9 @@
 #endif
 
+    WOLFSSL_START(WC_FUNC_CERTIFICATE_REQUEST_DO);
     WOLFSSL_ENTER("DoTls13CertificateRequest");
 
 #ifdef WOLFSSL_CALLBACKS
-    if (ssl->hsInfoOn) AddPacketName("CertificateRequest", &ssl->handShakeInfo);
+    if (ssl->hsInfoOn) AddPacketName(ssl, "CertificateRequest");
     if (ssl->toInfoOn) AddLateName("CertificateRequest", &ssl->timeoutInfo);
 #endif
@@ -2799,15 +3226,6 @@
     *inOutIdx += ssl->keys.padSz;
 
-#if !defined(NO_WOLFSSL_CLIENT) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
-    if (ssl->options.side == WOLFSSL_CLIENT_END &&
-                                ssl->options.handShakeState == HANDSHAKE_DONE) {
-        /* reset handshake states */
-        ssl->options.clientState = CLIENT_HELLO_COMPLETE;
-        ssl->options.connectState  = FIRST_REPLY_DONE;
-        ssl->options.handShakeState = CLIENT_HELLO_COMPLETE;
-    }
-#endif
-
     WOLFSSL_LEAVE("DoTls13CertificateRequest", ret);
+    WOLFSSL_END(WC_FUNC_CERTIFICATE_REQUEST_DO);
 
     return ret;
@@ -2818,4 +3236,29 @@
 #ifndef NO_WOLFSSL_SERVER
 #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+/* Refine list of supported cipher suites to those common to server and client.
+ *
+ * ssl         SSL/TLS object.
+ * peerSuites  The peer's advertised list of supported cipher suites.
+ */
+static void RefineSuites(WOLFSSL* ssl, Suites* peerSuites)
+{
+    byte suites[WOLFSSL_MAX_SUITE_SZ];
+    int suiteSz = 0;
+    int i, j;
+
+    for (i = 0; i < ssl->suites->suiteSz; i += 2) {
+        for (j = 0; j < peerSuites->suiteSz; j += 2) {
+            if (ssl->suites->suites[i+0] == peerSuites->suites[j+0] &&
+                ssl->suites->suites[i+1] == peerSuites->suites[j+1]) {
+                suites[suiteSz++] = peerSuites->suites[j+0];
+                suites[suiteSz++] = peerSuites->suites[j+1];
+            }
+        }
+    }
+
+    ssl->suites->suiteSz = suiteSz;
+    XMEMCPY(ssl->suites->suites, &suites, sizeof(suites));
+}
+
 /* Handle any Pre-Shared Key (PSK) extension.
  * Must do this in ClientHello as it requires a hash of the truncated message.
@@ -2835,17 +3278,25 @@
     word16        bindersLen;
     PreSharedKey* current;
-    byte          binderKey[MAX_DIGEST_SIZE];
-    byte          binder[MAX_DIGEST_SIZE];
+    byte          binderKey[WC_MAX_DIGEST_SIZE];
+    byte          binder[WC_MAX_DIGEST_SIZE];
     word32        binderLen;
     word16        modes;
+    byte          suite[2];
 #ifdef WOLFSSL_EARLY_DATA
     int           pskCnt = 0;
     TLSX*         extEarlyData;
 #endif
+#ifndef NO_PSK
+    const char*   cipherName = NULL;
+    byte          cipherSuite0 = TLS13_BYTE;
+    byte          cipherSuite  = WOLFSSL_DEF_PSK_CIPHER;
+#endif
+
+    WOLFSSL_ENTER("DoPreSharedKeys");
 
     ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY);
     if (ext == NULL) {
 #ifdef WOLFSSL_EARLY_DATA
-        ssl->earlyData = 0;
+        ssl->earlyData = no_early_data;
 #endif
         return 0;
@@ -2905,4 +3356,14 @@
             }
 
+            /* Check whether resumption is possible based on suites in SSL and
+             * ciphersuite in ticket.
+             */
+            suite[0] = ssl->session.cipherSuite0;
+            suite[1] = ssl->session.cipherSuite;
+            if (!FindSuite(ssl, suite)) {
+                current = current->next;
+                continue;
+            }
+
         #ifdef WOLFSSL_EARLY_DATA
             ssl->options.maxEarlyDataSz = ssl->session.maxEarlyDataSz;
@@ -2917,6 +3378,13 @@
             /* Resumption PSK is resumption master secret. */
             ssl->arrays->psk_keySz = ssl->specs.hash_size;
+        #ifdef WOLFSSL_TLS13_DRAFT_18
             XMEMCPY(ssl->arrays->psk_key, ssl->session.masterSecret,
-                    ssl->specs.hash_size);
+                    ssl->arrays->psk_keySz);
+        #else
+            if ((ret = DeriveResumptionPSK(ssl, ssl->session.ticketNonce.data,
+                    ssl->session.ticketNonce.len, ssl->arrays->psk_key)) != 0) {
+                return ret;
+            }
+        #endif
 
             /* Derive the early secret using the PSK. */
@@ -2932,11 +3400,26 @@
     #endif
     #ifndef NO_PSK
-        if (ssl->options.server_psk_cb != NULL &&
+        if ((ssl->options.server_psk_tls13_cb != NULL &&
+             (ssl->arrays->psk_keySz = ssl->options.server_psk_tls13_cb(ssl,
+                             ssl->arrays->client_identity, ssl->arrays->psk_key,
+                             MAX_PSK_KEY_LEN, &cipherName)) != 0 && 
+             GetCipherSuiteFromName(cipherName, &cipherSuite0,
+                                                          &cipherSuite) == 0) ||
+            (ssl->options.server_psk_cb != NULL &&
             (ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl,
                              ssl->arrays->client_identity, ssl->arrays->psk_key,
-                             MAX_PSK_KEY_LEN)) != 0) {
+                             MAX_PSK_KEY_LEN)) != 0)) {
             if (ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN)
                 return PSK_KEY_ERROR;
 
+            /* Check whether PSK ciphersuite is in SSL. */
+            suite[0] = cipherSuite0;
+            suite[1] = cipherSuite;
+            if (!FindSuite(ssl, suite)) {
+                current = current->next;
+                continue;
+            }
+
+            /* Default to ciphersuite if cb doesn't specify. */
             ssl->options.resuming = 0;
 
@@ -2945,8 +3428,7 @@
                 return PSK_KEY_ERROR;
 
-            /* TODO: Callback should be able to change ciphersuite. */
-            /* Default to ciphersuite if cb doesn't specify. */
-            ssl->options.cipherSuite0 = TLS13_BYTE;
-            ssl->options.cipherSuite  = WOLFSSL_DEF_PSK_CIPHER;
+            /* Set PSK ciphersuite into SSL. */
+            ssl->options.cipherSuite0 = cipherSuite0;
+            ssl->options.cipherSuite  = cipherSuite;
             ret = SetCipherSpecs(ssl);
             if (ret != 0)
@@ -2993,4 +3475,16 @@
     }
 
+    if (current == NULL) {
+#ifdef WOLFSSL_PSK_ID_PROTECTION
+    #ifndef NO_CERTS
+        if (ssl->buffers.certChainCnt != 0)
+            return 0;
+    #endif
+        return BAD_BINDER;
+#else
+        return 0;
+#endif
+    }
+
     /* Hash the rest of the ClientHello. */
     ret = HashInputRaw(ssl, input + helloSz - bindersLen, bindersLen);
@@ -3001,5 +3495,5 @@
     extEarlyData = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA);
     if (extEarlyData != NULL) {
-        if (ssl->earlyData && current == ext->data) {
+        if (ssl->earlyData != no_early_data && current == ext->data) {
             extEarlyData->resp = 1;
 
@@ -3011,5 +3505,5 @@
                 return ret;
 
-            ssl->earlyData = 2;
+            ssl->earlyData = process_early_data;
         }
         else
@@ -3031,8 +3525,10 @@
         ssl->namedGroup = ssl->session.namedGroup;
 
-        /* Try to establish a new secret. */
+        /* Pick key share and Generate a new key if not present. */
         ret = TLSX_KeyShare_Establish(ssl);
-        if (ret == KEY_SHARE_ERROR)
-            return PSK_KEY_ERROR;
+        if (ret == KEY_SHARE_ERROR) {
+            ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE;
+            ret = 0;
+        }
         else if (ret < 0)
             return ret;
@@ -3041,8 +3537,13 @@
         ext->resp = 1;
     }
-    else if ((modes & (1 << PSK_KE)) == 0)
+    else {
+        if ((modes & (1 << PSK_KE)) == 0)
         return PSK_KEY_ERROR;
+        ssl->options.noPskDheKe = 1;
+    }
 
     *usingPSK = 1;
+
+    WOLFSSL_LEAVE("DoPreSharedKeys", ret);
 
     return ret;
@@ -3061,5 +3562,5 @@
 {
     int  ret;
-    byte mac[MAX_DIGEST_SIZE];
+    byte mac[WC_MAX_DIGEST_SIZE];
     Hmac cookieHmac;
     byte cookieType;
@@ -3096,6 +3597,9 @@
 /* Length of the KeyShare Extension */
 #define HRR_KEY_SHARE_SZ   (OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN)
+/* Length of the Supported Vresions Extension */
+#define HRR_VERSIONS_SZ    (OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN)
 /* Length of the Cookie Extension excluding cookie data */
 #define HRR_COOKIE_HDR_SZ  (OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN)
+#ifdef WOLFSSL_TLS13_DRAFT_18
 /* PV | CipherSuite | Ext Len */
 #define HRR_BODY_SZ        (OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN)
@@ -3105,4 +3609,16 @@
                           HRR_KEY_SHARE_SZ + \
                           HRR_COOKIE_HDR_SZ)
+#else
+/* PV | Random | Session Id | CipherSuite | Compression | Ext Len */
+#define HRR_BODY_SZ        (VERSION_SZ + RAN_LEN + ENUM_LEN + ID_LEN + \
+                            SUITE_LEN + COMP_LEN + OPAQUE16_LEN)
+/* HH | PV | CipherSuite | Ext Len | Key Share | Supported Version | Cookie */
+#define MAX_HRR_SZ   (HANDSHAKE_HEADER_SZ   + \
+                        HRR_BODY_SZ         + \
+                          HRR_KEY_SHARE_SZ  + \
+                          HRR_VERSIONS_SZ   + \
+                          HRR_COOKIE_HDR_SZ)
+#endif
+
 /* Restart the Hanshake hash from the cookie value.
  *
@@ -3141,20 +3657,20 @@
 
     /* Reconstruct the HelloRetryMessage for handshake hash. */
+#ifdef WOLFSSL_TLS13_DRAFT_18
     length = HRR_BODY_SZ + HRR_COOKIE_HDR_SZ + cookie->len;
+#else
+    length = HRR_BODY_SZ - ID_LEN + ssl->session.sessionIDSz +
+             HRR_COOKIE_HDR_SZ + cookie->len;
+    length += HRR_VERSIONS_SZ;
+#endif
     if (cookieDataSz > hashSz + OPAQUE16_LEN) {
         keyShareExt = 1;
         length += HRR_KEY_SHARE_SZ;
     }
+#ifdef WOLFSSL_TLS13_DRAFT_18
     AddTls13HandShakeHeader(hrr, length, 0, 0, hello_retry_request, ssl);
 
     idx += hashSz;
     hrrIdx = HANDSHAKE_HEADER_SZ;
-    /* TODO: [TLS13] Replace existing code with code in comment.
-     * Use the TLS v1.3 draft version for now.
-     *
-     * Change to:
-     * hrr[hrrIdx++] = ssl->version.major;
-     * hrr[hrrIdx++] = ssl->version.minor;
-     */
     /* The negotiated protocol version. */
     hrr[hrrIdx++] = TLS_DRAFT_MAJOR;
@@ -3168,4 +3684,37 @@
     c16toa(length, hrr + hrrIdx);
     hrrIdx += 2;
+#else
+    AddTls13HandShakeHeader(hrr, length, 0, 0, server_hello, ssl);
+
+    idx += hashSz;
+    hrrIdx = HANDSHAKE_HEADER_SZ;
+
+    /* The negotiated protocol version. */
+    hrr[hrrIdx++] = ssl->version.major;
+    hrr[hrrIdx++] = TLSv1_2_MINOR;
+
+    /* HelloRetryRequest message has fixed value for random. */
+    XMEMCPY(hrr + hrrIdx, helloRetryRequestRandom, RAN_LEN);
+    hrrIdx += RAN_LEN;
+
+    hrr[hrrIdx++] = ssl->session.sessionIDSz;
+    if (ssl->session.sessionIDSz > 0) {
+        XMEMCPY(hrr + hrrIdx, ssl->session.sessionID, ssl->session.sessionIDSz);
+        hrrIdx += ssl->session.sessionIDSz;
+    }
+
+    /* Cipher Suite */
+    hrr[hrrIdx++] = cookieData[idx++];
+    hrr[hrrIdx++] = cookieData[idx++];
+
+    /* Compression not supported in TLS v1.3. */
+    hrr[hrrIdx++] = 0;
+
+    /* Extensions' length */
+    length -= HRR_BODY_SZ - ID_LEN + ssl->session.sessionIDSz;
+    c16toa(length, hrr + hrrIdx);
+    hrrIdx += 2;
+
+#endif
     /* Optional KeyShare Extension */
     if (keyShareExt) {
@@ -3177,4 +3726,17 @@
         hrr[hrrIdx++] = cookieData[idx++];
     }
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    c16toa(TLSX_SUPPORTED_VERSIONS, hrr + hrrIdx);
+    hrrIdx += 2;
+    c16toa(OPAQUE16_LEN, hrr + hrrIdx);
+    hrrIdx += 2;
+    #ifdef WOLFSSL_TLS13_DRAFT
+        hrr[hrrIdx++] = TLS_DRAFT_MAJOR;
+        hrr[hrrIdx++] = TLS_DRAFT_MINOR;
+    #else
+        hrr[hrrIdx++] = ssl->version.major;
+        hrr[hrrIdx++] = ssl->version.minor;
+    #endif
+#endif
     /* Mandatory Cookie Extension */
     c16toa(TLSX_COOKIE, hrr + hrrIdx);
@@ -3214,5 +3776,5 @@
                        word32 helloSz)
 {
-    int             ret;
+    int             ret = VERSION_ERROR;
     byte            b;
     ProtocolVersion pv;
@@ -3220,12 +3782,16 @@
     word32          i = *inOutIdx;
     word32          begin = i;
-    word16          totalExtSz;
+    word16          totalExtSz = 0;
     int             usingPSK = 0;
     byte            sessIdSz;
-
+#ifndef WOLFSSL_NO_TLS12
+    int             bogusID = 0;
+#endif
+
+    WOLFSSL_START(WC_FUNC_CLIENT_HELLO_DO);
     WOLFSSL_ENTER("DoTls13ClientHello");
 
 #ifdef WOLFSSL_CALLBACKS
-    if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo);
+    if (ssl->hsInfoOn) AddPacketName(ssl, "ClientHello");
     if (ssl->toInfoOn) AddLateName("ClientHello", &ssl->timeoutInfo);
 #endif
@@ -3239,7 +3805,19 @@
     ssl->chVersion = pv;   /* store */
     i += OPAQUE16_LEN;
-
+    /* Legacy protocol version cannot negotiate TLS 1.3 or higher. */
+    if (pv.major == SSLv3_MAJOR && pv.minor >= TLSv1_3_MINOR)
+        pv.minor = TLSv1_2_MINOR;
+
+#ifndef WOLFSSL_NO_TLS12
     if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor < TLSv1_3_MINOR)
         return DoClientHello(ssl, input, inOutIdx, helloSz);
+#endif
+
+#ifdef HAVE_SESSION_TICKET
+    if (ssl->options.downgrade) {
+       if ((ret = HashInput(ssl, input + begin, helloSz)) != 0)
+            return ret;
+    }
+#endif
 
     /* Client random */
@@ -3252,10 +3830,27 @@
 #endif
 
+#ifdef WOLFSSL_TLS13_DRAFT_18
     /* Session id - empty in TLS v1.3 */
     sessIdSz = input[i++];
-    if (sessIdSz > 0) {
+    if (sessIdSz > 0 && !ssl->options.downgrade) {
         WOLFSSL_MSG("Client sent session id - not supported");
         return BUFFER_ERROR;
     }
+#else
+    sessIdSz = input[i++];
+    if (sessIdSz != ID_LEN && sessIdSz != 0)
+        return INVALID_PARAMETER;
+#endif
+    ssl->session.sessionIDSz = sessIdSz;
+    if (sessIdSz == ID_LEN) {
+        XMEMCPY(ssl->session.sessionID, input + i, sessIdSz);
+        i += ID_LEN;
+    }
+#ifndef WOLFSSL_NO_TLS12
+    #ifdef HAVE_SESSION_TICKET
+        if (sessIdSz > 0 && sessIdSz < ID_LEN)
+            bogusID = 1;
+    #endif
+#endif
 
     /* Cipher suites */
@@ -3287,9 +3882,5 @@
     }
 
-    /* TLS v1.3 ClientHello messages will have extensions. */
-    if ((i - begin) >= helloSz) {
-        WOLFSSL_MSG("ClientHello must have extensions in TLS v1.3");
-        return BUFFER_ERROR;
-    }
+    if ((i - begin) < helloSz) {
     if ((i - begin) + OPAQUE16_LEN > helloSz)
         return BUFFER_ERROR;
@@ -3313,26 +3904,42 @@
     }
 
-#ifdef HAVE_STUNNEL
+#if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \
+                                                        defined(WOLFSSL_HAPROXY)
     if ((ret = SNI_Callback(ssl)) != 0)
         return ret;
-#endif /*HAVE_STUNNEL*/
+        ssl->options.side = WOLFSSL_SERVER_END;
+#endif /* OPENSSL_ALL || HAVE_STUNNEL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */
+    }
+
+    i += totalExtSz;
+    *inOutIdx = i;
 
     if (TLSX_Find(ssl->extensions, TLSX_SUPPORTED_VERSIONS) == NULL) {
         if (!ssl->options.downgrade) {
-            WOLFSSL_MSG("Client trying to connect with lesser version");
+            WOLFSSL_MSG("Client trying to connect with lesser version than "
+                        "TLS v1.3");
             return VERSION_ERROR;
         }
+
+        if (pv.minor < ssl->options.minDowngrade)
+            return VERSION_ERROR;
         ssl->version.minor = pv.minor;
     }
 
-#ifdef WOLFSSL_SEND_HRR_COOKIE
+    ssl->options.sendVerify = SEND_CERT;
+
+    ssl->options.clientState = CLIENT_HELLO_COMPLETE;
+    ssl->options.haveSessionId = 1;
+
+    if (IsAtLeastTLSv1_3(ssl->version)) {
+#if !defined(WOLFSSL_TLS13_DRAFT_18) && defined(WOLFSSL_SEND_HRR_COOKIE)
     if (ssl->options.sendCookie &&
-                       ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) {
+              ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
         TLSX* ext;
 
         if ((ext = TLSX_Find(ssl->extensions, TLSX_COOKIE)) == NULL)
             return HRR_COOKIE_ERROR;
-        /* Ensure the cookie came from client and isn't the one in the response
-         * - HelloRetryRequest.
+            /* Ensure the cookie came from client and isn't the one in the
+             * response - HelloRetryRequest.
          */
         if (ext->resp == 1)
@@ -3344,11 +3951,37 @@
 #endif
 
-    ssl->options.sendVerify = SEND_CERT;
-
 #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+        if (ssl->options.downgrade) {
+            if ((ret = InitHandshakeHashes(ssl)) != 0)
+                return ret;
+        }
+
+        /* Refine list for PSK processing. */
+        RefineSuites(ssl, &clSuites);
+
     /* Process the Pre-Shared Key extension if present. */
     ret = DoPreSharedKeys(ssl, input + begin, helloSz, &usingPSK);
     if (ret != 0)
         return ret;
+#endif
+    }
+#ifndef WOLFSSL_NO_TLS12
+    else if (ssl->options.resuming) {
+        ret = HandleTlsResumption(ssl, bogusID, &clSuites);
+        if (ret != 0)
+            return ret;
+        /* Check wheter resuming has been chosen */
+        if (ssl->options.clientState == CLIENT_KEYEXCHANGE_COMPLETE) {
+            WOLFSSL_LEAVE("DoTls13ClientHello", ret);
+            WOLFSSL_END(WC_FUNC_CLIENT_HELLO_DO);
+
+            return ret;
+        }
+    }
+#else
+    else {
+        WOLFSSL_MSG("Negotiated lesser version than TLS v1.3");
+        return VERSION_ERROR;
+    }
 #endif
 
@@ -3358,4 +3991,14 @@
             return ret;
         }
+
+        /* Check that the negotiated ciphersuite matches protocol version. */
+        if (IsAtLeastTLSv1_3(ssl->version)) {
+            if (ssl->options.cipherSuite0 != TLS13_BYTE) {
+                WOLFSSL_MSG("Negotiated ciphersuite from lesser version than "
+                            "TLS v1.3");
+                return VERSION_ERROR;
+            }
+        }
+        /* VerifyServerSuite handles when version is less than 1.3 */
 
 #ifdef HAVE_SESSION_TICKET
@@ -3369,22 +4012,27 @@
 #endif
 
+#ifdef HAVE_SESSION_TICKET
+        if (IsAtLeastTLSv1_3(ssl->version) || !ssl->options.downgrade)
+#endif
+        {
         if ((ret = HashInput(ssl, input + begin,  helloSz)) != 0)
             return ret;
-
+        }
+
+        if (IsAtLeastTLSv1_3(ssl->version)) {
         /* Derive early secret for handshake secret. */
         if ((ret = DeriveEarlySecret(ssl)) != 0)
             return ret;
     }
-
-    i += totalExtSz;
-    *inOutIdx = i;
-
-    ssl->options.clientState = CLIENT_HELLO_COMPLETE;
+    }
 
     WOLFSSL_LEAVE("DoTls13ClientHello", ret);
+    WOLFSSL_END(WC_FUNC_CLIENT_HELLO_DO);
 
     return ret;
 }
 
+#ifdef WOLFSSL_TLS13_DRAFT_18
+/* handle generation of TLS 1.3 hello_retry_request (6) */
 /* Send the HelloRetryRequest message to indicate the negotiated protocol
  * version and security parameters the server is willing to use.
@@ -3399,5 +4047,5 @@
     byte*  output;
     word32 length;
-    word32 len;
+    word16 len;
     word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
     int    sendSz;
@@ -3405,22 +4053,13 @@
     WOLFSSL_ENTER("SendTls13HelloRetryRequest");
 
-#ifndef WOLFSSL_TLS13_DRAFT_18
-    if ((ret = RestartHandshakeHash(ssl)) < 0)
-        return ret;
-#endif
-
     /* Get the length of the extensions that will be written. */
-    len = TLSX_GetResponseSize(ssl, hello_retry_request);
+    len = 0;
+    ret = TLSX_GetResponseSize(ssl, hello_retry_request, &len);
     /* There must be extensions sent to indicate what client needs to do. */
-    if (len == 0)
+    if (ret != 0)
         return MISSING_HANDSHAKE_DATA;
 
-#ifndef WOLFSSL_TLS13_DRAFT_18
-    /* Protocol version + CipherSuite + Extensions */
-    length = OPAQUE16_LEN + OPAQUE16_LEN + len;
-#else
     /* Protocol version + Extensions */
     length = OPAQUE16_LEN + len;
-#endif
     sendSz = idx + length;
 
@@ -3435,108 +4074,144 @@
     AddTls13Headers(output, length, hello_retry_request, ssl);
 
-    /* TODO: [TLS13] Replace existing code with code in comment.
-     * Use the TLS v1.3 draft version for now.
-     *
-     * Change to:
-     * output[idx++] = ssl->version.major;
-     * output[idx++] = ssl->version.minor;
-     */
     /* The negotiated protocol version. */
     output[idx++] = TLS_DRAFT_MAJOR;
     output[idx++] = TLS_DRAFT_MINOR;
 
+    /* Add TLS extensions. */
+    ret = TLSX_WriteResponse(ssl, output + idx, hello_retry_request, NULL);
+    if (ret != 0)
+        return ret;
+    idx += len;
+
+#ifdef WOLFSSL_CALLBACKS
+    if (ssl->hsInfoOn)
+        AddPacketName(ssl, "HelloRetryRequest");
+    if (ssl->toInfoOn) {
+        AddPacketInfo(ssl, "HelloRetryRequest", handshake, output, sendSz,
+                      WRITE_PROTO, ssl->heap);
+    }
+#endif
+    if ((ret = HashOutput(ssl, output, idx, 0)) != 0)
+        return ret;
+
+    ssl->buffers.outputBuffer.length += sendSz;
+
+    if (!ssl->options.groupMessages)
+        ret = SendBuffered(ssl);
+
+    WOLFSSL_LEAVE("SendTls13HelloRetryRequest", ret);
+
+    return ret;
+}
+#endif /* WOLFSSL_TLS13_DRAFT_18 */
+
+/* Send TLS v1.3 ServerHello message to client.
+ * Only a server will send this message.
+ *
+ * ssl  The SSL/TLS object.
+ * returns 0 on success, otherwise failure.
+ */
+#ifdef WOLFSSL_TLS13_DRAFT_18
+static
+#endif
+/* handle generation of TLS 1.3 server_hello (2) */
+int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType)
+{
+    int    ret;
+    byte*  output;
+    word16 length;
+    word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+    int    sendSz;
+
+    WOLFSSL_START(WC_FUNC_SERVER_HELLO_SEND);
+    WOLFSSL_ENTER("SendTls13ServerHello");
+
 #ifndef WOLFSSL_TLS13_DRAFT_18
+    if (extMsgType == hello_retry_request) {
+        if ((ret = RestartHandshakeHash(ssl)) < 0)
+            return ret;
+    }
+#endif
+
+#ifdef WOLFSSL_TLS13_DRAFT_18
+    /* Protocol version, server random, cipher suite and extensions. */
+    length = VERSION_SZ + RAN_LEN + SUITE_LEN;
+    ret = TLSX_GetResponseSize(ssl, server_hello, &length);
+    if (ret != 0)
+        return ret;
+#else
+    /* Protocol version, server random, session id, cipher suite, compression
+     * and extensions.
+     */
+    length = VERSION_SZ + RAN_LEN + ENUM_LEN + ssl->session.sessionIDSz +
+             SUITE_LEN + COMP_LEN;
+    ret = TLSX_GetResponseSize(ssl, extMsgType, &length);
+    if (ret != 0)
+        return ret;
+#endif
+    sendSz = idx + length;
+
+    /* Check buffers are big enough and grow if needed. */
+    if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
+        return ret;
+
+    /* Get position in output buffer to write new message to. */
+    output = ssl->buffers.outputBuffer.buffer +
+             ssl->buffers.outputBuffer.length;
+
+    /* Put the record and handshake headers on. */
+    AddTls13Headers(output, length, server_hello, ssl);
+
+#ifdef WOLFSSL_TLS13_DRAFT_18
+    /* The negotiated protocol version. */
+    output[idx++] = TLS_DRAFT_MAJOR;
+    output[idx++] = TLS_DRAFT_MINOR;
+#else
+    /* The protocol version must be TLS v1.2 for middleboxes. */
+    output[idx++] = ssl->version.major;
+    output[idx++] = TLSv1_2_MINOR;
+#endif
+
+    if (extMsgType == server_hello) {
+    /* Generate server random. */
+    if ((ret = wc_RNG_GenerateBlock(ssl->rng, output + idx, RAN_LEN)) != 0)
+        return ret;
+    }
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    else {
+        /* HelloRetryRequest message has fixed value for random. */
+        XMEMCPY(output + idx, helloRetryRequestRandom, RAN_LEN);
+    }
+#endif
+    /* Store in SSL for debugging. */
+    XMEMCPY(ssl->arrays->serverRandom, output + idx, RAN_LEN);
+    idx += RAN_LEN;
+
+#ifdef WOLFSSL_DEBUG_TLS
+    WOLFSSL_MSG("Server random");
+    WOLFSSL_BUFFER(ssl->arrays->serverRandom, RAN_LEN);
+#endif
+
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    output[idx++] = ssl->session.sessionIDSz;
+    if (ssl->session.sessionIDSz > 0) {
+        XMEMCPY(output + idx, ssl->session.sessionID, ssl->session.sessionIDSz);
+        idx += ssl->session.sessionIDSz;
+    }
+#endif
+
     /* Chosen cipher suite */
     output[idx++] = ssl->options.cipherSuite0;
     output[idx++] = ssl->options.cipherSuite;
-#endif
-
-    /* Add TLS extensions. */
-    TLSX_WriteResponse(ssl, output + idx, hello_retry_request);
-    idx += len;
-
-#ifdef WOLFSSL_CALLBACKS
-    if (ssl->hsInfoOn)
-        AddPacketName("HelloRetryRequest", &ssl->handShakeInfo);
-    if (ssl->toInfoOn) {
-        AddPacketInfo("HelloRetryRequest", &ssl->timeoutInfo, output, sendSz,
-                      ssl->heap);
-    }
-#endif
-
-    if ((ret = HashOutput(ssl, output, idx, 0)) != 0)
-        return ret;
-
-    ssl->buffers.outputBuffer.length += sendSz;
-
-    if (!ssl->options.groupMessages)
-        ret = SendBuffered(ssl);
-
-    WOLFSSL_LEAVE("SendTls13HelloRetryRequest", ret);
-
-    return ret;
-}
-
-/* Send TLS v1.3 ServerHello message to client.
- * Only a server will send this message.
- *
- * ssl  The SSL/TLS object.
- * returns 0 on success, otherwise failure.
- */
-static int SendTls13ServerHello(WOLFSSL* ssl)
-{
-    byte*  output;
-    word32 length;
-    word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
-    int    sendSz;
-    int    ret;
-
-    WOLFSSL_ENTER("SendTls13ServerHello");
-
-    /* Protocol version, server random, cipher suite and extensions. */
-    length = VERSION_SZ + RAN_LEN + SUITE_LEN +
-             TLSX_GetResponseSize(ssl, server_hello);
-    sendSz = idx + length;
-
-    /* Check buffers are big enough and grow if needed. */
-    if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
-        return ret;
-
-    /* Get position in output buffer to write new message to. */
-    output = ssl->buffers.outputBuffer.buffer +
-             ssl->buffers.outputBuffer.length;
-
-    /* Put the record and handshake headers on. */
-    AddTls13Headers(output, length, server_hello, ssl);
-
-    /* TODO: [TLS13] Replace existing code with code in comment.
-     * Use the TLS v1.3 draft version for now.
-     *
-     * Change to:
-     * output[idx++] = ssl->version.major;
-     * output[idx++] = ssl->version.minor;
-     */
-    /* The negotiated protocol version. */
-    output[idx++] = TLS_DRAFT_MAJOR;
-    output[idx++] = TLS_DRAFT_MINOR;
-
-    /* Generate server random. */
-    if ((ret = wc_RNG_GenerateBlock(ssl->rng, output + idx, RAN_LEN)) != 0)
-        return ret;
-    /* Store in SSL for debugging. */
-    XMEMCPY(ssl->arrays->serverRandom, output + idx, RAN_LEN);
-    idx += RAN_LEN;
-
-#ifdef WOLFSSL_DEBUG_TLS
-    WOLFSSL_MSG("Server random");
-    WOLFSSL_BUFFER(ssl->arrays->serverRandom, RAN_LEN);
-#endif
-
-    /* Chosen cipher suite */
-    output[idx++] = ssl->options.cipherSuite0;
-    output[idx++] = ssl->options.cipherSuite;
+
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    /* Compression not supported in TLS v1.3. */
+    output[idx++] = 0;
+#endif
 
     /* Extensions */
-    TLSX_WriteResponse(ssl, output + idx, server_hello);
+    ret = TLSX_WriteResponse(ssl, output + idx, extMsgType, NULL);
+    if (ret != 0)
+        return ret;
 
     ssl->buffers.outputBuffer.length += sendSz;
@@ -3547,21 +4222,32 @@
     #ifdef WOLFSSL_CALLBACKS
     if (ssl->hsInfoOn)
-        AddPacketName("ServerHello", &ssl->handShakeInfo);
+        AddPacketName(ssl, "ServerHello");
     if (ssl->toInfoOn) {
-        AddPacketInfo("ServerHello", &ssl->timeoutInfo, output, sendSz,
-                      ssl->heap);
+        AddPacketInfo(ssl, "ServerHello", handshake, output, sendSz,
+                      WRITE_PROTO, ssl->heap);
     }
     #endif
 
+#ifdef WOLFSSL_TLS13_DRAFT_18
     ssl->options.serverState = SERVER_HELLO_COMPLETE;
-
+#else
+    if (extMsgType == server_hello)
+    ssl->options.serverState = SERVER_HELLO_COMPLETE;
+#endif
+
+#ifdef WOLFSSL_TLS13_DRAFT_18
     if (!ssl->options.groupMessages)
+#else
+    if (!ssl->options.groupMessages || extMsgType != server_hello)
+#endif
         ret = SendBuffered(ssl);
 
     WOLFSSL_LEAVE("SendTls13ServerHello", ret);
+    WOLFSSL_END(WC_FUNC_SERVER_HELLO_SEND);
 
     return ret;
 }
 
+/* handle generation of TLS 1.3 encrypted_extensions (8) */
 /* Send the rest of the extensions encrypted under the handshake key.
  * This message is always encrypted in TLS v1.3.
@@ -3575,11 +4261,17 @@
     int    ret;
     byte*  output;
-    word32 length;
+    word16 length = 0;
     word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
     int    sendSz;
 
+    WOLFSSL_START(WC_FUNC_ENCRYPTED_EXTENSIONS_SEND);
     WOLFSSL_ENTER("SendTls13EncryptedExtensions");
 
     ssl->keys.encryptionOn = 1;
+
+#ifndef WOLFSSL_NO_SERVER_GROUPS_EXT
+    if ((ret = TLSX_SupportedCurve_CheckPriority(ssl)) != 0)
+        return ret;
+#endif
 
     /* Derive the handshake secret now that we are at first message to be
@@ -3596,5 +4288,5 @@
     if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0)
         return ret;
-    if (ssl->earlyData != 2) {
+    if (ssl->earlyData != process_early_data) {
         if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0)
             return ret;
@@ -3605,5 +4297,8 @@
 #endif
 
-    length = TLSX_GetResponseSize(ssl, encrypted_extensions);
+    ret = TLSX_GetResponseSize(ssl, encrypted_extensions, &length);
+    if (ret != 0)
+        return ret;
+
     sendSz = idx + length;
     /* Encryption always on. */
@@ -3622,13 +4317,15 @@
     AddTls13Headers(output, length, encrypted_extensions, ssl);
 
-    TLSX_WriteResponse(ssl, output + idx, encrypted_extensions);
+    ret = TLSX_WriteResponse(ssl, output + idx, encrypted_extensions, NULL);
+    if (ret != 0)
+        return ret;
     idx += length;
 
 #ifdef WOLFSSL_CALLBACKS
     if (ssl->hsInfoOn)
-        AddPacketName("EncryptedExtensions", &ssl->handShakeInfo);
+        AddPacketName(ssl, "EncryptedExtensions");
     if (ssl->toInfoOn) {
-        AddPacketInfo("EncryptedExtensions", &ssl->timeoutInfo, output,
-                      sendSz, ssl->heap);
+        AddPacketInfo(ssl, "EncryptedExtensions", handshake, output,
+                      sendSz, WRITE_PROTO, ssl->heap);
     }
 #endif
@@ -3648,4 +4345,5 @@
 
     WOLFSSL_LEAVE("SendTls13EncryptedExtensions", ret);
+    WOLFSSL_END(WC_FUNC_ENCRYPTED_EXTENSIONS_SEND);
 
     return ret;
@@ -3653,4 +4351,5 @@
 
 #ifndef NO_CERTS
+/* handle generation TLS v1.3 certificate_request (13) */
 /* Send the TLS v1.3 CertificateRequest message.
  * This message is always encrypted in TLS v1.3.
@@ -3669,9 +4368,10 @@
     int    sendSz;
     word32 i;
-    int    reqSz;
+    word16 reqSz;
 #ifndef WOLFSSL_TLS13_DRAFT_18
     TLSX*  ext;
 #endif
 
+    WOLFSSL_START(WC_FUNC_CERTIFICATE_REQUEST_SEND);
     WOLFSSL_ENTER("SendTls13CertificateRequest");
 
@@ -3727,6 +4427,8 @@
 
     i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
-    reqSz = OPAQUE8_LEN + reqCtxLen +
-        TLSX_GetRequestSize(ssl, certificate_request);
+    reqSz = (word16)(OPAQUE8_LEN + reqCtxLen);
+    ret = TLSX_GetRequestSize(ssl, certificate_request, &reqSz);
+    if (ret != 0)
+        return ret;
 
     sendSz = i + reqSz;
@@ -3746,5 +4448,5 @@
 
     /* Certificate request context. */
-    output[i++] = reqCtxLen;
+    output[i++] = (byte)reqCtxLen;
     if (reqCtxLen != 0) {
         XMEMCPY(output + i, reqCtx, reqCtxLen);
@@ -3753,5 +4455,9 @@
 
     /* Certificate extensions. */
-    i += TLSX_WriteRequest(ssl, output + i, certificate_request);
+    reqSz = 0;
+    ret = TLSX_WriteRequest(ssl, output + i, certificate_request, &reqSz);
+    if (ret != 0)
+        return ret;
+    i += reqSz;
 #endif
 
@@ -3764,8 +4470,8 @@
     #ifdef WOLFSSL_CALLBACKS
         if (ssl->hsInfoOn)
-            AddPacketName("CertificateRequest", &ssl->handShakeInfo);
+            AddPacketName(ssl, "CertificateRequest");
         if (ssl->toInfoOn) {
-            AddPacketInfo("CertificateRequest", &ssl->timeoutInfo, output,
-                          sendSz, ssl->heap);
+            AddPacketInfo(ssl, "CertificateRequest", handshake, output,
+                          sendSz, WRITE_PROTO, ssl->heap);
         }
     #endif
@@ -3776,4 +4482,5 @@
 
     WOLFSSL_LEAVE("SendTls13CertificateRequest", ret);
+    WOLFSSL_END(WC_FUNC_CERTIFICATE_REQUEST_SEND);
 
     return ret;
@@ -3790,5 +4497,5 @@
  * output    The buffer to encode into.
  */
-static INLINE void EncodeSigAlg(byte hashAlgo, byte hsType, byte* output)
+static WC_INLINE void EncodeSigAlg(byte hashAlgo, byte hsType, byte* output)
 {
     switch (hsType) {
@@ -3824,5 +4531,5 @@
  * hsType   The signature type.
  */
-static INLINE void DecodeSigAlg(byte* input, byte* hashAlgo, byte* hsType)
+static WC_INLINE void DecodeSigAlg(byte* input, byte* hashAlgo, byte* hsType)
 {
     switch (input[0]) {
@@ -3856,5 +4563,5 @@
  * returns the length of the hash.
  */
-static INLINE int GetMsgHash(WOLFSSL* ssl, byte* hash)
+static WC_INLINE int GetMsgHash(WOLFSSL* ssl, byte* hash)
 {
     int ret = 0;
@@ -3901,5 +4608,5 @@
 #define MAX_SIG_DATA_SZ            (SIGNING_DATA_PREFIX_SZ + \
                                     CERT_VFY_LABEL_SZ      + \
-                                    MAX_DIGEST_SIZE)
+                                    WC_MAX_DIGEST_SIZE)
 
 /* Create the signature data for TLS v1.3 certificate verification.
@@ -3935,5 +4642,5 @@
         return ret;
 
-    *sigDataSz = idx + ret;
+    *sigDataSz = (word16)(idx + ret);
     ret = 0;
 
@@ -4075,5 +4782,5 @@
  *
  * ssl       The SSL/TLS object.
- * hashAlgo  The signature algorithm used to generate signature.
+ * sigAlgo   The signature algorithm used to generate signature.
  * hashAlgo  The hash algorithm used to generate signature.
  * decSig    The decrypted signature.
@@ -4100,5 +4807,5 @@
             return ret;
 
-        /* PSS signature can be done in-pace */
+        /* PSS signature can be done in-place */
         ret = CreateRSAEncodedSig(sigData, sigData, sigDataSz,
                                   sigAlgo, hashAlgo);
@@ -4147,6 +4854,8 @@
 /* Add certificate data and empty extension to output up to the fragment size.
  *
+ * ssl     SSL/TLS object.
  * cert    The certificate data to write out.
  * len     The length of the certificate data.
+ * extSz   Length of the extension data with the certificate.
  * idx     The start of the certificate data to write out.
  * fragSz  The maximum size of this fragment.
@@ -4154,6 +4863,6 @@
  * returns the number of bytes written.
  */
-static word32 AddCertExt(byte* cert, word32 len, word32 idx, word32 fragSz,
-                         byte* output)
+static word32 AddCertExt(WOLFSSL* ssl, byte* cert, word32 len, word16 extSz,
+                         word32 idx, word32 fragSz, byte* output)
 {
     word32 i = 0;
@@ -4163,15 +4872,29 @@
         XMEMCPY(output, cert + idx, copySz);
         i = copySz;
-    }
-
-    if (copySz + OPAQUE16_LEN <= fragSz) {
+        if (copySz == fragSz)
+            return i;
+    }
+    copySz = len + extSz - idx - i;
+
+    if (extSz == OPAQUE16_LEN) {
+        if (copySz <= fragSz) {
         /* Empty extension */
         output[i++] = 0;
         output[i++] = 0;
     }
+    }
+    else {
+        byte* certExts = ssl->buffers.certExts->buffer + idx + i - len;
+        /* Put out as much of the extensions' data as will fit in fragment. */
+        if (copySz > fragSz - i)
+            copySz = fragSz - i;
+        XMEMCPY(output + i, certExts, copySz);
+        i += copySz;
+    }
 
     return i;
 }
 
+/* handle generation TLS v1.3 certificate (11) */
 /* Send the certificate for this end and any CAs that help with validation.
  * This message is always encrypted in TLS v1.3.
@@ -4184,4 +4907,5 @@
     int    ret = 0;
     word32 certSz, certChainSz, headerSz, listSz, payloadSz;
+    word16 extSz = 0;
     word32 length, maxFragment;
     word32 len = 0;
@@ -4192,4 +4916,5 @@
     byte*  certReqCtx = NULL;
 
+    WOLFSSL_START(WC_FUNC_CERTIFICATE_SEND);
     WOLFSSL_ENTER("SendTls13Certificate");
 
@@ -4218,12 +4943,28 @@
         headerSz = OPAQUE8_LEN + certReqCtxLen + CERT_HEADER_SZ +
                    CERT_HEADER_SZ;
-        /* Length of message data with one certificate and empty extensions. */
-        length = headerSz + certSz + OPAQUE16_LEN;
-        /* Length of list data with one certificate and empty extensions. */
-        listSz = CERT_HEADER_SZ + certSz + OPAQUE16_LEN;
+
+        ret = TLSX_GetResponseSize(ssl, certificate, &extSz);
+        if (ret < 0)
+            return ret;
+
+        /* Create extensions' data if none already present. */
+        if (extSz > OPAQUE16_LEN && ssl->buffers.certExts == NULL) {
+            ret = AllocDer(&ssl->buffers.certExts, extSz, CERT_TYPE, ssl->heap);
+            if (ret < 0)
+                return ret;
+
+            ret = TLSX_WriteResponse(ssl, ssl->buffers.certExts->buffer,
+                                                           certificate, &extSz);
+            if (ret < 0)
+                return ret;
+        }
+
+        /* Length of message data with one certificate and extensions. */
+        length = headerSz + certSz + extSz;
+        /* Length of list data with one certificate and extensions. */
+        listSz = CERT_HEADER_SZ + certSz + extSz;
 
         /* Send rest of chain if sending cert (chain has leading size/s). */
         if (certSz > 0 && ssl->buffers.certChainCnt > 0) {
-            /* The pointer to the current spot in the cert chain buffer. */
             p = ssl->buffers.certChain->buffer;
             /* Chain length including extensions. */
@@ -4242,10 +4983,5 @@
         length -= (ssl->fragOffset + headerSz);
 
-    maxFragment = MAX_RECORD_SIZE;
-
-    #ifdef HAVE_MAX_FRAGMENT
-    if (ssl->max_fragment != 0 && maxFragment >= ssl->max_fragment)
-        maxFragment = ssl->max_fragment;
-    #endif /* HAVE_MAX_FRAGMENT */
+    maxFragment = wolfSSL_GetMaxRecordSize(ssl, MAX_RECORD_SIZE);
 
     while (length > 0 && ret == 0) {
@@ -4256,12 +4992,11 @@
 
         if (ssl->fragOffset == 0)  {
-            if (headerSz + certSz + OPAQUE16_LEN + certChainSz <=
+            if (headerSz + certSz + extSz + certChainSz <=
                 maxFragment - HANDSHAKE_HEADER_SZ) {
-
-                fragSz = headerSz + certSz + OPAQUE16_LEN + certChainSz;
-            }
-            else {
+                fragSz = headerSz + certSz + extSz + certChainSz;
+            }
+            else
                 fragSz = maxFragment - HANDSHAKE_HEADER_SZ;
-            }
+
             sendSz += fragSz + HANDSHAKE_HEADER_SZ;
             i += HANDSHAKE_HEADER_SZ;
@@ -4309,13 +5044,14 @@
             AddTls13RecordHeader(output, fragSz, handshake, ssl);
 
-        if (certSz > 0 && ssl->fragOffset < certSz + OPAQUE16_LEN) {
-            /* Put in the leaf certificate and empty extension. */
-            word32 copySz = AddCertExt(ssl->buffers.certificate->buffer, certSz,
-                                       ssl->fragOffset, fragSz, output + i);
-
+        if (certSz > 0 && ssl->fragOffset < certSz + extSz) {
+            /* Put in the leaf certificate with extensions. */
+            word32 copySz = AddCertExt(ssl, ssl->buffers.certificate->buffer,
+                            certSz, extSz, ssl->fragOffset, fragSz, output + i);
             i += copySz;
             ssl->fragOffset += copySz;
             length -= copySz;
             fragSz -= copySz;
+            if (ssl->fragOffset == certSz + extSz)
+                FreeDer(&ssl->buffers.certExts);
         }
         if (certChainSz > 0 && fragSz > 0) {
@@ -4327,4 +5063,6 @@
                     /* Find next CA certificate to write out. */
                     offset = 0;
+                    /* Point to the start of current cert in chain buffer. */
+                    p = ssl->buffers.certChain->buffer + idx;
                     len = NextCert(ssl->buffers.certChain->buffer,
                                    ssl->buffers.certChain->length, &idx);
@@ -4334,5 +5072,6 @@
 
                 /* Write out certificate and empty extension. */
-                l = AddCertExt(p, len, offset, fragSz, output + i);
+                l = AddCertExt(ssl, p, len, OPAQUE16_LEN, offset, fragSz,
+                                                                    output + i);
                 i += l;
                 ssl->fragOffset += l;
@@ -4357,8 +5096,8 @@
         #ifdef WOLFSSL_CALLBACKS
             if (ssl->hsInfoOn)
-                AddPacketName("Certificate", &ssl->handShakeInfo);
+                AddPacketName(ssl, "Certificate");
             if (ssl->toInfoOn) {
-                AddPacketInfo("Certificate", &ssl->timeoutInfo, output, sendSz,
-                               ssl->heap);
+                AddPacketInfo(ssl, "Certificate", handshake, output,
+                        sendSz, WRITE_PROTO, ssl->heap);
             }
         #endif
@@ -4385,4 +5124,5 @@
 
     WOLFSSL_LEAVE("SendTls13Certificate", ret);
+    WOLFSSL_END(WC_FUNC_CERTIFICATE_SEND);
 
     return ret;
@@ -4391,7 +5131,4 @@
 typedef struct Scv13Args {
     byte*  output; /* not allocated */
-#ifndef NO_RSA
-    byte*  verifySig;
-#endif
     byte*  verify; /* not allocated */
     word32 idx;
@@ -4411,10 +5148,4 @@
     (void)ssl;
 
-#ifndef NO_RSA
-    if (args->verifySig) {
-        XFREE(args->verifySig, ssl->heap, DYNAMIC_TYPE_SIGNATURE);
-        args->verifySig = NULL;
-    }
-#endif
     if (args->sigData) {
         XFREE(args->sigData, ssl->heap, DYNAMIC_TYPE_SIGNATURE);
@@ -4423,4 +5154,5 @@
 }
 
+/* handle generation TLS v1.3 certificate_verify (15) */
 /* Send the TLS v1.3 CertificateVerify message.
  * A hash of all the message so far is used.
@@ -4444,4 +5176,5 @@
 #endif
 
+    WOLFSSL_START(WC_FUNC_CERTIFICATE_VERIFY_SEND);
     WOLFSSL_ENTER("SendTls13CertificateVerify");
 
@@ -4473,5 +5206,5 @@
             }
 
-            args->sendSz = MAX_CERT_VERIFY_SZ;
+            args->sendSz = MAX_CERT_VERIFY_SZ + MAX_MSG_EXTRA;
             /* Always encrypted.  */
             args->sendSz += MAX_MSG_EXTRA;
@@ -4498,7 +5231,21 @@
                           &args->output[RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ];
 
+            if (ssl->buffers.key == NULL) {
+            #ifdef HAVE_PK_CALLBACKS
+                if (wolfSSL_CTX_IsPrivatePkSet(ssl->ctx))
+                    args->length = GetPrivateKeySigSize(ssl);
+                else
+            #endif
+                    ERROR_OUT(NO_PRIVATE_KEY, exit_scv);
+            }
+            else {
             ret = DecodePrivateKey(ssl, &args->length);
             if (ret != 0)
                 goto exit_scv;
+            }
+
+            if (args->length <= 0) {
+                ERROR_OUT(NO_PRIVATE_KEY, exit_scv);
+            }
 
             /* Add signature algorithm. */
@@ -4513,11 +5260,20 @@
             EncodeSigAlg(ssl->suites->hashAlgo, args->sigAlgo, args->verify);
 
-            /* Create the data to be signed. */
+            if (ssl->hsType == DYNAMIC_TYPE_RSA) {
+                int sigLen = MAX_SIG_DATA_SZ;
+                if (args->length > MAX_SIG_DATA_SZ)
+                    sigLen = args->length;
+                args->sigData = (byte*)XMALLOC(sigLen, ssl->heap,
+                                                        DYNAMIC_TYPE_SIGNATURE);
+            }
+            else {
             args->sigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap,
                                                     DYNAMIC_TYPE_SIGNATURE);
+            }
             if (args->sigData == NULL) {
                 ERROR_OUT(MEMORY_E, exit_scv);
             }
 
+            /* Create the data to be signed. */
             ret = CreateSigData(ssl, args->sigData, &args->sigDataSz, 0);
             if (ret != 0)
@@ -4527,5 +5283,5 @@
             if (ssl->hsType == DYNAMIC_TYPE_RSA) {
                 /* build encoded signature buffer */
-                sig->length = MAX_ENCODED_SIG_SZ;
+                sig->length = WC_MAX_DIGEST_SIZE;
                 sig->buffer = (byte*)XMALLOC(sig->length, ssl->heap,
                                                     DYNAMIC_TYPE_SIGNATURE);
@@ -4553,5 +5309,5 @@
                 if (ret < 0)
                     goto exit_scv;
-                args->sigDataSz = ret;
+                args->sigDataSz = (word16)ret;
                 ret = 0;
             }
@@ -4559,5 +5315,8 @@
         #ifdef HAVE_ED25519
             if (ssl->hsType == DYNAMIC_TYPE_ED25519) {
-                /* Nothing to do */
+                ret = Ed25519CheckPubKey(ssl);
+                if (ret < 0) {
+                    ERROR_OUT(ret, exit_scv);
+                }
                 sig->length = ED25519_SIG_SIZE;
             }
@@ -4576,12 +5335,11 @@
                     args->verify + HASH_SIG_SIZE + VERIFY_HEADER,
                     &sig->length, (ecc_key*)ssl->hsKey,
-            #if defined(HAVE_PK_CALLBACKS)
-                    ssl->buffers.key->buffer, ssl->buffers.key->length,
-                    ssl->EccSignCtx
+            #ifdef HAVE_PK_CALLBACKS
+                    ssl->buffers.key
             #else
-                    NULL, 0, NULL
+                    NULL
             #endif
                 );
-                args->length = sig->length;
+                args->length = (word16)sig->length;
             }
         #endif /* HAVE_ECC */
@@ -4591,9 +5349,8 @@
                     args->verify + HASH_SIG_SIZE + VERIFY_HEADER,
                     &sig->length, (ed25519_key*)ssl->hsKey,
-            #if defined(HAVE_PK_CALLBACKS)
-                    ssl->buffers.key->buffer, ssl->buffers.key->length,
-                    ssl->Ed25519SignCtx
+            #ifdef HAVE_PK_CALLBACKS
+                    ssl->buffers.key
             #else
-                    NULL, 0, NULL
+                    NULL
             #endif
                 );
@@ -4608,12 +5365,13 @@
                     args->sigAlgo, ssl->suites->hashAlgo,
                     (RsaKey*)ssl->hsKey,
-                    ssl->buffers.key->buffer, ssl->buffers.key->length,
-                #ifdef HAVE_PK_CALLBACKS
-                    ssl->RsaSignCtx
-                #else
-                    NULL
-                #endif
+                    ssl->buffers.key
                 );
-                args->length = args->sigLen;
+                if (ret == 0) {
+                    args->length = (word16)args->sigLen;
+
+                    XMEMCPY(args->sigData,
+                        args->verify + HASH_SIG_SIZE + VERIFY_HEADER,
+                        args->sigLen);
+                }
             }
         #endif /* !NO_RSA */
@@ -4636,19 +5394,10 @@
         #ifndef NO_RSA
             if (ssl->hsType == DYNAMIC_TYPE_RSA) {
-                if (args->verifySig == NULL) {
-                    args->verifySig = (byte*)XMALLOC(args->sigLen, ssl->heap,
-                                                   DYNAMIC_TYPE_SIGNATURE);
-                    if (args->verifySig == NULL) {
-                        ERROR_OUT(MEMORY_E, exit_scv);
-                    }
-                    XMEMCPY(args->verifySig,
-                        args->verify + HASH_SIG_SIZE + VERIFY_HEADER,
-                        args->sigLen);
-                }
-
                 /* check for signature faults */
-                ret = VerifyRsaSign(ssl, args->verifySig, args->sigLen,
+                ret = VerifyRsaSign(ssl, args->sigData, args->sigLen,
                     sig->buffer, sig->length, args->sigAlgo,
-                    ssl->suites->hashAlgo, (RsaKey*)ssl->hsKey);
+                    ssl->suites->hashAlgo, (RsaKey*)ssl->hsKey,
+                    ssl->buffers.key
+                );
             }
         #endif /* !NO_RSA */
@@ -4697,8 +5446,8 @@
         #ifdef WOLFSSL_CALLBACKS
             if (ssl->hsInfoOn)
-                AddPacketName("CertificateVerify", &ssl->handShakeInfo);
+                AddPacketName(ssl, "CertificateVerify");
             if (ssl->toInfoOn) {
-                AddPacketInfo("CertificateVerify", &ssl->timeoutInfo,
-                              args->output, args->sendSz, ssl->heap);
+                AddPacketInfo(ssl, "CertificateVerify", handshake,
+                            args->output, args->sendSz, WRITE_PROTO, ssl->heap);
             }
         #endif
@@ -4717,4 +5466,5 @@
 
     WOLFSSL_LEAVE("SendTls13CertificateVerify", ret);
+    WOLFSSL_END(WC_FUNC_CERTIFICATE_VERIFY_SEND);
 
 #ifdef WOLFSSL_ASYNC_CRYPT
@@ -4732,5 +5482,5 @@
 }
 
-
+/* handle processing TLS v1.3 certificate (11) */
 /* Parse and handle a TLS v1.3 Certificate message.
  *
@@ -4747,10 +5497,15 @@
     int ret;
 
+    WOLFSSL_START(WC_FUNC_CERTIFICATE_DO);
     WOLFSSL_ENTER("DoTls13Certificate");
 
     ret = ProcessPeerCerts(ssl, input, inOutIdx, totalSz);
-
+    if (ret == 0) {
+#if !defined(NO_WOLFSSL_CLIENT)
+        if (ssl->options.side == WOLFSSL_CLIENT_END)
+            ssl->options.serverState = SERVER_CERT_COMPLETE;
+#endif
 #if !defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
-    if (ret == 0 && ssl->options.side == WOLFSSL_SERVER_END &&
+        if (ssl->options.side == WOLFSSL_SERVER_END &&
                                 ssl->options.handShakeState == HANDSHAKE_DONE) {
         /* reset handshake states */
@@ -4760,6 +5515,8 @@
     }
 #endif
+    }
 
     WOLFSSL_LEAVE("DoTls13Certificate", ret);
+    WOLFSSL_END(WC_FUNC_CERTIFICATE_DO);
 
     return ret;
@@ -4794,4 +5551,5 @@
 }
 
+/* handle processing TLS v1.3 certificate_verify (15) */
 /* Parse and handle a TLS v1.3 CertificateVerify message.
  *
@@ -4817,4 +5575,5 @@
 #endif
 
+    WOLFSSL_START(WC_FUNC_CERTIFICATE_VERIFY_DO);
     WOLFSSL_ENTER("DoTls13CertificateVerify");
 
@@ -4847,6 +5606,5 @@
         {
         #ifdef WOLFSSL_CALLBACKS
-            if (ssl->hsInfoOn) AddPacketName("CertificateVerify",
-                                             &ssl->handShakeInfo);
+            if (ssl->hsInfoOn) AddPacketName(ssl, "CertificateVerify");
             if (ssl->toInfoOn) AddLateName("CertificateVerify",
                                            &ssl->timeoutInfo);
@@ -4926,5 +5684,5 @@
                 if (ret < 0)
                     goto exit_dcv;
-                args->sigDataSz = ret;
+                args->sigDataSz = (word16)ret;
                 ret = 0;
             }
@@ -4953,6 +5711,5 @@
         {
         #ifndef NO_RSA
-            if (args->sigAlgo == rsa_sa_algo ||
-                                             args->sigAlgo == rsa_pss_sa_algo) {
+            if (ssl->peerRsaKey != NULL && ssl->peerRsaKeyPresent != 0) {
                 WOLFSSL_MSG("Doing RSA peer cert verify");
 
@@ -4960,9 +5717,7 @@
                     args->sigAlgo, args->hashAlgo, ssl->peerRsaKey,
                 #ifdef HAVE_PK_CALLBACKS
-                    ssl->buffers.peerRsaKey.buffer,
-                    ssl->buffers.peerRsaKey.length,
-                    ssl->RsaVerifyCtx
+                    &ssl->buffers.peerRsaKey
                 #else
-                    NULL, 0, NULL
+                    NULL
                 #endif
                 );
@@ -4970,4 +5725,7 @@
                     args->sendSz = ret;
                     ret = 0;
+
+                    FreeKey(ssl, DYNAMIC_TYPE_RSA, (void**)&ssl->peerRsaKey);
+                    ssl->peerRsaKeyPresent = 0;
                 }
             }
@@ -4981,11 +5739,14 @@
                     ssl->peerEccDsaKey,
                 #ifdef HAVE_PK_CALLBACKS
-                    ssl->buffers.peerEccDsaKey.buffer,
-                    ssl->buffers.peerEccDsaKey.length,
-                    ssl->EccVerifyCtx
+                    &ssl->buffers.peerEccDsaKey
                 #else
-                    NULL, 0, NULL
+                    NULL
                 #endif
                 );
+
+                if (ret >= 0) {
+                    FreeKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->peerEccDsaKey);
+                    ssl->peerEccDsaKeyPresent = 0;
+                }
             }
         #endif /* HAVE_ECC */
@@ -4998,11 +5759,15 @@
                     ssl->peerEd25519Key,
                 #ifdef HAVE_PK_CALLBACKS
-                    ssl->buffers.peerEd25519Key.buffer,
-                    ssl->buffers.peerEd25519Key.length,
-                    ssl->Ed25519VerifyCtx
+                    &ssl->buffers.peerEd25519Key
                 #else
-                    NULL, 0, NULL
+                    NULL
                 #endif
                 );
+
+                if (ret >= 0) {
+                    FreeKey(ssl, DYNAMIC_TYPE_ED25519,
+                                                  (void**)&ssl->peerEd25519Key);
+                    ssl->peerEd25519KeyPresent = 0;
+                }
             }
         #endif
@@ -5060,14 +5825,18 @@
 
     WOLFSSL_LEAVE("DoTls13CertificateVerify", ret);
+    WOLFSSL_END(WC_FUNC_CERTIFICATE_VERIFY_DO);
 
 #ifdef WOLFSSL_ASYNC_CRYPT
     /* Handle async operation */
     if (ret == WC_PENDING_E) {
-        /* Mark message as not recevied so it can process again */
+        /* Mark message as not received so it can process again */
         ssl->msgsReceived.got_certificate_verify = 0;
 
         return ret;
     }
+    else
 #endif /* WOLFSSL_ASYNC_CRYPT */
+    if (ret != 0)
+        SendAlert(ssl, alert_fatal, decrypt_error);
 
     /* Final cleanup */
@@ -5096,6 +5865,7 @@
     word32 finishedSz = 0;
     byte*  secret;
-    byte   mac[MAX_DIGEST_SIZE];
-
+    byte   mac[WC_MAX_DIGEST_SIZE];
+
+    WOLFSSL_START(WC_FUNC_FINISHED_DO);
     WOLFSSL_ENTER("DoTls13Finished");
 
@@ -5104,14 +5874,22 @@
         return BUFFER_E;
 
-    if (ssl->options.side == WOLFSSL_CLIENT_END) {
+    if (ssl->options.handShakeDone) {
+        ret = DeriveFinishedSecret(ssl, ssl->clientSecret,
+                                   ssl->keys.client_write_MAC_secret);
+        if (ret != 0)
+            return ret;
+
+        secret = ssl->keys.client_write_MAC_secret;
+    }
+    else if (ssl->options.side == WOLFSSL_CLIENT_END) {
         /* All the handshake messages have been received to calculate
          * client and server finished keys.
          */
-        ret = DeriveFinishedSecret(ssl, ssl->arrays->clientSecret,
+        ret = DeriveFinishedSecret(ssl, ssl->clientSecret,
                                    ssl->keys.client_write_MAC_secret);
         if (ret != 0)
             return ret;
 
-        ret = DeriveFinishedSecret(ssl, ssl->arrays->serverSecret,
+        ret = DeriveFinishedSecret(ssl, ssl->serverSecret,
                                    ssl->keys.server_write_MAC_secret);
         if (ret != 0)
@@ -5130,5 +5908,5 @@
 
     #ifdef WOLFSSL_CALLBACKS
-        if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo);
+        if (ssl->hsInfoOn) AddPacketName(ssl, "Finished");
         if (ssl->toInfoOn) AddLateName("Finished", &ssl->timeoutInfo);
     #endif
@@ -5138,4 +5916,5 @@
         if (XMEMCMP(input + *inOutIdx, mac, size) != 0){
             WOLFSSL_MSG("Verify finished error on hashes");
+            SendAlert(ssl, alert_fatal, decrypt_error);
             return VERIFY_FINISHED_ERROR;
         }
@@ -5148,5 +5927,5 @@
                                                   !ssl->options.handShakeDone) {
 #ifdef WOLFSSL_EARLY_DATA
-        if (ssl->earlyData) {
+        if (ssl->earlyData != no_early_data) {
             if ((ret = DeriveTls13Keys(ssl, no_key, DECRYPT_SIDE_ONLY, 1)) != 0)
                 return ret;
@@ -5171,4 +5950,5 @@
 
     WOLFSSL_LEAVE("DoTls13Finished", 0);
+    WOLFSSL_END(WC_FUNC_FINISHED_DO);
 
     return 0;
@@ -5192,7 +5972,8 @@
     byte* secret;
 
+    WOLFSSL_START(WC_FUNC_FINISHED_SEND);
     WOLFSSL_ENTER("SendTls13Finished");
 
-    outputSz = MAX_DIGEST_SIZE + DTLS_HANDSHAKE_HEADER_SZ + MAX_MSG_EXTRA;
+    outputSz = WC_MAX_DIGEST_SIZE + DTLS_HANDSHAKE_HEADER_SZ + MAX_MSG_EXTRA;
     /* Check buffers are big enough and grow if needed. */
     if ((ret = CheckAvailableSize(ssl, outputSz)) != 0)
@@ -5207,5 +5988,13 @@
 
     /* make finished hashes */
-    if (ssl->options.side == WOLFSSL_CLIENT_END)
+    if (ssl->options.handShakeDone) {
+        ret = DeriveFinishedSecret(ssl, ssl->clientSecret,
+                                   ssl->keys.client_write_MAC_secret);
+        if (ret != 0)
+            return ret;
+
+        secret = ssl->keys.client_write_MAC_secret;
+    }
+    else if (ssl->options.side == WOLFSSL_CLIENT_END)
         secret = ssl->keys.client_write_MAC_secret;
     else {
@@ -5213,10 +6002,10 @@
          * server finished keys.
          */
-        ret = DeriveFinishedSecret(ssl, ssl->arrays->clientSecret,
+        ret = DeriveFinishedSecret(ssl, ssl->clientSecret,
                                    ssl->keys.client_write_MAC_secret);
         if (ret != 0)
             return ret;
 
-        ret = DeriveFinishedSecret(ssl, ssl->arrays->serverSecret,
+        ret = DeriveFinishedSecret(ssl, ssl->serverSecret,
                                    ssl->keys.server_write_MAC_secret);
         if (ret != 0)
@@ -5235,5 +6024,5 @@
         return BUILD_MSG_ERROR;
 
-    if (!ssl->options.resuming) {
+    if (!ssl->options.resuming && ssl->options.side == WOLFSSL_SERVER_END) {
 #ifndef NO_SESSION_CACHE
         AddSession(ssl);    /* just try */
@@ -5242,15 +6031,12 @@
 
     #ifdef WOLFSSL_CALLBACKS
-        if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo);
+        if (ssl->hsInfoOn) AddPacketName(ssl, "Finished");
         if (ssl->toInfoOn) {
-            AddPacketInfo("Finished", &ssl->timeoutInfo, output, sendSz,
-                          ssl->heap);
+            AddPacketInfo(ssl, "Finished", handshake, output, sendSz,
+                          WRITE_PROTO, ssl->heap);
         }
     #endif
 
     ssl->buffers.outputBuffer.length += sendSz;
-
-    if ((ret = SendBuffered(ssl)) != 0)
-        return ret;
 
     if (ssl->options.side == WOLFSSL_SERVER_END) {
@@ -5264,5 +6050,5 @@
         }
         if ((ret = DeriveTls13Keys(ssl, traffic_key, DECRYPT_SIDE_ONLY,
-                                                       !ssl->earlyData)) != 0) {
+                                       ssl->earlyData == no_early_data)) != 0) {
             return ret;
         }
@@ -5280,5 +6066,5 @@
                                                   !ssl->options.handShakeDone) {
 #ifdef WOLFSSL_EARLY_DATA
-        if (ssl->earlyData) {
+        if (ssl->earlyData != no_early_data) {
             if ((ret = DeriveTls13Keys(ssl, no_key, ENCRYPT_AND_DECRYPT_SIDE,
                                                                      1)) != 0) {
@@ -5293,27 +6079,32 @@
 #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
         ret = DeriveResumptionSecret(ssl, ssl->session.masterSecret);
-#endif
-    }
-
-    if (ssl->options.resuming) {
-        if (ssl->options.side == WOLFSSL_CLIENT_END) {
+        if (ret != 0)
+            return ret;
+#endif
+    }
+
+#ifndef NO_WOLFSSL_CLIENT
+    if (ssl->options.side == WOLFSSL_CLIENT_END) {
+        ssl->options.clientState = CLIENT_FINISHED_COMPLETE;
             ssl->options.handShakeState = HANDSHAKE_DONE;
             ssl->options.handShakeDone  = 1;
         }
-    }
-#ifndef NO_WOLFSSL_CLIENT
-    if (ssl->options.side == WOLFSSL_CLIENT_END) {
-        if (!ssl->options.resuming) {
-            ssl->options.handShakeState = HANDSHAKE_DONE;
-            ssl->options.handShakeDone  = 1;
-        }
-    }
-#endif
+#endif
+#ifndef NO_WOLFSSL_SERVER
+    if (ssl->options.side == WOLFSSL_SERVER_END) {
+        ssl->options.serverState = SERVER_FINISHED_COMPLETE;
+    }
+#endif
+
+    if ((ret = SendBuffered(ssl)) != 0)
+        return ret;
 
     WOLFSSL_LEAVE("SendTls13Finished", ret);
+    WOLFSSL_END(WC_FUNC_FINISHED_SEND);
 
     return ret;
 }
 
+/* handle generation TLS v1.3 key_update (24) */
 /* Send the TLS v1.3 KeyUpdate message.
  *
@@ -5331,4 +6122,5 @@
     word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
 
+    WOLFSSL_START(WC_FUNC_KEY_UPDATE_SEND);
     WOLFSSL_ENTER("SendTls13KeyUpdate");
 
@@ -5362,8 +6154,8 @@
 
     #ifdef WOLFSSL_CALLBACKS
-        if (ssl->hsInfoOn) AddPacketName("KeyUpdate", &ssl->handShakeInfo);
+        if (ssl->hsInfoOn) AddPacketName(ssl, "KeyUpdate");
         if (ssl->toInfoOn) {
-            AddPacketInfo("KeyUpdate", &ssl->timeoutInfo, output, sendSz,
-                          ssl->heap);
+            AddPacketInfo(ssl, "KeyUpdate", handshake, output, sendSz,
+                          WRITE_PROTO, ssl->heap);
         }
     #endif
@@ -5383,8 +6175,10 @@
 
     WOLFSSL_LEAVE("SendTls13KeyUpdate", ret);
+    WOLFSSL_END(WC_FUNC_KEY_UPDATE_SEND);
 
     return ret;
 }
 
+/* handle processing TLS v1.3 key_update (24) */
 /* Parse and handle a TLS v1.3 KeyUpdate message.
  *
@@ -5402,4 +6196,5 @@
     word32 i = *inOutIdx;
 
+    WOLFSSL_START(WC_FUNC_KEY_UPDATE_DO);
     WOLFSSL_ENTER("DoTls13KeyUpdate");
 
@@ -5440,4 +6235,5 @@
 
     WOLFSSL_LEAVE("DoTls13KeyUpdate", ret);
+    WOLFSSL_END(WC_FUNC_KEY_UPDATE_DO);
 
     return 0;
@@ -5461,4 +6257,5 @@
     word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
 
+    WOLFSSL_START(WC_FUNC_END_OF_EARLY_DATA_SEND);
     WOLFSSL_ENTER("SendTls13EndOfEarlyData");
 
@@ -5492,4 +6289,5 @@
 
     WOLFSSL_LEAVE("SendTls13EndOfEarlyData", ret);
+    WOLFSSL_END(WC_FUNC_END_OF_EARLY_DATA_SEND);
 
     return ret;
@@ -5498,4 +6296,5 @@
 
 #ifndef NO_WOLFSSL_SERVER
+/* handle processing of TLS 1.3 end_of_early_data (5) */
 /* Parse the TLS v1.3 EndOfEarlyData message that indicates that there will be
  * no more early application data.
@@ -5513,4 +6312,5 @@
     (void)input;
 
+    WOLFSSL_START(WC_FUNC_END_OF_EARLY_DATA_DO);
     WOLFSSL_ENTER("DoTls13EndOfEarlyData");
 
@@ -5518,4 +6318,12 @@
         return BUFFER_ERROR;
 
+    if (ssl->earlyData == no_early_data) {
+        WOLFSSL_MSG("EndOfEarlyData recieved unexpectedly");
+        SendAlert(ssl, alert_fatal, unexpected_message);
+        return OUT_OF_ORDER_E;
+    }
+
+    ssl->earlyData = done_early_data;
+
     /* Always encrypted. */
     *inOutIdx += ssl->keys.padSz;
@@ -5523,5 +6331,6 @@
     ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY);
 
-    WOLFSSL_LEAVE("SendTls13EndOfEarlyData", ret);
+    WOLFSSL_LEAVE("DoTls13EndOfEarlyData", ret);
+    WOLFSSL_END(WC_FUNC_END_OF_EARLY_DATA_DO);
 
     return ret;
@@ -5551,5 +6360,10 @@
     word16 length;
     word32 now;
-
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    const byte*  nonce;
+    byte         nonceLength;
+#endif
+
+    WOLFSSL_START(WC_FUNC_NEW_SESSION_TICKET_DO);
     WOLFSSL_ENTER("DoTls13NewSessionTicket");
 
@@ -5567,4 +6381,20 @@
     ato32(input + *inOutIdx, &ageAdd);
     *inOutIdx += SESSION_ADD_SZ;
+
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    /* Ticket nonce. */
+    if ((*inOutIdx - begin) + 1 > size)
+        return BUFFER_ERROR;
+    nonceLength = input[*inOutIdx];
+    if (nonceLength > MAX_TICKET_NONCE_SZ) {
+        WOLFSSL_MSG("Nonce length not supported");
+        return INVALID_PARAMETER;
+    }
+    *inOutIdx += 1;
+    if ((*inOutIdx - begin) + nonceLength > size)
+        return BUFFER_ERROR;
+    nonce = input + *inOutIdx;
+    *inOutIdx += nonceLength;
+#endif
 
     /* Ticket length. */
@@ -5593,4 +6423,10 @@
     ssl->session.maxEarlyDataSz = ssl->options.maxEarlyDataSz;
     #endif
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    ssl->session.ticketNonce.len = nonceLength;
+    if (nonceLength > 0)
+        XMEMCPY(&ssl->session.ticketNonce.data, nonce, nonceLength);
+#endif
+    ssl->session.namedGroup     = ssl->namedGroup;
 
     if ((*inOutIdx - begin) + EXTS_SZ > size)
@@ -5626,4 +6462,5 @@
 
     WOLFSSL_LEAVE("DoTls13NewSessionTicket", 0);
+    WOLFSSL_END(WC_FUNC_NEW_SESSION_TICKET_DO);
 
     return 0;
@@ -5648,5 +6485,5 @@
     int         ret;
     word32      finishedSz = 0;
-    byte        mac[MAX_DIGEST_SIZE];
+    byte        mac[WC_MAX_DIGEST_SIZE];
     Digest      digest;
     static byte header[] = { 0x14, 0x00, 0x00, 0x00 };
@@ -5684,5 +6521,5 @@
     header[FINISHED_MSG_SIZE_OFFSET] = finishedSz;
 #ifdef WOLFSSL_EARLY_DATA
-    if (ssl->earlyData) {
+    if (ssl->earlyData != no_early_data) {
         static byte endOfEarlyData[] = { 0x05, 0x00, 0x00, 0x00 };
         ret = HashInputRaw(ssl, endOfEarlyData, sizeof(endOfEarlyData));
@@ -5739,8 +6576,9 @@
     int    ret;
     int    sendSz;
-    word32 extSz;
+    word16 extSz;
     word32 length;
     word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
 
+    WOLFSSL_START(WC_FUNC_NEW_SESSION_TICKET_SEND);
     WOLFSSL_ENTER("SendTls13NewSessionTicket");
 
@@ -5752,4 +6590,14 @@
 #endif
 
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    /* Start ticket nonce at 0 and go up to 255. */
+    if (ssl->session.ticketNonce.len == 0) {
+        ssl->session.ticketNonce.len = DEF_TICKET_NONCE_SZ;
+        ssl->session.ticketNonce.data[0] = 0;
+    }
+    else
+        ssl->session.ticketNonce.data[0]++;
+#endif
+
     if (!ssl->options.noTicketTls13) {
         if ((ret = CreateTicket(ssl)) != 0)
@@ -5761,5 +6609,8 @@
     if (ssl->session.maxEarlyDataSz > 0)
         TLSX_EarlyData_Use(ssl, ssl->session.maxEarlyDataSz);
-    extSz = TLSX_GetResponseSize(ssl, session_ticket);
+    extSz = 0;
+    ret = TLSX_GetResponseSize(ssl, session_ticket, &extSz);
+    if (ret != 0)
+        return ret;
 #else
     extSz = EXTS_SZ;
@@ -5769,4 +6620,8 @@
     length = SESSION_HINT_SZ + SESSION_ADD_SZ + LENGTH_SZ +
              ssl->session.ticketLen + extSz;
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    /* Nonce */
+    length += TICKET_NONCE_LEN_SZ + DEF_TICKET_NONCE_SZ;
+#endif
     sendSz = idx + length + MAX_MSG_EXTRA;
 
@@ -5789,4 +6644,9 @@
     idx += SESSION_ADD_SZ;
 
+#ifndef WOLFSSL_TLS13_DRAFT_18
+    output[idx++] = ssl->session.ticketNonce.len;
+    output[idx++] = ssl->session.ticketNonce.data[0];
+#endif
+
     /* length */
     c16toa(ssl->session.ticketLen, output + idx);
@@ -5797,5 +6657,9 @@
 
 #ifdef WOLFSSL_EARLY_DATA
-    idx += TLSX_WriteResponse(ssl, output + idx, session_ticket);
+    extSz = 0;
+    ret = TLSX_WriteResponse(ssl, output + idx, session_ticket, &extSz);
+    if (ret != 0)
+        return ret;
+    idx += extSz;
 #else
     /* No extension support - empty extensions. */
@@ -5822,4 +6686,5 @@
 
     WOLFSSL_LEAVE("SendTls13NewSessionTicket", 0);
+    WOLFSSL_END(WC_FUNC_NEW_SESSION_TICKET_SEND);
 
     return ret;
@@ -5841,4 +6706,14 @@
 #ifndef NO_WOLFSSL_SERVER
         case client_hello:
+        #ifndef NO_WOLFSSL_CLIENT
+            if (ssl->options.side == WOLFSSL_CLIENT_END) {
+                WOLFSSL_MSG("ClientHello received by client");
+                return OUT_OF_ORDER_E;
+            }
+        #endif
+            if (ssl->options.clientState >= CLIENT_HELLO_COMPLETE) {
+                WOLFSSL_MSG("ClientHello received out of order");
+                return OUT_OF_ORDER_E;
+            }
             if (ssl->msgsReceived.got_client_hello == 2) {
                 WOLFSSL_MSG("Too many ClientHello received");
@@ -5852,4 +6727,11 @@
 #ifndef NO_WOLFSSL_CLIENT
         case server_hello:
+        #ifndef NO_WOLFSSL_SERVER
+            if (ssl->options.side == WOLFSSL_SERVER_END) {
+                WOLFSSL_MSG("ServerHello received by server");
+                return OUT_OF_ORDER_E;
+            }
+        #endif
+        #ifdef WOLFSSL_TLS13_DRAFT_18
             if (ssl->msgsReceived.got_server_hello) {
                 WOLFSSL_MSG("Duplicate ServerHello received");
@@ -5857,4 +6739,11 @@
             }
             ssl->msgsReceived.got_server_hello = 1;
+        #else
+            if (ssl->msgsReceived.got_server_hello == 2) {
+                WOLFSSL_MSG("Duplicate ServerHello received");
+                return DUPLICATE_MSG_E;
+            }
+            ssl->msgsReceived.got_server_hello++;
+        #endif
 
             break;
@@ -5863,7 +6752,13 @@
 #ifndef NO_WOLFSSL_CLIENT
         case session_ticket:
-            if (ssl->msgsReceived.got_session_ticket) {
-                WOLFSSL_MSG("Duplicate SessionTicket received");
-                return DUPLICATE_MSG_E;
+        #ifndef NO_WOLFSSL_SERVER
+            if (ssl->options.side == WOLFSSL_SERVER_END) {
+                WOLFSSL_MSG("NewSessionTicket received by server");
+                return OUT_OF_ORDER_E;
+            }
+        #endif
+            if (ssl->options.clientState < CLIENT_FINISHED_COMPLETE) {
+                WOLFSSL_MSG("NewSessionTicket received out of order");
+                return OUT_OF_ORDER_E;
             }
             ssl->msgsReceived.got_session_ticket = 1;
@@ -5875,4 +6770,18 @@
     #ifdef WOLFSSL_EARLY_DATA
         case end_of_early_data:
+        #ifndef NO_WOLFSSL_CLIENT
+            if (ssl->options.side == WOLFSSL_CLIENT_END) {
+                WOLFSSL_MSG("EndOfEarlyData received by client");
+                return OUT_OF_ORDER_E;
+            }
+        #endif
+            if (ssl->options.serverState < SERVER_FINISHED_COMPLETE) {
+                WOLFSSL_MSG("EndOfEarlyData received out of order");
+                return OUT_OF_ORDER_E;
+            }
+            if (ssl->options.clientState >= CLIENT_FINISHED_COMPLETE) {
+                WOLFSSL_MSG("EndOfEarlyData received out of order");
+                return OUT_OF_ORDER_E;
+            }
             if (ssl->msgsReceived.got_end_of_early_data == 1) {
                 WOLFSSL_MSG("Too many EndOfEarlyData received");
@@ -5885,6 +6794,17 @@
 #endif
 
+#ifdef WOLFSSL_TLS13_DRAFT_18
 #ifndef NO_WOLFSSL_CLIENT
         case hello_retry_request:
+        #ifndef NO_WOLFSSL_SERVER
+            if (ssl->options.side == WOLFSSL_SERVER_END) {
+                WOLFSSL_MSG("HelloRetryRequest received by server");
+                return OUT_OF_ORDER_E;
+            }
+        #endif
+            if (ssl->options.clientState > CLIENT_FINISHED_COMPLETE) {
+                WOLFSSL_MSG("HelloRetryRequest received out of order");
+                return OUT_OF_ORDER_E;
+            }
             if (ssl->msgsReceived.got_hello_retry_request) {
                 WOLFSSL_MSG("Duplicate HelloRetryRequest received");
@@ -5895,7 +6815,18 @@
             break;
 #endif
+#endif
 
 #ifndef NO_WOLFSSL_CLIENT
         case encrypted_extensions:
+        #ifndef NO_WOLFSSL_SERVER
+            if (ssl->options.side == WOLFSSL_SERVER_END) {
+                WOLFSSL_MSG("EncryptedExtensions received by server");
+                return OUT_OF_ORDER_E;
+            }
+        #endif
+            if (ssl->options.serverState != SERVER_HELLO_COMPLETE) {
+                WOLFSSL_MSG("EncryptedExtensions received out of order");
+                return OUT_OF_ORDER_E;
+            }
             if (ssl->msgsReceived.got_encrypted_extensions) {
                 WOLFSSL_MSG("Duplicate EncryptedExtensions received");
@@ -5908,4 +6839,28 @@
 
         case certificate:
+    #ifndef NO_WOLFSSL_CLIENT
+            if (ssl->options.side == WOLFSSL_CLIENT_END &&
+                ssl->options.serverState !=
+                                         SERVER_ENCRYPTED_EXTENSIONS_COMPLETE) {
+                WOLFSSL_MSG("Certificate received out of order - Client");
+                return OUT_OF_ORDER_E;
+            }
+        #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+            /* Server's authenticating with PSK must not send this. */
+            if (ssl->options.side == WOLFSSL_CLIENT_END &&
+                             ssl->options.serverState == SERVER_CERT_COMPLETE &&
+                             ssl->arrays->psk_keySz != 0) {
+                WOLFSSL_MSG("Certificate received while using PSK");
+                return SANITY_MSG_E;
+            }
+        #endif
+    #endif
+    #ifndef NO_WOLFSSL_SERVER
+            if (ssl->options.side == WOLFSSL_SERVER_END &&
+                ssl->options.serverState < SERVER_FINISHED_COMPLETE) {
+                WOLFSSL_MSG("Certificate received out of order - Server");
+                return OUT_OF_ORDER_E;
+            }
+    #endif
             if (ssl->msgsReceived.got_certificate) {
                 WOLFSSL_MSG("Duplicate Certificate received");
@@ -5914,33 +6869,44 @@
             ssl->msgsReceived.got_certificate = 1;
 
+            break;
+
 #ifndef NO_WOLFSSL_CLIENT
-            if (ssl->options.side == WOLFSSL_CLIENT_END) {
-                if ( ssl->msgsReceived.got_server_hello == 0) {
-                    WOLFSSL_MSG("No ServerHello before Cert");
+        case certificate_request:
+        #ifndef NO_WOLFSSL_SERVER
+            if (ssl->options.side == WOLFSSL_SERVER_END) {
+                WOLFSSL_MSG("CertificateRequest received by server");
                     return OUT_OF_ORDER_E;
                 }
-            }
-#endif
-#ifndef NO_WOLFSSL_SERVER
-            if (ssl->options.side == WOLFSSL_SERVER_END) {
-                if ( ssl->msgsReceived.got_client_hello == 0) {
-                    WOLFSSL_MSG("No ClientHello before Cert");
+#endif
+        #ifndef WOLFSSL_POST_HANDSHAKE_AUTH
+            if (ssl->options.serverState !=
+                                         SERVER_ENCRYPTED_EXTENSIONS_COMPLETE) {
+                WOLFSSL_MSG("CertificateRequest received out of order");
                     return OUT_OF_ORDER_E;
                 }
-            }
-#endif
-            break;
-
-#ifndef NO_WOLFSSL_CLIENT
-        case certificate_request:
-    #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
-            if (ssl->msgsReceived.got_finished)
-                ;
-            else
+        #else
+            if (ssl->options.serverState !=
+                                         SERVER_ENCRYPTED_EXTENSIONS_COMPLETE &&
+                       (ssl->options.serverState != SERVER_FINISHED_COMPLETE ||
+                        ssl->options.clientState != CLIENT_FINISHED_COMPLETE)) {
+                WOLFSSL_MSG("CertificateRequest received out of order");
+                return OUT_OF_ORDER_E;
+            }
+#endif
+        #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+            /* Server's authenticating with PSK must not send this. */
+            if (ssl->options.serverState ==
+                                         SERVER_ENCRYPTED_EXTENSIONS_COMPLETE &&
+                                                  ssl->arrays->psk_keySz != 0) {
+                WOLFSSL_MSG("CertificateRequset received while using PSK");
+                return SANITY_MSG_E;
+            }
     #endif
+        #ifndef WOLFSSL_POST_HANDSHAKE_AUTH
             if (ssl->msgsReceived.got_certificate_request) {
                 WOLFSSL_MSG("Duplicate CertificateRequest received");
                 return DUPLICATE_MSG_E;
             }
+        #endif
             ssl->msgsReceived.got_certificate_request = 1;
 
@@ -5949,4 +6915,36 @@
 
         case certificate_verify:
+    #ifndef NO_WOLFSSL_CLIENT
+            if (ssl->options.side == WOLFSSL_CLIENT_END) {
+                if (ssl->options.serverState != SERVER_CERT_COMPLETE) {
+                    WOLFSSL_MSG("No Cert before CertVerify");
+                    return OUT_OF_ORDER_E;
+                }
+            #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+                /* Server's authenticating with PSK must not send this. */
+                if (ssl->options.serverState == SERVER_CERT_COMPLETE &&
+                                                  ssl->arrays->psk_keySz != 0) {
+                    WOLFSSL_MSG("CertificateVerify received while using PSK");
+                    return SANITY_MSG_E;
+                }
+            #endif
+            }
+    #endif
+    #ifndef NO_WOLFSSL_SERVER
+            if (ssl->options.side == WOLFSSL_SERVER_END) {
+                if (ssl->options.serverState < SERVER_FINISHED_COMPLETE) {
+                    WOLFSSL_MSG("CertificateVerify received out of order");
+                    return OUT_OF_ORDER_E;
+                }
+                if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) {
+                    WOLFSSL_MSG("CertificateVerify before ClientHello done");
+                    return OUT_OF_ORDER_E;
+                }
+                if (!ssl->msgsReceived.got_certificate) {
+                    WOLFSSL_MSG("No Cert before CertificateVerify");
+                    return OUT_OF_ORDER_E;
+                }
+            }
+    #endif
             if (ssl->msgsReceived.got_certificate_verify) {
                 WOLFSSL_MSG("Duplicate CertificateVerify received");
@@ -5955,15 +6953,36 @@
             ssl->msgsReceived.got_certificate_verify = 1;
 
-            if (ssl->msgsReceived.got_certificate == 0) {
-                WOLFSSL_MSG("No Cert before CertVerify");
-                return OUT_OF_ORDER_E;
-            }
             break;
 
         case finished:
-    #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
-            if (1) {
-            }
-            else
+        #ifndef NO_WOLFSSL_CLIENT
+            if (ssl->options.side == WOLFSSL_CLIENT_END) {
+                if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) {
+                    WOLFSSL_MSG("Finished received out of order");
+                    return OUT_OF_ORDER_E;
+                }
+                if (ssl->options.serverState <
+                                         SERVER_ENCRYPTED_EXTENSIONS_COMPLETE) {
+                    WOLFSSL_MSG("Finished received out of order");
+                    return OUT_OF_ORDER_E;
+                }
+            }
+        #endif
+        #ifndef NO_WOLFSSL_SERVER
+            if (ssl->options.side == WOLFSSL_SERVER_END) {
+                if (ssl->options.serverState < SERVER_FINISHED_COMPLETE) {
+                    WOLFSSL_MSG("Finished received out of order");
+                    return OUT_OF_ORDER_E;
+                }
+                if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) {
+                    WOLFSSL_MSG("Finished received out of order");
+                    return OUT_OF_ORDER_E;
+                }
+            #ifdef WOLFSSL_EARLY_DATA
+                if (ssl->earlyData == process_early_data) {
+                    return OUT_OF_ORDER_E;
+                }
+            #endif
+            }
     #endif
             if (ssl->msgsReceived.got_finished) {
@@ -6004,6 +7023,7 @@
 {
     int ret = 0;
+    word32 inIdx = *inOutIdx;
+
     (void)totalSz;
-    word32 inIdx = *inOutIdx;
 
     WOLFSSL_ENTER("DoTls13HandShakeMsgType");
@@ -6016,4 +7036,5 @@
     if ( (ret = SanityCheckTls13MsgReceived(ssl, type)) != 0) {
         WOLFSSL_MSG("Sanity Check on handshake message type received failed");
+        SendAlert(ssl, alert_fatal, unexpected_message);
         return ret;
     }
@@ -6023,6 +7044,6 @@
     if (ssl->toInfoOn) {
         int add = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
-        AddPacketInfo(0, &ssl->timeoutInfo, input + *inOutIdx - add,
-                      size + add, ssl->heap);
+        AddPacketInfo(ssl, 0, handshake, input + *inOutIdx - add,
+                      size + add, READ_PROTO, ssl->heap);
         AddLateRecordHeader(&ssl->curRL, &ssl->timeoutInfo);
     }
@@ -6054,14 +7075,32 @@
     /* above checks handshake state */
     switch (type) {
-
 #ifndef NO_WOLFSSL_CLIENT
+    /* Messages only recieved by client. */
+    #ifdef WOLFSSL_TLS13_DRAFT_18
     case hello_retry_request:
         WOLFSSL_MSG("processing hello rety request");
         ret = DoTls13HelloRetryRequest(ssl, input, inOutIdx, size);
         break;
+    #endif
 
     case server_hello:
         WOLFSSL_MSG("processing server hello");
-        ret = DoTls13ServerHello(ssl, input, inOutIdx, size);
+        ret = DoTls13ServerHello(ssl, input, inOutIdx, size, &type);
+    #if !defined(WOLFSSL_NO_CLIENT_AUTH) && defined(HAVE_ED25519) && \
+                                                !defined(NO_ED25519_CLIENT_AUTH)
+        if (ssl->options.resuming || !IsAtLeastTLSv1_2(ssl) ||
+                                               IsAtLeastTLSv1_3(ssl->version)) {
+            ssl->options.cacheMessages = 0;
+            if (ssl->hsHashes->messages != NULL) {
+                XFREE(ssl->hsHashes->messages, ssl->heap, DYNAMIC_TYPE_HASHES);
+                ssl->hsHashes->messages = NULL;
+            }
+        }
+    #endif
+        break;
+
+    case encrypted_extensions:
+        WOLFSSL_MSG("processing encrypted extensions");
+        ret = DoTls13EncryptedExtensions(ssl, input, inOutIdx, size);
         break;
 
@@ -6077,11 +7116,22 @@
         ret = DoTls13NewSessionTicket(ssl, input, inOutIdx, size);
         break;
-
-    case encrypted_extensions:
-        WOLFSSL_MSG("processing encrypted extensions");
-        ret = DoTls13EncryptedExtensions(ssl, input, inOutIdx, size);
+#endif /* !NO_WOLFSSL_CLIENT */
+
+#ifndef NO_WOLFSSL_SERVER
+    /* Messages only recieved by server. */
+    case client_hello:
+        WOLFSSL_MSG("processing client hello");
+        ret = DoTls13ClientHello(ssl, input, inOutIdx, size);
         break;
-#endif /* !NO_WOLFSSL_CLIENT */
-
+
+    #ifdef WOLFSSL_EARLY_DATA
+    case end_of_early_data:
+        WOLFSSL_MSG("processing end of early data");
+        ret = DoTls13EndOfEarlyData(ssl, input, inOutIdx, size);
+        break;
+    #endif
+#endif /* !NO_WOLFSSL_SERVER */
+
+    /* Messages recieved by both client and server. */
 #ifndef NO_CERTS
     case certificate:
@@ -6098,13 +7148,4 @@
 #endif /* !NO_RSA || HAVE_ECC */
 
-#ifdef WOLFSSL_EARLY_DATA
-    #ifndef NO_WOLFSSL_SERVER
-    case end_of_early_data:
-        WOLFSSL_MSG("processing end of early data");
-        ret = DoTls13EndOfEarlyData(ssl, input, inOutIdx, size);
-        break;
-    #endif
-#endif
-
     case finished:
         WOLFSSL_MSG("processing finished");
@@ -6117,11 +7158,4 @@
         break;
 
-#ifndef NO_WOLFSSL_SERVER
-    case client_hello:
-        WOLFSSL_MSG("processing client hello");
-        ret = DoTls13ClientHello(ssl, input, inOutIdx, size);
-        break;
-#endif /* !NO_WOLFSSL_SERVER */
-
     default:
         WOLFSSL_MSG("Unknown handshake message type");
@@ -6134,14 +7168,15 @@
         ssl->error = 0;
 
-
     if (ret == 0 && type != client_hello && type != session_ticket &&
-                             type != key_update && ssl->error != WC_PENDING_E) {
+                                                           type != key_update) {
         ret = HashInput(ssl, input + inIdx, size);
+    }
+    if (ret == 0 && ssl->buffers.inputBuffer.dynamicFlag) {
+        ShrinkInputBuffer(ssl, NO_FORCED_FREE);
     }
 
     if (ret == BUFFER_ERROR || ret == MISSING_HANDSHAKE_DATA)
         SendAlert(ssl, alert_fatal, decode_error);
-
-    if (ret == EXT_NOT_ALLOWED || ret == PEER_KEY_ERROR ||
+    else if (ret == EXT_NOT_ALLOWED || ret == PEER_KEY_ERROR ||
             ret == ECC_PEERKEY_ERROR || ret == BAD_KEY_SHARE_DATA ||
             ret == PSK_KEY_ERROR || ret == INVALID_PARAMETER) {
@@ -6150,5 +7185,8 @@
 
     if (ssl->options.tls1_3) {
-        if (type == server_hello && ssl->options.side == WOLFSSL_CLIENT_END) {
+        /* Need to hash input message before deriving secrets. */
+    #ifndef NO_WOLFSSL_CLIENT
+        if (ssl->options.side == WOLFSSL_CLIENT_END) {
+            if (type == server_hello) {
             if ((ret = DeriveEarlySecret(ssl)) != 0)
                 return ret;
@@ -6168,21 +7206,12 @@
 #endif
         }
-#ifdef WOLFSSL_EARLY_DATA
-        if (type == encrypted_extensions &&
-                                      ssl->options.side == WOLFSSL_CLIENT_END) {
-            if (!ssl->earlyData)
-            {
-                if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0)
-                    return ret;
-            }
-        }
-#endif
-
-        if (type == finished && ssl->options.side == WOLFSSL_CLIENT_END) {
+
+            if (type == finished) {
             if ((ret = DeriveMasterSecret(ssl)) != 0)
                 return ret;
 #ifdef WOLFSSL_EARLY_DATA
             if ((ret = DeriveTls13Keys(ssl, traffic_key,
-                             ENCRYPT_AND_DECRYPT_SIDE, !ssl->earlyData)) != 0) {
+                                       ENCRYPT_AND_DECRYPT_SIDE,
+                                       ssl->earlyData == no_early_data)) != 0) {
                 return ret;
             }
@@ -6194,7 +7223,22 @@
 #endif
         }
-
+        #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
+            if (type == certificate_request &&
+                                ssl->options.handShakeState == HANDSHAKE_DONE) {
+                /* reset handshake states */
+                ssl->options.clientState = CLIENT_HELLO_COMPLETE;
+                ssl->options.connectState  = FIRST_REPLY_DONE;
+                ssl->options.handShakeState = CLIENT_HELLO_COMPLETE;
+
+                if (wolfSSL_connect_TLSv13(ssl) != SSL_SUCCESS)
+                    ret = POST_HAND_AUTH_ERROR;
+            }
+        #endif
+        }
+    #endif /* NO_WOLFSSL_CLIENT */
+
+#ifndef NO_WOLFSSL_SERVER
 #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
-        if (type == finished && ssl->options.side == WOLFSSL_SERVER_END) {
+        if (ssl->options.side == WOLFSSL_SERVER_END && type == finished) {
             ret = DeriveResumptionSecret(ssl, ssl->session.masterSecret);
             if (ret != 0)
@@ -6202,4 +7246,5 @@
         }
 #endif
+#endif /* NO_WOLFSSL_SERVER */
     }
 
@@ -6286,7 +7331,7 @@
         if (inputLength + ssl->arrays->pendingMsgOffset >
                                                     ssl->arrays->pendingMsgSz) {
-            return BUFFER_ERROR;
+            inputLength = ssl->arrays->pendingMsgSz -
+                                                  ssl->arrays->pendingMsgOffset;
         }
-
         XMEMCPY(ssl->arrays->pendingMsg + ssl->arrays->pendingMsgOffset,
                 input + *inOutIdx, inputLength);
@@ -6322,4 +7367,5 @@
 }
 
+#ifndef NO_WOLFSSL_CLIENT
 
 /* The client connecting to the server.
@@ -6336,6 +7382,4 @@
 int wolfSSL_connect_TLSv13(WOLFSSL* ssl)
 {
-    int neededState;
-
     WOLFSSL_ENTER("wolfSSL_connect_TLSv13()");
 
@@ -6382,5 +7426,13 @@
             WOLFSSL_MSG("connect state: CLIENT_HELLO_SENT");
     #ifdef WOLFSSL_EARLY_DATA
-            if (ssl->earlyData) {
+            if (ssl->earlyData != no_early_data) {
+        #if !defined(WOLFSSL_TLS13_DRAFT_18) && \
+                                         defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
+                if ((ssl->error = SendChangeCipher(ssl)) != 0) {
+                    WOLFSSL_ERROR(ssl->error);
+                    return WOLFSSL_FATAL_ERROR;
+                }
+                ssl->options.sentChangeCipher = 1;
+        #endif
                 ssl->options.handShakeState = CLIENT_HELLO_COMPLETE;
                 return WOLFSSL_SUCCESS;
@@ -6390,17 +7442,11 @@
 
         case CLIENT_HELLO_SENT:
-            neededState = ssl->options.resuming ? SERVER_FINISHED_COMPLETE :
-                                                  SERVER_HELLODONE_COMPLETE;
             /* Get the response/s from the server. */
-            while (ssl->options.serverState < neededState) {
+            while (ssl->options.serverState <
+                                          SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
                 if ((ssl->error = ProcessReply(ssl)) < 0) {
                     WOLFSSL_ERROR(ssl->error);
                     return WOLFSSL_FATAL_ERROR;
                 }
-                /* if resumption failed, reset needed state. */
-                if (neededState == SERVER_FINISHED_COMPLETE &&
-                        !ssl->options.resuming) {
-                    neededState = SERVER_HELLODONE_COMPLETE;
-                }
             }
 
@@ -6414,6 +7460,8 @@
 
             if (!ssl->options.tls1_3) {
+    #ifndef WOLFSSL_NO_TLS12
                 if (ssl->options.downgrade)
                     return wolfSSL_connect(ssl);
+    #endif
 
                 WOLFSSL_MSG("Client using higher version, fatal error");
@@ -6421,6 +7469,16 @@
             }
 
-            if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) {
-                ssl->options.serverState = NULL_STATE;
+            if (ssl->options.serverState ==
+                                          SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
+        #if !defined(WOLFSSL_TLS13_DRAFT_18) && \
+                                         defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
+                if (!ssl->options.sentChangeCipher) {
+                    if ((ssl->error = SendChangeCipher(ssl)) != 0) {
+                        WOLFSSL_ERROR(ssl->error);
+                        return WOLFSSL_FATAL_ERROR;
+                    }
+                    ssl->options.sentChangeCipher = 1;
+                }
+        #endif
                 /* Try again with different security parameters. */
                 if ((ssl->error = SendTls13ClientHello(ssl)) != 0) {
@@ -6435,21 +7493,10 @@
 
         case HELLO_AGAIN_REPLY:
-            if (ssl->options.serverState == NULL_STATE ||
-                                                ssl->error == WC_PENDING_E) {
-                neededState = ssl->options.resuming ? SERVER_FINISHED_COMPLETE :
-                                                      SERVER_HELLODONE_COMPLETE;
-
                 /* Get the response/s from the server. */
-                while (ssl->options.serverState < neededState) {
+            while (ssl->options.serverState < SERVER_FINISHED_COMPLETE) {
                     if ((ssl->error = ProcessReply(ssl)) < 0) {
                             WOLFSSL_ERROR(ssl->error);
                             return WOLFSSL_FATAL_ERROR;
                     }
-                    /* if resumption failed, reset needed state */
-                    else if (neededState == SERVER_FINISHED_COMPLETE) {
-                        if (!ssl->options.resuming)
-                            neededState = SERVER_HELLODONE_COMPLETE;
-                    }
-                }
             }
 
@@ -6460,5 +7507,5 @@
         case FIRST_REPLY_DONE:
         #ifdef WOLFSSL_EARLY_DATA
-            if (ssl->earlyData) {
+            if (ssl->earlyData != no_early_data) {
                 if ((ssl->error = SendTls13EndOfEarlyData(ssl)) != 0) {
                     WOLFSSL_ERROR(ssl->error);
@@ -6474,4 +7521,20 @@
 
         case FIRST_REPLY_FIRST:
+        #if !defined(WOLFSSL_TLS13_DRAFT_18) && \
+                                         defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
+            if (!ssl->options.sentChangeCipher) {
+                if ((ssl->error = SendChangeCipher(ssl)) != 0) {
+                    WOLFSSL_ERROR(ssl->error);
+                    return WOLFSSL_FATAL_ERROR;
+                }
+                ssl->options.sentChangeCipher = 1;
+            }
+        #endif
+
+            ssl->options.connectState = FIRST_REPLY_SECOND;
+            WOLFSSL_MSG("connect state: FIRST_REPLY_SECOND");
+            FALL_THROUGH;
+
+        case FIRST_REPLY_SECOND:
         #ifndef NO_CERTS
             if (!ssl->options.resuming && ssl->options.sendVerify) {
@@ -6485,10 +7548,9 @@
         #endif
 
-            ssl->options.connectState = FIRST_REPLY_SECOND;
-            WOLFSSL_MSG("connect state: FIRST_REPLY_SECOND");
+            ssl->options.connectState = FIRST_REPLY_THIRD;
+            WOLFSSL_MSG("connect state: FIRST_REPLY_THIRD");
             FALL_THROUGH;
 
-        case FIRST_REPLY_SECOND:
-
+        case FIRST_REPLY_THIRD:
         #ifndef NO_CERTS
             if (!ssl->options.resuming && ssl->options.sendVerify) {
@@ -6502,9 +7564,9 @@
         #endif
 
-            ssl->options.connectState = FIRST_REPLY_THIRD;
-            WOLFSSL_MSG("connect state: FIRST_REPLY_THIRD");
+            ssl->options.connectState = FIRST_REPLY_FOURTH;
+            WOLFSSL_MSG("connect state: FIRST_REPLY_FOURTH");
             FALL_THROUGH;
 
-        case FIRST_REPLY_THIRD:
+        case FIRST_REPLY_FOURTH:
             if ((ssl->error = SendTls13Finished(ssl)) != 0) {
                 WOLFSSL_ERROR(ssl->error);
@@ -6529,4 +7591,8 @@
         #endif /* NO_HANDSHAKE_DONE_CB */
 
+            if (!ssl->options.keepResources) {
+                FreeHandshakeResources(ssl);
+            }
+
             WOLFSSL_LEAVE("wolfSSL_connect_TLSv13()", WOLFSSL_SUCCESS);
             return WOLFSSL_SUCCESS;
@@ -6537,6 +7603,7 @@
     }
 }
-
-#if defined(WOLFSSL_SEND_HRR_COOKIE) && !defined(NO_WOLFSSL_SERVER)
+#endif
+
+#if defined(WOLFSSL_SEND_HRR_COOKIE)
 /* Send a cookie with the HelloRetryRequest to avoid storing state.
  *
@@ -6556,4 +7623,5 @@
     if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version))
         return BAD_FUNC_ARG;
+ #ifndef NO_WOLFSSL_SERVER
     if (ssl->options.side == WOLFSSL_CLIENT_END)
         return SIDE_ERROR;
@@ -6602,5 +7670,13 @@
     ssl->options.sendCookie = 1;
 
-    return WOLFSSL_SUCCESS;
+    ret = WOLFSSL_SUCCESS;
+#else
+    (void)secret;
+    (void)secretSz;
+
+    ret = SIDE_ERROR;
+#endif
+
+    return ret;
 }
 #endif
@@ -6619,6 +7695,4 @@
     if (ssl == NULL)
         return BAD_FUNC_ARG;
-    if (ssl->options.side == WOLFSSL_SERVER_END)
-        return SIDE_ERROR;
 
     ret = TLSX_KeyShare_Use(ssl, group, 0, NULL, NULL);
@@ -6748,5 +7822,5 @@
  *
  * ctx  The SSL/TLS CTX object.
- * returns BAD_FUNC_ARG when ctx is NULL, SIDE_ERROR when not a server and
+ * returns BAD_FUNC_ARG when ctx is NULL, SIDE_ERROR when not a client and
  * 0 on success.
  */
@@ -6767,5 +7841,5 @@
  * ssl  The SSL/TLS object.
  * returns BAD_FUNC_ARG when ssl is NULL, or not using TLS v1.3,
- * SIDE_ERROR when not a server and 0 on success.
+ * SIDE_ERROR when not a client and 0 on success.
  */
 int wolfSSL_allow_post_handshake_auth(WOLFSSL* ssl)
@@ -6790,8 +7864,11 @@
 {
     int         ret;
+#ifndef NO_WOLFSSL_SERVER
     CertReqCtx* certReqCtx;
+#endif
 
     if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version))
         return BAD_FUNC_ARG;
+#ifndef NO_WOLFSSL_SERVER
     if (ssl->options.side == WOLFSSL_CLIENT_END)
         return SIDE_ERROR;
@@ -6812,4 +7889,8 @@
     ssl->certReqCtx = certReqCtx;
 
+    ssl->msgsReceived.got_certificate = 0;
+    ssl->msgsReceived.got_certificate_verify = 0;
+    ssl->msgsReceived.got_finished = 0;
+
     ret = SendTls13CertificateRequest(ssl, &certReqCtx->ctx, certReqCtx->len);
     if (ret == WANT_WRITE)
@@ -6817,7 +7898,164 @@
     else if (ret == 0)
         ret = WOLFSSL_SUCCESS;
+#else
+    ret = SIDE_ERROR;
+#endif
+
     return ret;
 }
 #endif /* !NO_CERTS && WOLFSSL_POST_HANDSHAKE_AUTH */
+
+#if !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)
+/* Get the preferred key exchange group.
+ *
+ * ssl  The SSL/TLS object.
+ * returns BAD_FUNC_ARG when ssl is NULL or not using TLS v1.3,
+ * SIDE_ERROR when not a client, NOT_READY_ERROR when handshake not complete
+ * and group number on success.
+ */
+int wolfSSL_preferred_group(WOLFSSL* ssl)
+{
+    if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version))
+        return BAD_FUNC_ARG;
+#ifndef NO_WOLFSSL_CLIENT
+    if (ssl->options.side == WOLFSSL_SERVER_END)
+        return SIDE_ERROR;
+    if (ssl->options.handShakeState != HANDSHAKE_DONE)
+        return NOT_READY_ERROR;
+
+    /* Return supported groups only. */
+    return TLSX_SupportedCurve_Preferred(ssl, 1);
+#else
+    return SIDE_ERROR;
+#endif
+}
+#endif
+
+/* Sets the key exchange groups in rank order on a context.
+ *
+ * ctx     SSL/TLS context object.
+ * groups  Array of groups.
+ * count   Number of groups in array.
+ * returns BAD_FUNC_ARG when ctx or groups is NULL, not using TLS v1.3 or
+ * count is greater than WOLFSSL_MAX_GROUP_COUNT and WOLFSSL_SUCCESS on success.
+ */
+int wolfSSL_CTX_set_groups(WOLFSSL_CTX* ctx, int* groups, int count)
+{
+    int i;
+
+    if (ctx == NULL || groups == NULL || count > WOLFSSL_MAX_GROUP_COUNT)
+        return BAD_FUNC_ARG;
+    if (!IsAtLeastTLSv1_3(ctx->method->version))
+        return BAD_FUNC_ARG;
+
+    for (i = 0; i < count; i++)
+        ctx->group[i] = (word16)groups[i];
+    ctx->numGroups = (byte)count;
+
+    return WOLFSSL_SUCCESS;
+}
+
+/* Sets the key exchange groups in rank order.
+ *
+ * ssl     SSL/TLS object.
+ * groups  Array of groups.
+ * count   Number of groups in array.
+ * returns BAD_FUNC_ARG when ssl or groups is NULL, not using TLS v1.3 or
+ * count is greater than WOLFSSL_MAX_GROUP_COUNT and WOLFSSL_SUCCESS on success.
+ */
+int wolfSSL_set_groups(WOLFSSL* ssl, int* groups, int count)
+{
+    int i;
+
+    if (ssl == NULL || groups == NULL || count > WOLFSSL_MAX_GROUP_COUNT)
+        return BAD_FUNC_ARG;
+    if (!IsAtLeastTLSv1_3(ssl->version))
+        return BAD_FUNC_ARG;
+
+    for (i = 0; i < count; i++)
+        ssl->group[i] = (word16)groups[i];
+    ssl->numGroups = (byte)count;
+
+    return WOLFSSL_SUCCESS;
+}
+
+#ifndef NO_PSK
+void wolfSSL_CTX_set_psk_client_tls13_callback(WOLFSSL_CTX* ctx,
+                                               wc_psk_client_tls13_callback cb)
+{
+    WOLFSSL_ENTER("SSL_CTX_set_psk_client_tls13_callback");
+
+    if (ctx == NULL)
+        return;
+
+    ctx->havePSK = 1;
+    ctx->client_psk_tls13_cb = cb;
+}
+
+
+void wolfSSL_set_psk_client_tls13_callback(WOLFSSL* ssl,
+                                           wc_psk_client_tls13_callback cb)
+{
+    byte haveRSA = 1;
+    int  keySz   = 0;
+
+    WOLFSSL_ENTER("SSL_set_psk_client_tls13_callback");
+
+    if (ssl == NULL)
+        return;
+
+    ssl->options.havePSK = 1;
+    ssl->options.client_psk_tls13_cb = cb;
+
+    #ifdef NO_RSA
+        haveRSA = 0;
+    #endif
+    #ifndef NO_CERTS
+        keySz = ssl->buffers.keySz;
+    #endif
+    InitSuites(ssl->suites, ssl->version, keySz, haveRSA, TRUE,
+               ssl->options.haveDH, ssl->options.haveNTRU,
+               ssl->options.haveECDSAsig, ssl->options.haveECC,
+               ssl->options.haveStaticECC, ssl->options.side);
+}
+
+
+void wolfSSL_CTX_set_psk_server_tls13_callback(WOLFSSL_CTX* ctx,
+                                               wc_psk_server_tls13_callback cb)
+{
+    WOLFSSL_ENTER("SSL_CTX_set_psk_server_tls13_callback");
+    if (ctx == NULL)
+        return;
+    ctx->havePSK = 1;
+    ctx->server_psk_tls13_cb = cb;
+}
+
+
+void wolfSSL_set_psk_server_tls13_callback(WOLFSSL* ssl,
+                                           wc_psk_server_tls13_callback cb)
+{
+    byte haveRSA = 1;
+    int  keySz   = 0;
+
+    WOLFSSL_ENTER("SSL_set_psk_server_tls13_callback");
+    if (ssl == NULL)
+        return;
+
+    ssl->options.havePSK = 1;
+    ssl->options.server_psk_tls13_cb = cb;
+
+    #ifdef NO_RSA
+        haveRSA = 0;
+    #endif
+    #ifndef NO_CERTS
+        keySz = ssl->buffers.keySz;
+    #endif
+    InitSuites(ssl->suites, ssl->version, keySz, haveRSA, TRUE,
+               ssl->options.haveDH, ssl->options.haveNTRU,
+               ssl->options.haveECDSAsig, ssl->options.haveECC,
+               ssl->options.haveStaticECC, ssl->options.side);
+}
+#endif
+
 
 #ifndef NO_WOLFSSL_SERVER
@@ -6836,5 +8074,4 @@
 {
     word16 havePSK = 0;
-    word16 haveAnon = 0;
     WOLFSSL_ENTER("SSL_accept_TLSv13()");
 
@@ -6847,9 +8084,4 @@
 #endif
     (void)havePSK;
-
-#ifdef HAVE_ANON
-    haveAnon = ssl->options.haveAnon;
-#endif
-    (void)haveAnon;
 
     if (ssl->options.side != WOLFSSL_SERVER_END) {
@@ -6859,14 +8091,25 @@
 
 #ifndef NO_CERTS
-    /* in case used set_accept_state after init */
-    if (!havePSK && !haveAnon &&
-        (!ssl->buffers.certificate ||
-         !ssl->buffers.certificate->buffer ||
-         !ssl->buffers.key ||
-         !ssl->buffers.key->buffer)) {
-        WOLFSSL_MSG("accept error: don't have server cert and key");
-        ssl->error = NO_PRIVATE_KEY;
-        WOLFSSL_ERROR(ssl->error);
+    /* allow no private key if using PK callbacks and CB is set */
+    if (!havePSK) {
+        if (!ssl->buffers.certificate ||
+            !ssl->buffers.certificate->buffer) {
+
+            WOLFSSL_MSG("accept error: server cert required");
+            WOLFSSL_ERROR(ssl->error = NO_PRIVATE_KEY);
         return WOLFSSL_FATAL_ERROR;
+    }
+
+    #ifdef HAVE_PK_CALLBACKS
+        if (wolfSSL_CTX_IsPrivatePkSet(ssl->ctx)) {
+            WOLFSSL_MSG("Using PK for server private key");
+        }
+        else
+    #endif
+        if (!ssl->buffers.key || !ssl->buffers.key->buffer) {
+            WOLFSSL_MSG("accept error: server key required");
+            WOLFSSL_ERROR(ssl->error = NO_PRIVATE_KEY);
+            return WOLFSSL_FATAL_ERROR;
+        }
     }
 #endif
@@ -6895,18 +8138,21 @@
     switch (ssl->options.acceptState) {
 
-        case ACCEPT_BEGIN :
-            /* get response */
-            while (ssl->options.clientState < CLIENT_HELLO_COMPLETE)
+        case TLS13_ACCEPT_BEGIN :
+            /* get client_hello */
+            while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) {
                 if ((ssl->error = ProcessReply(ssl)) < 0) {
                     WOLFSSL_ERROR(ssl->error);
                     return WOLFSSL_FATAL_ERROR;
                 }
-
-            ssl->options.acceptState = ACCEPT_CLIENT_HELLO_DONE;
+            }
+
+            ssl->options.acceptState = TLS13_ACCEPT_CLIENT_HELLO_DONE;
             WOLFSSL_MSG("accept state ACCEPT_CLIENT_HELLO_DONE");
             FALL_THROUGH;
 
-        case ACCEPT_CLIENT_HELLO_DONE :
-            if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) {
+        case TLS13_ACCEPT_CLIENT_HELLO_DONE :
+#ifdef WOLFSSL_TLS13_DRAFT_18
+            if (ssl->options.serverState ==
+                                          SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
                 if ((ssl->error = SendTls13HelloRetryRequest(ssl)) != 0) {
                     WOLFSSL_ERROR(ssl->error);
@@ -6914,38 +8160,97 @@
                 }
             }
-            ssl->options.acceptState = ACCEPT_HELLO_RETRY_REQUEST_DONE;
-            WOLFSSL_MSG("accept state ACCEPT_HELLO_RETRY_REQUEST_DONE");
+
+            ssl->options.acceptState = TLS13_ACCEPT_FIRST_REPLY_DONE;
+            WOLFSSL_MSG("accept state ACCEPT_FIRST_REPLY_DONE");
             FALL_THROUGH;
 
-        case ACCEPT_HELLO_RETRY_REQUEST_DONE :
-            if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) {
-                if ( (ssl->error = ProcessReply(ssl)) < 0) {
+        case TLS13_ACCEPT_HELLO_RETRY_REQUEST_DONE :
+#else
+            if (ssl->options.serverState ==
+                                          SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
+                if ((ssl->error = SendTls13ServerHello(ssl,
+                                                   hello_retry_request)) != 0) {
                     WOLFSSL_ERROR(ssl->error);
                     return WOLFSSL_FATAL_ERROR;
                 }
             }
-            ssl->options.acceptState = ACCEPT_FIRST_REPLY_DONE;
+
+            ssl->options.acceptState = TLS13_ACCEPT_HELLO_RETRY_REQUEST_DONE;
+            WOLFSSL_MSG("accept state ACCEPT_HELLO_RETRY_REQUEST_DONE");
+            FALL_THROUGH;
+
+        case TLS13_ACCEPT_HELLO_RETRY_REQUEST_DONE :
+    #ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT
+            if (ssl->options.serverState ==
+                                          SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
+                if ((ssl->error = SendChangeCipher(ssl)) != 0) {
+                    WOLFSSL_ERROR(ssl->error);
+                    return WOLFSSL_FATAL_ERROR;
+                }
+                ssl->options.sentChangeCipher = 1;
+            }
+    #endif
+            ssl->options.acceptState = TLS13_ACCEPT_FIRST_REPLY_DONE;
             WOLFSSL_MSG("accept state ACCEPT_FIRST_REPLY_DONE");
             FALL_THROUGH;
-
-        case ACCEPT_FIRST_REPLY_DONE :
-            if ((ssl->error = SendTls13ServerHello(ssl)) != 0) {
+#endif
+
+        case TLS13_ACCEPT_FIRST_REPLY_DONE :
+            if (ssl->options.serverState ==
+                                          SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
+                ssl->options.clientState = CLIENT_HELLO_RETRY;
+                while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) {
+                    if ((ssl->error = ProcessReply(ssl)) < 0) {
+                        WOLFSSL_ERROR(ssl->error);
+                        return WOLFSSL_FATAL_ERROR;
+                    }
+                }
+            }
+
+            ssl->options.acceptState = TLS13_ACCEPT_SECOND_REPLY_DONE;
+            WOLFSSL_MSG("accept state ACCEPT_SECOND_REPLY_DONE");
+            FALL_THROUGH;
+
+        case TLS13_ACCEPT_SECOND_REPLY_DONE :
+            if ((ssl->error = SendTls13ServerHello(ssl, server_hello)) != 0) {
                 WOLFSSL_ERROR(ssl->error);
                 return WOLFSSL_FATAL_ERROR;
             }
-            ssl->options.acceptState = SERVER_HELLO_SENT;
+            ssl->options.acceptState = TLS13_SERVER_HELLO_SENT;
             WOLFSSL_MSG("accept state SERVER_HELLO_SENT");
             FALL_THROUGH;
 
-        case SERVER_HELLO_SENT :
+        case TLS13_SERVER_HELLO_SENT :
+    #if !defined(WOLFSSL_TLS13_DRAFT_18) && \
+                                         defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
+            if (!ssl->options.sentChangeCipher) {
+                if ((ssl->error = SendChangeCipher(ssl)) != 0) {
+                    WOLFSSL_ERROR(ssl->error);
+                    return WOLFSSL_FATAL_ERROR;
+                }
+                ssl->options.sentChangeCipher = 1;
+            }
+    #endif
+
+            ssl->options.acceptState = TLS13_ACCEPT_THIRD_REPLY_DONE;
+            WOLFSSL_MSG("accept state ACCEPT_THIRD_REPLY_DONE");
+            FALL_THROUGH;
+
+        case TLS13_ACCEPT_THIRD_REPLY_DONE :
+            if (!ssl->options.noPskDheKe) {
+                ssl->error = TLSX_KeyShare_DeriveSecret(ssl);
+                if (ssl->error != 0)
+                    return WOLFSSL_FATAL_ERROR;
+            }
+
             if ((ssl->error = SendTls13EncryptedExtensions(ssl)) != 0) {
                 WOLFSSL_ERROR(ssl->error);
                 return WOLFSSL_FATAL_ERROR;
             }
-            ssl->options.acceptState = SERVER_EXTENSIONS_SENT;
+            ssl->options.acceptState = TLS13_SERVER_EXTENSIONS_SENT;
             WOLFSSL_MSG("accept state SERVER_EXTENSIONS_SENT");
             FALL_THROUGH;
 
-        case SERVER_EXTENSIONS_SENT :
+        case TLS13_SERVER_EXTENSIONS_SENT :
 #ifndef NO_CERTS
             if (!ssl->options.resuming) {
@@ -6959,10 +8264,9 @@
             }
 #endif
-            ssl->options.acceptState = CERT_REQ_SENT;
+            ssl->options.acceptState = TLS13_CERT_REQ_SENT;
             WOLFSSL_MSG("accept state CERT_REQ_SENT");
             FALL_THROUGH;
 
-        case CERT_REQ_SENT :
-            ssl->options.acceptState = KEY_EXCHANGE_SENT;
+        case TLS13_CERT_REQ_SENT :
 #ifndef NO_CERTS
             if (!ssl->options.resuming && ssl->options.sendVerify) {
@@ -6973,9 +8277,9 @@
             }
 #endif
-            ssl->options.acceptState = CERT_SENT;
+            ssl->options.acceptState = TLS13_CERT_SENT;
             WOLFSSL_MSG("accept state CERT_SENT");
             FALL_THROUGH;
 
-        case CERT_SENT :
+        case TLS13_CERT_SENT :
 #ifndef NO_CERTS
             if (!ssl->options.resuming && ssl->options.sendVerify) {
@@ -6986,9 +8290,9 @@
             }
 #endif
-            ssl->options.acceptState = CERT_STATUS_SENT;
-            WOLFSSL_MSG("accept state CERT_STATUS_SENT");
+            ssl->options.acceptState = TLS13_CERT_VERIFY_SENT;
+            WOLFSSL_MSG("accept state CERT_VERIFY_SENT");
             FALL_THROUGH;
 
-        case CERT_VERIFY_SENT :
+        case TLS13_CERT_VERIFY_SENT :
             if ((ssl->error = SendTls13Finished(ssl)) != 0) {
                 WOLFSSL_ERROR(ssl->error);
@@ -6996,8 +8300,8 @@
             }
 
-            ssl->options.acceptState = ACCEPT_FINISHED_DONE;
-            WOLFSSL_MSG("accept state ACCEPT_FINISHED_DONE");
+            ssl->options.acceptState = TLS13_ACCEPT_FINISHED_SENT;
+            WOLFSSL_MSG("accept state ACCEPT_FINISHED_SENT");
 #ifdef WOLFSSL_EARLY_DATA
-            if (ssl->earlyData) {
+            if (ssl->earlyData != no_early_data) {
                 ssl->options.handShakeState = SERVER_FINISHED_COMPLETE;
                 return WOLFSSL_SUCCESS;
@@ -7006,5 +8310,5 @@
             FALL_THROUGH;
 
-        case ACCEPT_FINISHED_DONE :
+        case TLS13_ACCEPT_FINISHED_SENT :
 #ifdef HAVE_SESSION_TICKET
     #ifdef WOLFSSL_TLS13_TICKET_BEFORE_FINISHED
@@ -7018,9 +8322,9 @@
     #endif
 #endif /* HAVE_SESSION_TICKET */
-            ssl->options.acceptState = TICKET_SENT;
+            ssl->options.acceptState = TLS13_PRE_TICKET_SENT;
             WOLFSSL_MSG("accept state  TICKET_SENT");
             FALL_THROUGH;
 
-        case TICKET_SENT:
+        case TLS13_PRE_TICKET_SENT :
             while (ssl->options.clientState < CLIENT_FINISHED_COMPLETE)
                 if ( (ssl->error = ProcessReply(ssl)) < 0) {
@@ -7029,9 +8333,9 @@
                 }
 
-            ssl->options.acceptState = ACCEPT_SECOND_REPLY_DONE;
-            WOLFSSL_MSG("accept state ACCEPT_SECOND_REPLY_DONE");
+            ssl->options.acceptState = TLS13_ACCEPT_FINISHED_DONE;
+            WOLFSSL_MSG("accept state ACCEPT_FINISHED_DONE");
             FALL_THROUGH;
 
-        case ACCEPT_SECOND_REPLY_DONE :
+        case TLS13_ACCEPT_FINISHED_DONE :
 #ifdef HAVE_SESSION_TICKET
     #ifdef WOLFSSL_TLS13_TICKET_BEFORE_FINISHED
@@ -7048,9 +8352,9 @@
             }
 #endif /* HAVE_SESSION_TICKET */
-            ssl->options.acceptState = ACCEPT_THIRD_REPLY_DONE;
-            WOLFSSL_MSG("accept state ACCEPT_THIRD_REPLY_DONE");
+            ssl->options.acceptState = TLS13_TICKET_SENT;
+            WOLFSSL_MSG("accept state TICKET_SENT");
             FALL_THROUGH;
 
-        case ACCEPT_THIRD_REPLY_DONE:
+        case TLS13_TICKET_SENT :
 #ifndef NO_HANDSHAKE_DONE_CB
             if (ssl->hsDoneCb) {
@@ -7064,4 +8368,8 @@
 #endif /* NO_HANDSHAKE_DONE_CB */
 
+            if (!ssl->options.keepResources) {
+                FreeHandshakeResources(ssl);
+            }
+
             WOLFSSL_LEAVE("SSL_accept()", WOLFSSL_SUCCESS);
             return WOLFSSL_SUCCESS;
@@ -7140,11 +8448,12 @@
         return BAD_FUNC_ARG;
 
+#ifndef NO_WOLFSSL_CLIENT
     if (ssl->options.side == WOLFSSL_SERVER_END)
         return SIDE_ERROR;
 
     if (ssl->options.handShakeState == NULL_STATE) {
-        ssl->earlyData = 1;
+        ssl->earlyData = expecting_early_data;
         ret = wolfSSL_connect_TLSv13(ssl);
-        if (ret <= 0)
+        if (ret != WOLFSSL_SUCCESS)
             return WOLFSSL_FATAL_ERROR;
     }
@@ -7154,4 +8463,7 @@
             *outSz = ret;
     }
+#else
+    return SIDE_ERROR;
+#endif
 
     WOLFSSL_LEAVE("SSL_write_early_data()", ret);
@@ -7174,5 +8486,5 @@
 int wolfSSL_read_early_data(WOLFSSL* ssl, void* data, int sz, int* outSz)
 {
-    int ret;
+    int ret = 0;
 
     WOLFSSL_ENTER("wolfSSL_read_early_data()");
@@ -7184,9 +8496,10 @@
         return BAD_FUNC_ARG;
 
+#ifndef NO_WOLFSSL_SERVER
     if (ssl->options.side == WOLFSSL_CLIENT_END)
         return SIDE_ERROR;
 
     if (ssl->options.handShakeState == NULL_STATE) {
-        ssl->earlyData = 1;
+        ssl->earlyData = expecting_early_data;
         ret = wolfSSL_accept_TLSv13(ssl);
         if (ret <= 0)
@@ -7202,4 +8515,7 @@
     else
         ret = 0;
+#else
+    return SIDE_ERROR;
+#endif
 
     WOLFSSL_LEAVE("wolfSSL_read_early_data()", ret);
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/wolfio.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/wolfio.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/src/wolfio.c	(revision 372)
@@ -47,5 +47,5 @@
  * WOLFSSL_USER_IO:     Disables default Embed* callbacks and     default: off
                         allows user to define their own using
-                        wolfSSL_SetIORecv and wolfSSL_SetIOSend
+                        wolfSSL_CTX_SetIORecv and wolfSSL_CTX_SetIOSend
  * USE_WOLFSSL_IO:      Enables the wolfSSL IO functions          default: off
  * HAVE_HTTP_CLIENT:    Enables HTTP client API's                 default: off
@@ -65,5 +65,5 @@
  * send() and recv() if need be.
  */
-static INLINE int TranslateReturnCode(int old, int sd)
+static WC_INLINE int TranslateReturnCode(int old, int sd)
 {
     (void)sd;
@@ -89,5 +89,5 @@
 }
 
-static INLINE int LastError(void)
+static WC_INLINE int wolfSSL_LastError(void)
 {
 #ifdef USE_WINDOWS_API
@@ -103,4 +103,88 @@
 
 
+#ifdef OPENSSL_EXTRA
+/* Use the WOLFSSL read BIO for receiving data. This is set by the function
+ * wolfSSL_set_bio and can also be set by wolfSSL_CTX_SetIORecv.
+ *
+ * ssl  WOLFSSL struct passed in that has this function set as the receive
+ *      callback.
+ * buf  buffer to fill with data read
+ * sz   size of buf buffer
+ * ctx  a user set context
+ *
+ * returns the amount of data read or want read. See WOLFSSL_CBIO_ERR_* values.
+ */
+int BioReceive(WOLFSSL* ssl, char* buf, int sz, void* ctx)
+{
+    int recvd = WOLFSSL_CBIO_ERR_GENERAL;
+
+    WOLFSSL_ENTER("BioReceive");
+
+    if (ssl->biord == NULL) {
+        WOLFSSL_MSG("WOLFSSL biord not set");
+        return WOLFSSL_CBIO_ERR_GENERAL;
+    }
+
+    switch (ssl->biord->type) {
+        case WOLFSSL_BIO_MEMORY:
+        case WOLFSSL_BIO_BIO:
+            if (wolfSSL_BIO_ctrl_pending(ssl->biord) == 0) {
+               return WOLFSSL_CBIO_ERR_WANT_READ;
+            }
+            recvd = wolfSSL_BIO_read(ssl->biord, buf, sz);
+            if (recvd <= 0) {
+                return WOLFSSL_CBIO_ERR_GENERAL;
+            }
+            break;
+
+       default:
+            WOLFSSL_MSG("This BIO type is unknown / unsupported");
+            return WOLFSSL_CBIO_ERR_GENERAL;
+    }
+
+    (void)ctx;
+    return recvd;
+}
+
+
+/* Use the WOLFSSL write BIO for sending data. This is set by the function
+ * wolfSSL_set_bio and can also be set by wolfSSL_CTX_SetIOSend.
+ *
+ * ssl  WOLFSSL struct passed in that has this function set as the send callback.
+ * buf  buffer with data to write out
+ * sz   size of buf buffer
+ * ctx  a user set context
+ *
+ * returns the amount of data sent or want send. See WOLFSSL_CBIO_ERR_* values.
+ */
+int BioSend(WOLFSSL* ssl, char *buf, int sz, void *ctx)
+{
+    int sent = WOLFSSL_CBIO_ERR_GENERAL;
+
+    if (ssl->biowr == NULL) {
+        WOLFSSL_MSG("WOLFSSL biowr not set\n");
+        return WOLFSSL_CBIO_ERR_GENERAL;
+    }
+
+    switch (ssl->biowr->type) {
+        case WOLFSSL_BIO_MEMORY:
+        case WOLFSSL_BIO_BIO:
+            sent = wolfSSL_BIO_write(ssl->biowr, buf, sz);
+            if (sent < 0) {
+                return WOLFSSL_CBIO_ERR_GENERAL;
+            }
+            break;
+
+        default:
+            WOLFSSL_MSG("This BIO type is unknown / unsupported");
+            return WOLFSSL_CBIO_ERR_GENERAL;
+    }
+    (void)ctx;
+
+    return sent;
+}
+#endif
+
+
 #ifdef USE_WOLFSSL_IO
 
@@ -113,40 +197,13 @@
     int recvd;
 
-#ifdef WOLFSSL_DTLS
-    {
-        int dtls_timeout = wolfSSL_dtls_get_current_timeout(ssl);
-        if (wolfSSL_dtls(ssl)
-                     && !wolfSSL_get_using_nonblock(ssl)
-                     && dtls_timeout != 0) {
-            #ifdef USE_WINDOWS_API
-                DWORD timeout = dtls_timeout * 1000;
-            #else
-                struct timeval timeout;
-                XMEMSET(&timeout, 0, sizeof(timeout));
-                timeout.tv_sec = dtls_timeout;
-            #endif
-            if (setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout,
-                           sizeof(timeout)) != 0) {
-                WOLFSSL_MSG("setsockopt rcvtimeo failed");
-            }
-        }
-    }
-#endif
-
     recvd = wolfIO_Recv(sd, buf, sz, ssl->rflags);
     if (recvd < 0) {
-        int err = LastError();
+        int err = wolfSSL_LastError();
         WOLFSSL_MSG("Embed Receive error");
 
         if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
-            if (!wolfSSL_dtls(ssl) || wolfSSL_get_using_nonblock(ssl)) {
                 WOLFSSL_MSG("\tWould block");
                 return WOLFSSL_CBIO_ERR_WANT_READ;
             }
-            else {
-                WOLFSSL_MSG("\tSocket timeout");
-                return WOLFSSL_CBIO_ERR_TIMEOUT;
-            }
-        }
         else if (err == SOCKET_ECONNRESET) {
             WOLFSSL_MSG("\tConnection reset");
@@ -157,8 +214,4 @@
             return WOLFSSL_CBIO_ERR_ISR;
         }
-        else if (err == SOCKET_ECONNREFUSED) {
-            WOLFSSL_MSG("\tConnection refused");
-            return WOLFSSL_CBIO_ERR_WANT_READ;
-        }
         else if (err == SOCKET_ECONNABORTED) {
             WOLFSSL_MSG("\tConnection aborted");
@@ -188,5 +241,5 @@
     sent = wolfIO_Send(sd, buf, sz, ssl->wflags);
     if (sent < 0) {
-        int err = LastError();
+        int err = wolfSSL_LastError();
         WOLFSSL_MSG("Embed Send error");
 
@@ -263,9 +316,9 @@
 
     if (recvd < 0) {
-        err = LastError();
+        err = wolfSSL_LastError();
         WOLFSSL_MSG("Embed Receive From error");
 
         if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
-            if (wolfSSL_get_using_nonblock(ssl)) {
+            if (wolfSSL_dtls_get_using_nonblock(ssl)) {
                 WOLFSSL_MSG("\tWould block");
                 return WOLFSSL_CBIO_ERR_WANT_READ;
@@ -326,5 +379,5 @@
 
     if (sent < 0) {
-        err = LastError();
+        err = wolfSSL_LastError();
         WOLFSSL_MSG("Embed Send To error");
 
@@ -374,9 +427,9 @@
 
     if (recvd < 0) {
-        err = LastError();
+        err = wolfSSL_LastError();
         WOLFSSL_MSG("Embed Receive From error");
 
         if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
-            if (wolfSSL_get_using_nonblock(ssl)) {
+            if (wolfSSL_dtls_get_using_nonblock(ssl)) {
                 WOLFSSL_MSG("\tWould block");
                 return WOLFSSL_CBIO_ERR_WANT_READ;
@@ -626,19 +679,20 @@
     }
 
-    #ifdef _MSC_VER
-        /* 4204: non-constant aggregate initializer (nfds = sockfd + 1) */
-        #pragma warning(disable: 4204)
-    #endif
     int wolfIO_Select(SOCKET_T sockfd, int to_sec)
     {
-        fd_set fds;
-        SOCKET_T nfds = sockfd + 1;
+        fd_set rfds, wfds;
+        int nfds = 0;
         struct timeval timeout = { (to_sec > 0) ? to_sec : 0, 0};
         int ret;
 
-        FD_ZERO(&fds);
-        FD_SET(sockfd, &fds);
-
-        ret = select(nfds, &fds, &fds, NULL, &timeout);
+    #ifndef USE_WINDOWS_API
+        nfds = (int)sockfd + 1;
+    #endif
+
+        FD_ZERO(&rfds);
+        FD_SET(sockfd, &rfds);
+        wfds = rfds;
+
+        ret = select(nfds, &rfds, &wfds, NULL, &timeout);
         if (ret == 0) {
         #ifdef DEBUG_HTTP
@@ -648,6 +702,9 @@
         }
         else if (ret > 0) {
-            if (FD_ISSET(sockfd, &fds))
+            if (FD_ISSET(sockfd, &wfds)) {
+                if (!FD_ISSET(sockfd, &rfds)) {
                 return 0;
+        }
+            }
         }
         return SOCKET_ERROR_E;
@@ -934,5 +991,5 @@
 }
 
-int wolfIO_HttpProcessResponse(int sfd, const char* appStr,
+int wolfIO_HttpProcessResponse(int sfd, const char** appStrList,
     byte** respBuf, byte* httpBuf, int httpBufSz, int dynType, void* heap)
 {
@@ -1017,7 +1074,19 @@
                 case phr_have_type:
                     if (XSTRNCASECMP(start, "Content-Type:", 13) == 0) {
+                        int i;
+
                         start += 13;
                         while (*start == ' ' && *start != '\0') start++;
-                        if (XSTRNCASECMP(start, appStr, XSTRLEN(appStr)) != 0) {
+
+                        /* try and match against appStrList */
+                        i = 0;
+                        while (appStrList[i] != NULL) {
+                            if (XSTRNCASECMP(start, appStrList[i],
+                                                XSTRLEN(appStrList[i])) == 0) {
+                                break;
+                            }
+                            i++;
+                        }
+                        if (appStrList[i] == NULL) {
                             WOLFSSL_MSG("wolfIO_HttpProcessResponse appstr mismatch");
                             return -1;
@@ -1117,31 +1186,31 @@
         return 0;
 
-    XSTRNCPY((char*)buf, reqType, reqTypeLen);
-    buf += reqTypeLen;
-    XSTRNCPY((char*)buf, blankStr, blankStrLen+1);
-    buf += blankStrLen;
-    XSTRNCPY((char*)buf, path, pathLen);
-    buf += pathLen;
-    XSTRNCPY((char*)buf, http11Str, http11StrLen+1);
-    buf += http11StrLen;
+    XSTRNCPY((char*)buf, reqType, bufSize);
+    buf += reqTypeLen; bufSize -= reqTypeLen;
+    XSTRNCPY((char*)buf, blankStr, bufSize);
+    buf += blankStrLen; bufSize -= blankStrLen;
+    XSTRNCPY((char*)buf, path, bufSize);
+    buf += pathLen; bufSize -= pathLen;
+    XSTRNCPY((char*)buf, http11Str, bufSize);
+    buf += http11StrLen; bufSize -= http11StrLen;
     if (domainNameLen > 0) {
-        XSTRNCPY((char*)buf, hostStr, hostStrLen+1);
-        buf += hostStrLen;
-        XSTRNCPY((char*)buf, domainName, domainNameLen);
-        buf += domainNameLen;
+        XSTRNCPY((char*)buf, hostStr, bufSize);
+        buf += hostStrLen; bufSize -= hostStrLen;
+        XSTRNCPY((char*)buf, domainName, bufSize);
+        buf += domainNameLen; bufSize -= domainNameLen;
     }
     if (reqSz > 0 && reqSzStrLen > 0) {
-        XSTRNCPY((char*)buf, contentLenStr, contentLenStrLen+1);
-        buf += contentLenStrLen;
-        XSTRNCPY((char*)buf, reqSzStr, reqSzStrLen);
-        buf += reqSzStrLen;
+        XSTRNCPY((char*)buf, contentLenStr, bufSize);
+        buf += contentLenStrLen; bufSize -= contentLenStrLen;
+        XSTRNCPY((char*)buf, reqSzStr, bufSize);
+        buf += reqSzStrLen; bufSize -= reqSzStrLen;
     }
     if (contentTypeLen > 0) {
-        XSTRNCPY((char*)buf, contentTypeStr, contentTypeStrLen+1);
-        buf += contentTypeStrLen;
-        XSTRNCPY((char*)buf, contentType, contentTypeLen);
-        buf += contentTypeLen;
-    }
-    XSTRNCPY((char*)buf, doubleCrLfStr, doubleCrLfStrLen+1);
+        XSTRNCPY((char*)buf, contentTypeStr, bufSize);
+        buf += contentTypeStrLen; bufSize -= contentTypeStrLen;
+        XSTRNCPY((char*)buf, contentType, bufSize);
+        buf += contentTypeLen; bufSize -= contentTypeLen;
+    }
+    XSTRNCPY((char*)buf, doubleCrLfStr, bufSize);
     buf += doubleCrLfStrLen;
 
@@ -1169,5 +1238,10 @@
                                        byte* httpBuf, int httpBufSz, void* heap)
 {
-    return wolfIO_HttpProcessResponse(sfd, "application/ocsp-response",
+    const char* appStrList[] = {
+        "application/ocsp-response",
+        NULL
+    };
+
+    return wolfIO_HttpProcessResponse(sfd, appStrList,
         respBuf, httpBuf, httpBufSz, DYNAMIC_TYPE_OCSP, heap);
 }
@@ -1223,5 +1297,5 @@
 
             ret = wolfIO_TcpConnect(&sfd, domainName, port, io_timeout_sec);
-            if ((ret != 0) || (sfd < 0)) {
+            if ((ret != 0) || ((int)sfd < 0)) {
                 WOLFSSL_MSG("OCSP Responder connection failed");
             }
@@ -1239,5 +1313,5 @@
             }
 
-            close(sfd);
+            CloseSocket(sfd);
             XFREE(httpBuf, ctx, DYNAMIC_TYPE_OCSP);
         }
@@ -1278,5 +1352,11 @@
     byte *respBuf = NULL;
 
-    result = wolfIO_HttpProcessResponse(sfd, "application/pkix-crl",
+    const char* appStrList[] = {
+        "application/pkix-crl",
+        "application/x-pkcs7-crl",
+        NULL
+    };
+
+    result = wolfIO_HttpProcessResponse(sfd, appStrList,
         &respBuf, httpBuf, httpBufSz, DYNAMIC_TYPE_CRL, crl->heap);
     if (result >= 0) {
@@ -1334,5 +1414,5 @@
             }
 
-            close(sfd);
+            CloseSocket(sfd);
             XFREE(httpBuf, crl->heap, DYNAMIC_TYPE_CRL);
         }
@@ -1351,13 +1431,23 @@
 
 
-WOLFSSL_API void wolfSSL_SetIORecv(WOLFSSL_CTX *ctx, CallbackIORecv CBIORecv)
-{
+WOLFSSL_API void wolfSSL_CTX_SetIORecv(WOLFSSL_CTX *ctx, CallbackIORecv CBIORecv)
+{
+    if (ctx != NULL) {
     ctx->CBIORecv = CBIORecv;
-}
-
-
-WOLFSSL_API void wolfSSL_SetIOSend(WOLFSSL_CTX *ctx, CallbackIOSend CBIOSend)
-{
+        #ifdef OPENSSL_EXTRA
+        ctx->cbioFlag |= WOLFSSL_CBIO_RECV;
+        #endif
+    }
+}
+
+
+WOLFSSL_API void wolfSSL_CTX_SetIOSend(WOLFSSL_CTX *ctx, CallbackIOSend CBIOSend)
+{
+    if (ctx != NULL) {
     ctx->CBIOSend = CBIOSend;
+        #ifdef OPENSSL_EXTRA
+        ctx->cbioFlag |= WOLFSSL_CBIO_SEND;
+        #endif
+    }
 }
 
@@ -1611,5 +1701,5 @@
         int dtls_timeout = wolfSSL_dtls_get_current_timeout(ssl);
         if (wolfSSL_dtls(ssl)
-                     && !wolfSSL_get_using_nonblock(ssl)
+                     && !wolfSSL_dtls_get_using_nonblock(ssl)
                      && dtls_timeout != 0) {
             /* needs timeout in milliseconds */
@@ -1628,5 +1718,5 @@
         if (err == NET_ERR_RX || err == NET_SOCK_ERR_RX_Q_EMPTY ||
             err == NET_ERR_FAULT_LOCK_ACQUIRE) {
-            if (!wolfSSL_dtls(ssl) || wolfSSL_get_using_nonblock(ssl)) {
+            if (!wolfSSL_dtls(ssl) || wolfSSL_dtls_get_using_nonblock(ssl)) {
                 WOLFSSL_MSG("\tWould block");
                 return WOLFSSL_CBIO_ERR_WANT_READ;
@@ -1668,5 +1758,5 @@
         dtls_timeout = 0;
 
-    if (!wolfSSL_get_using_nonblock(ssl)) {
+    if (!wolfSSL_dtls_get_using_nonblock(ssl)) {
         /* needs timeout in milliseconds */
         NetSock_CfgTimeoutRxQ_Set(sd, dtls_timeout * 1000, &err);
@@ -1683,5 +1773,5 @@
         if (err == NET_ERR_RX || err == NET_SOCK_ERR_RX_Q_EMPTY ||
             err == NET_ERR_FAULT_LOCK_ACQUIRE) {
-            if (wolfSSL_get_using_nonblock(ssl)) {
+            if (wolfSSL_dtls_get_using_nonblock(ssl)) {
                 WOLFSSL_MSG("\tWould block");
                 return WOLFSSL_CBIO_ERR_WANT_READ;
@@ -1773,3 +1863,308 @@
 #endif /* MICRIUM */
 
+#if defined(WOLFSSL_APACHE_MYNEWT) && !defined(WOLFSSL_LWIP)
+
+#include <os/os_error.h>
+#include <os/os_mbuf.h>
+#include <os/os_mempool.h>
+
+#define MB_NAME "wolfssl_mb"
+
+typedef struct Mynewt_Ctx {
+        struct mn_socket *mnSocket;          /* send/recv socket handler */
+        struct mn_sockaddr_in mnSockAddrIn;  /* socket address */
+        struct os_mbuf *mnPacket;            /* incoming packet handle
+                                                for short reads */
+        int reading;                         /* reading flag */
+
+        /* private */
+        void *mnMemBuffer;                   /* memory buffer for mempool */
+        struct os_mempool mnMempool;         /* mempool */
+        struct os_mbuf_pool mnMbufpool;      /* mbuf pool */
+} Mynewt_Ctx;
+
+void mynewt_ctx_clear(void *ctx) {
+    Mynewt_Ctx *mynewt_ctx = (Mynewt_Ctx*)ctx;
+    if(!mynewt_ctx) return;
+
+    if(mynewt_ctx->mnPacket) {
+        os_mbuf_free_chain(mynewt_ctx->mnPacket);
+        mynewt_ctx->mnPacket = NULL;
+    }
+    os_mempool_clear(&mynewt_ctx->mnMempool);
+    XFREE(mynewt_ctx->mnMemBuffer, 0, 0);
+    XFREE(mynewt_ctx, 0, 0);
+}
+
+/* return Mynewt_Ctx instance */
+void* mynewt_ctx_new() {
+    int rc = 0;
+    Mynewt_Ctx *mynewt_ctx = NULL;
+    int mem_buf_count = MYNEWT_VAL(WOLFSSL_MNSOCK_MEM_BUF_COUNT);
+    int mem_buf_size = MYNEWT_VAL(WOLFSSL_MNSOCK_MEM_BUF_SIZE);
+    int mempool_bytes = OS_MEMPOOL_BYTES(mem_buf_count, mem_buf_size);
+
+    mynewt_ctx = (Mynewt_Ctx *)XMALLOC(sizeof(struct Mynewt_Ctx),
+                                       NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if(!mynewt_ctx) return NULL;
+
+    XMEMSET(mynewt_ctx, 0, sizeof(Mynewt_Ctx));
+    mynewt_ctx->mnMemBuffer = XMALLOC(mempool_bytes, 0, 0);
+    if(!mynewt_ctx->mnMemBuffer) {
+        mynewt_ctx_clear((void*)mynewt_ctx);
+        return NULL;
+    }
+
+    rc = os_mempool_init(&mynewt_ctx->mnMempool,
+                         mem_buf_count, mem_buf_size,
+                         mynewt_ctx->mnMemBuffer, MB_NAME);
+    if(rc != 0) {
+        mynewt_ctx_clear((void*)mynewt_ctx);
+        return NULL;
+    }
+    rc = os_mbuf_pool_init(&mynewt_ctx->mnMbufpool, &mynewt_ctx->mnMempool,
+                           mem_buf_count, mem_buf_size);
+    if(rc != 0) {
+        mynewt_ctx_clear((void*)mynewt_ctx);
+        return NULL;
+    }
+
+    return mynewt_ctx;
+}
+
+static void mynewt_sock_writable(void *arg, int err);
+static void mynewt_sock_readable(void *arg, int err);
+static const union mn_socket_cb mynewt_sock_cbs = {
+    .socket.writable = mynewt_sock_writable,
+    .socket.readable = mynewt_sock_readable,
+};
+static void mynewt_sock_writable(void *arg, int err)
+{
+    /* do nothing */
+}
+static void mynewt_sock_readable(void *arg, int err)
+{
+    Mynewt_Ctx *mynewt_ctx = (Mynewt_Ctx *)arg;
+    if (err && mynewt_ctx->reading) {
+        mynewt_ctx->reading = 0;
+    }
+}
+
+/* The Mynewt receive callback
+ *  return :  bytes read, or error
+ */
+int Mynewt_Receive(WOLFSSL *ssl, char *buf, int sz, void *ctx)
+{
+    Mynewt_Ctx *mynewt_ctx = (Mynewt_Ctx*)ctx;
+    int rc = 0;
+    struct mn_sockaddr_in from;
+    struct os_mbuf *m;
+    int read_sz = 0;
+    uint16_t total;
+
+    if (mynewt_ctx == NULL || mynewt_ctx->mnSocket == NULL) {
+        WOLFSSL_MSG("Mynewt Recv NULL parameters");
+        return WOLFSSL_CBIO_ERR_GENERAL;
+    }
+
+    if(mynewt_ctx->mnPacket == NULL) {
+        mynewt_ctx->mnPacket = os_mbuf_get_pkthdr(&mynewt_ctx->mnMbufpool, 0);
+        if(mynewt_ctx->mnPacket == NULL) {
+            return MEMORY_E;
+        }
+
+        mynewt_ctx->reading = 1;
+        while(mynewt_ctx->reading && rc == 0) {
+            rc = mn_recvfrom(mynewt_ctx->mnSocket, &m, (struct mn_sockaddr *) &from);
+            if(rc == MN_ECONNABORTED) {
+                rc = 0;
+                mynewt_ctx->reading = 0;
+                break;
+            }
+            if (!(rc == 0 || rc == MN_EAGAIN)) {
+                WOLFSSL_MSG("Mynewt Recv receive error");
+                mynewt_ctx->reading = 0;
+                break;
+            }
+            if(rc == 0) {
+                int len = OS_MBUF_PKTLEN(m);
+                if(len == 0) {
+                    break;
+                }
+                rc = os_mbuf_appendfrom(mynewt_ctx->mnPacket, m, 0, len);
+                if(rc != 0) {
+                    WOLFSSL_MSG("Mynewt Recv os_mbuf_appendfrom error");
+                    break;
+                }
+                os_mbuf_free_chain(m);
+                m = NULL;
+            } else if(rc == MN_EAGAIN) {
+                /* continue to until reading all of packet data. */
+                rc = 0;
+                break;
+            }
+        }
+        if(rc != 0) {
+            mynewt_ctx->reading = 0;
+            os_mbuf_free_chain(mynewt_ctx->mnPacket);
+            mynewt_ctx->mnPacket = NULL;
+            return rc;
+        }
+    }
+
+    if(mynewt_ctx->mnPacket) {
+        total = OS_MBUF_PKTLEN(mynewt_ctx->mnPacket);
+        read_sz = (total >= sz)? sz : total;
+
+        os_mbuf_copydata(mynewt_ctx->mnPacket, 0, read_sz, (void*)buf);
+        os_mbuf_adj(mynewt_ctx->mnPacket, read_sz);
+
+        if (read_sz == total) {
+            WOLFSSL_MSG("Mynewt Recv Drained packet");
+            os_mbuf_free_chain(mynewt_ctx->mnPacket);
+            mynewt_ctx->mnPacket = NULL;
+        }
+    }
+
+    return read_sz;
+}
+
+/* The Mynewt send callback
+ *  return : bytes sent, or error
+ */
+int Mynewt_Send(WOLFSSL* ssl, char *buf, int sz, void *ctx)
+{
+    Mynewt_Ctx *mynewt_ctx = (Mynewt_Ctx*)ctx;
+    int rc = 0;
+    struct os_mbuf *m = NULL;
+    int write_sz = 0;
+    m = os_msys_get_pkthdr(sz, 0);
+    if (!m) {
+        WOLFSSL_MSG("Mynewt Send os_msys_get_pkthdr error");
+        return WOLFSSL_CBIO_ERR_GENERAL;
+    }
+    rc = os_mbuf_copyinto(m, 0, buf, sz);
+    if (rc != 0) {
+        WOLFSSL_MSG("Mynewt Send os_mbuf_copyinto error");
+        os_mbuf_free_chain(m);
+        return rc;
+    }
+    rc = mn_sendto(mynewt_ctx->mnSocket, m, (struct mn_sockaddr *)&mynewt_ctx->mnSockAddrIn);
+    if(rc != 0) {
+        WOLFSSL_MSG("Mynewt Send mn_sendto error");
+        os_mbuf_free_chain(m);
+        return rc;
+    }
+    write_sz = sz;
+    return write_sz;
+}
+
+/* like set_fd, but for default NetX context */
+void wolfSSL_SetIO_Mynewt(WOLFSSL* ssl, struct mn_socket* mnSocket, struct mn_sockaddr_in* mnSockAddrIn)
+{
+    if (ssl && ssl->mnCtx) {
+        Mynewt_Ctx *mynewt_ctx = (Mynewt_Ctx *)ssl->mnCtx;
+        mynewt_ctx->mnSocket = mnSocket;
+        memcpy(&mynewt_ctx->mnSockAddrIn, mnSockAddrIn, sizeof(struct mn_sockaddr_in));
+        mn_socket_set_cbs(mynewt_ctx->mnSocket, mnSocket, &mynewt_sock_cbs);
+    }
+}
+
+#endif /* defined(WOLFSSL_APACHE_MYNEWT) && !defined(WOLFSSL_LWIP) */
+
+#ifdef WOLFSSL_UIP
+#include <uip.h>
+#include <stdio.h>
+
+/* uIP TCP/IP port, using the native tcp/udp socket api.
+ * TCP and UDP are currently supported with the callbacks below.
+ *
+ */
+/* The uIP tcp send callback
+ * return : bytes sent, or error
+ */
+int uIPSend(WOLFSSL* ssl, char* buf, int sz, void* _ctx)
+{
+    uip_wolfssl_ctx *ctx = (struct uip_wolfssl_ctx *)_ctx;
+    int ret;
+    unsigned int max_sendlen;
+    int total_written = 0;
+    (void)ssl;
+    do {
+        unsigned int bytes_left = sz - total_written;
+        max_sendlen = tcp_socket_max_sendlen(&ctx->conn.tcp);
+        if (bytes_left > max_sendlen) {
+            printf("Send limited by buffer\r\n");
+            bytes_left = max_sendlen;
+        }
+        if (bytes_left == 0) {
+            printf("Buffer full!\r\n");
+            break;
+        }
+        ret = tcp_socket_send(&ctx->conn.tcp, (unsigned char *)buf + total_written, bytes_left);
+        if (ret <= 0)
+            break;
+        total_written += ret;
+    } while(total_written < sz);
+    return total_written;
+}
+
+int uIPSendTo(WOLFSSL* ssl, char* buf, int sz, void* _ctx)
+{
+    uip_wolfssl_ctx *ctx = (struct uip_wolfssl_ctx *)_ctx;
+    int ret = 0;
+    (void)ssl;
+    ret = udp_socket_sendto(&ctx->conn.udp, (unsigned char *)buf, sz, &ctx->peer_addr, ctx->peer_port );
+    if (ret <= 0)
+        return 0;
+    return ret;
+}
+
+/* The uIP uTCP/IP receive callback
+ *  return : nb bytes read, or error
+ */
+int uIPReceive(WOLFSSL *ssl, char *buf, int sz, void *_ctx)
+{
+    uip_wolfssl_ctx *ctx = (uip_wolfssl_ctx *)_ctx;
+    if (!ctx || !ctx->ssl_rx_databuf)
+        return -1;
+    (void)ssl;
+    if (ctx->ssl_rb_len > 0) {
+        if (sz > ctx->ssl_rb_len - ctx->ssl_rb_off)
+            sz = ctx->ssl_rb_len - ctx->ssl_rb_off;
+        XMEMCPY(buf, ctx->ssl_rx_databuf + ctx->ssl_rb_off, sz);
+        ctx->ssl_rb_off += sz;
+        if (ctx->ssl_rb_off >= ctx->ssl_rb_len) {
+            ctx->ssl_rb_len = 0;
+            ctx->ssl_rb_off = 0;
+        }
+        return sz;
+    } else {
+        return WOLFSSL_CBIO_ERR_WANT_READ;
+    }
+}
+
+/* uIP DTLS Generate Cookie callback
+ *  return : number of bytes copied into buf, or error
+ */
+int uIPGenerateCookie(WOLFSSL* ssl, byte *buf, int sz, void *_ctx)
+{
+    uip_wolfssl_ctx *ctx = (uip_wolfssl_ctx *)ctx;
+    byte token[32];
+    byte digest[WC_SHA_DIGEST_SIZE];
+    int  ret = 0;
+    XMEMSET(token, 0, sizeof(token));
+    XMEMCPY(token, &ctx->peer_addr, sizeof(uip_ipaddr_t));
+    XMEMCPY(token + sizeof(uip_ipaddr_t), &ctx->peer_port, sizeof(word16));
+    ret = wc_ShaHash(token, sizeof(uip_ipaddr_t) + sizeof(word16), digest);
+    if (ret != 0)
+        return ret;
+    if (sz > WC_SHA_DIGEST_SIZE)
+        sz = WC_SHA_DIGEST_SIZE;
+    XMEMCPY(buf, digest, sz);
+    return sz;
+}
+
+#endif /* WOLFSSL_UIP */
+
 #endif /* WOLFCRYPT_ONLY */
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/user_settings.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/user_settings.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/user_settings.h	(revision 372)
@@ -1,5 +1,5 @@
 //#define DEBUG_WOLFSSL
 
-//#define HAVE_LIBZ	X^bNª½­Kv
+//#define HAVE_LIBZ	スタックが多く必要
 #define HAVE_ECC
 #define HAVE_AESGCM
@@ -15,4 +15,6 @@
 #define WOLFSSL_SHA512
 #define WOLFSSL_SMALL_STACK
+// curlで使用している
+#define WOLFSSL_ALLOW_TLSV10
 
 #define WC_RSA_BLINDING
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/aes.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/aes.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/aes.c	(revision 372)
@@ -28,11 +28,32 @@
 #include <wolfssl/wolfcrypt/error-crypt.h>
 
-#ifndef NO_AES
+#if !defined(NO_AES)
+
+/* Tip: Locate the software cipher modes by searching for "Software AES" */
+
+#if defined(HAVE_FIPS) && \
+    defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+
+    /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+    #define FIPS_NO_WRAPPERS
+
+    #ifdef USE_WINDOWS_API
+        #pragma code_seg(".fipsA$g")
+        #pragma const_seg(".fipsB$g")
+    #endif
+#endif
+
 #include <wolfssl/wolfcrypt/aes.h>
 #include <wolfssl/wolfcrypt/cpuid.h>
 
+#ifdef WOLF_CRYPTO_DEV
+    #include <wolfssl/wolfcrypt/cryptodev.h>
+#endif
+
 
 /* fips wrapper calls, user can call direct */
-#ifdef HAVE_FIPS
+#if defined(HAVE_FIPS) && \
+    (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))
+
     int wc_AesSetKey(Aes* aes, const byte* key, word32 len, const byte* iv,
                               int dir)
@@ -173,8 +194,9 @@
 
     /* AES-CCM */
-    #ifdef HAVE_AESCCM
-        void wc_AesCcmSetKey(Aes* aes, const byte* key, word32 keySz)
+    #if defined(HAVE_AESCCM) && \
+        defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+        int wc_AesCcmSetKey(Aes* aes, const byte* key, word32 keySz)
         {
-            AesCcmSetKey(aes, key, keySz);
+            return AesCcmSetKey(aes, key, keySz);
         }
         int wc_AesCcmEncrypt(Aes* aes, byte* out, const byte* in, word32 inSz,
@@ -210,11 +232,14 @@
             }
         #endif /* HAVE_AES_DECRYPT */
-    #endif /* HAVE_AESCCM */
+    #endif /* HAVE_AESCCM && HAVE_FIPS_VERSION 2 */
 
     int  wc_AesInit(Aes* aes, void* h, int i)
     {
-        (void)aes;
+        if (aes == NULL)
+            return BAD_FUNC_ARG;
+
         (void)h;
         (void)i;
+
         /* FIPS doesn't support:
             return AesInit(aes, h, i); */
@@ -228,5 +253,5 @@
     }
 
-#else /* HAVE_FIPS */
+#else /* else build without fips, or for FIPS v2 */
 
 
@@ -244,5 +269,11 @@
 #endif
 
-#ifndef WOLFSSL_ARMASM
+#if !defined(WOLFSSL_ARMASM)
+
+#ifdef WOLFSSL_IMX6_CAAM_BLOB
+    /* case of possibly not using hardware acceleration for AES but using key
+       blobs */
+    #include <wolfssl/wolfcrypt/port/caam/wolfcaam.h>
+#endif
 
 #ifdef DEBUG_AESNI
@@ -258,10 +289,8 @@
 /* Define AES implementation includes and functions */
 #if defined(STM32_CRYPTO)
-     /* STM32F2/F4 hardware AES support for CBC, CTR modes */
-
-    /* CRYPT_AES_GCM starts the IV with 2 */
-    #define STM32_GCM_IV_START 2
+     /* STM32F2/F4/F7/L4 hardware AES support for ECB, CBC, CTR and GCM modes */
 
 #if defined(WOLFSSL_AES_DIRECT) || defined(HAVE_AESGCM) || defined(HAVE_AESCCM)
+
     static int wc_AesEncrypt(Aes* aes, const byte* inBlock, byte* outBlock)
     {
@@ -269,87 +298,48 @@
     #ifdef WOLFSSL_STM32_CUBEMX
         CRYP_HandleTypeDef hcryp;
-
-        XMEMSET(&hcryp, 0, sizeof(CRYP_HandleTypeDef));
-        switch(aes->rounds) {
-            case 10: /* 128-bit key */
-                hcryp.Init.KeySize = CRYP_KEYSIZE_128B;
-                break;
-            case 12: /* 192-bit key */
-                hcryp.Init.KeySize = CRYP_KEYSIZE_192B;
-                break;
-            case 14: /* 256-bit key */
-                hcryp.Init.KeySize = CRYP_KEYSIZE_256B;
-                break;
-            default:
-                break;
-        }
-        hcryp.Instance = CRYP;
-        hcryp.Init.DataType = CRYP_DATATYPE_8B;
-        hcryp.Init.pKey = (uint8_t*)aes->key;
-
+    #else
+        CRYP_InitTypeDef cryptInit;
+        CRYP_KeyInitTypeDef keyInit;
+    #endif
+
+    #ifdef WOLFSSL_STM32_CUBEMX
+        ret = wc_Stm32_Aes_Init(aes, &hcryp);
+        if (ret != 0)
+            return ret;
+
+    #ifdef STM32_CRYPTO_AES_ONLY
+        hcryp.Init.OperatingMode = CRYP_ALGOMODE_ENCRYPT;
+        hcryp.Init.ChainingMode  = CRYP_CHAINMODE_AES_ECB;
+        hcryp.Init.KeyWriteFlag  = CRYP_KEY_WRITE_ENABLE;
+    #endif
         HAL_CRYP_Init(&hcryp);
 
-        if (HAL_CRYP_AESECB_Encrypt(&hcryp, (uint8_t*)inBlock, AES_BLOCK_SIZE,
-                                    outBlock, STM32_HAL_TIMEOUT) != HAL_OK) {
+    #ifdef STM32_CRYPTO_AES_ONLY
+        ret = HAL_CRYPEx_AES(&hcryp, (uint8_t*)inBlock, AES_BLOCK_SIZE,
+            outBlock, STM32_HAL_TIMEOUT);
+    #else
+        ret = HAL_CRYP_AESECB_Encrypt(&hcryp, (uint8_t*)inBlock, AES_BLOCK_SIZE,
+            outBlock, STM32_HAL_TIMEOUT);
+    #endif
+        if (ret != HAL_OK) {
             ret = WC_TIMEOUT_E;
         }
-
         HAL_CRYP_DeInit(&hcryp);
-    #else
-        word32 *enc_key;
-        CRYP_InitTypeDef AES_CRYP_InitStructure;
-        CRYP_KeyInitTypeDef AES_CRYP_KeyInitStructure;
-
-        enc_key = aes->key;
-
-        /* crypto structure initialization */
-        CRYP_KeyStructInit(&AES_CRYP_KeyInitStructure);
-        CRYP_StructInit(&AES_CRYP_InitStructure);
+
+    #else /* STD_PERI_LIB */
+        ret = wc_Stm32_Aes_Init(aes, &cryptInit, &keyInit);
+        if (ret != 0)
+            return ret;
 
         /* reset registers to their default values */
         CRYP_DeInit();
 
-        /* load key into correct registers */
-        switch (aes->rounds) {
-            case 10: /* 128-bit key */
-                AES_CRYP_InitStructure.CRYP_KeySize = CRYP_KeySize_128b;
-                AES_CRYP_KeyInitStructure.CRYP_Key2Left  = enc_key[0];
-                AES_CRYP_KeyInitStructure.CRYP_Key2Right = enc_key[1];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Left  = enc_key[2];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Right = enc_key[3];
-                break;
-
-            case 12: /* 192-bit key */
-                AES_CRYP_InitStructure.CRYP_KeySize = CRYP_KeySize_192b;
-                AES_CRYP_KeyInitStructure.CRYP_Key1Left  = enc_key[0];
-                AES_CRYP_KeyInitStructure.CRYP_Key1Right = enc_key[1];
-                AES_CRYP_KeyInitStructure.CRYP_Key2Left  = enc_key[2];
-                AES_CRYP_KeyInitStructure.CRYP_Key2Right = enc_key[3];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Left  = enc_key[4];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Right = enc_key[5];
-                break;
-
-            case 14: /* 256-bit key */
-                AES_CRYP_InitStructure.CRYP_KeySize = CRYP_KeySize_256b;
-                AES_CRYP_KeyInitStructure.CRYP_Key0Left  = enc_key[0];
-                AES_CRYP_KeyInitStructure.CRYP_Key0Right = enc_key[1];
-                AES_CRYP_KeyInitStructure.CRYP_Key1Left  = enc_key[2];
-                AES_CRYP_KeyInitStructure.CRYP_Key1Right = enc_key[3];
-                AES_CRYP_KeyInitStructure.CRYP_Key2Left  = enc_key[4];
-                AES_CRYP_KeyInitStructure.CRYP_Key2Right = enc_key[5];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Left  = enc_key[6];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Right = enc_key[7];
-                break;
-
-            default:
-                break;
-        }
-        CRYP_KeyInit(&AES_CRYP_KeyInitStructure);
-
-        /* set direction, mode, and datatype */
-        AES_CRYP_InitStructure.CRYP_AlgoDir  = CRYP_AlgoDir_Encrypt;
-        AES_CRYP_InitStructure.CRYP_AlgoMode = CRYP_AlgoMode_AES_ECB;
-        AES_CRYP_InitStructure.CRYP_DataType = CRYP_DataType_8b;
-        CRYP_Init(&AES_CRYP_InitStructure);
+        /* setup key */
+        CRYP_KeyInit(&keyInit);
+
+        /* set direction and mode */
+        cryptInit.CRYP_AlgoDir  = CRYP_AlgoDir_Encrypt;
+        cryptInit.CRYP_AlgoMode = CRYP_AlgoMode_AES_ECB;
+        CRYP_Init(&cryptInit);
 
         /* enable crypto processor */
@@ -386,99 +376,57 @@
     #ifdef WOLFSSL_STM32_CUBEMX
         CRYP_HandleTypeDef hcryp;
-
-        XMEMSET(&hcryp, 0, sizeof(CRYP_HandleTypeDef));
-        switch(aes->rounds) {
-            case 10: /* 128-bit key */
-                hcryp.Init.KeySize = CRYP_KEYSIZE_128B;
-                break;
-            case 12: /* 192-bit key */
-                hcryp.Init.KeySize = CRYP_KEYSIZE_192B;
-                break;
-            case 14: /* 256-bit key */
-                hcryp.Init.KeySize = CRYP_KEYSIZE_256B;
-                break;
-            default:
-                break;
-        }
-        hcryp.Instance = CRYP;
-        hcryp.Init.DataType = CRYP_DATATYPE_8B;
-        hcryp.Init.pKey = (uint8_t*)aes->key;
-
+    #else
+        CRYP_InitTypeDef cryptInit;
+        CRYP_KeyInitTypeDef keyInit;
+    #endif
+
+    #ifdef WOLFSSL_STM32_CUBEMX
+        ret = wc_Stm32_Aes_Init(aes, &hcryp);
+        if (ret != 0)
+            return ret;
+
+    #ifdef STM32_CRYPTO_AES_ONLY
+        hcryp.Init.OperatingMode = CRYP_ALGOMODE_DECRYPT;
+        hcryp.Init.ChainingMode  = CRYP_CHAINMODE_AES_ECB;
+        hcryp.Init.KeyWriteFlag  = CRYP_KEY_WRITE_ENABLE;
+    #endif
         HAL_CRYP_Init(&hcryp);
 
-        if (HAL_CRYP_AESECB_Decrypt(&hcryp, (uint8_t*)inBlock, AES_BLOCK_SIZE,
-                                       outBlock, STM32_HAL_TIMEOUT) != HAL_OK) {
+    #ifdef STM32_CRYPTO_AES_ONLY
+        ret = HAL_CRYPEx_AES(&hcryp, (uint8_t*)inBlock, AES_BLOCK_SIZE,
+            outBlock, STM32_HAL_TIMEOUT);
+    #else
+        ret = HAL_CRYP_AESECB_Decrypt(&hcryp, (uint8_t*)inBlock, AES_BLOCK_SIZE,
+            outBlock, STM32_HAL_TIMEOUT)
+    #endif
+        if (ret != HAL_OK) {
             ret = WC_TIMEOUT_E;
         }
-
         HAL_CRYP_DeInit(&hcryp);
-    #else
-        word32 *enc_key;
-        CRYP_InitTypeDef AES_CRYP_InitStructure;
-        CRYP_KeyInitTypeDef AES_CRYP_KeyInitStructure;
-
-        enc_key = aes->key;
-
-        /* crypto structure initialization */
-        CRYP_KeyStructInit(&AES_CRYP_KeyInitStructure);
-        CRYP_StructInit(&AES_CRYP_InitStructure);
+
+    #else /* STD_PERI_LIB */
+        ret = wc_Stm32_Aes_Init(aes, &cryptInit, &keyInit);
+        if (ret != 0)
+            return ret;
 
         /* reset registers to their default values */
         CRYP_DeInit();
 
-        /* load key into correct registers */
-        switch (aes->rounds) {
-            case 10: /* 128-bit key */
-                AES_CRYP_InitStructure.CRYP_KeySize = CRYP_KeySize_128b;
-                AES_CRYP_KeyInitStructure.CRYP_Key2Left  = enc_key[0];
-                AES_CRYP_KeyInitStructure.CRYP_Key2Right = enc_key[1];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Left  = enc_key[2];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Right = enc_key[3];
-                break;
-
-            case 12: /* 192-bit key */
-                AES_CRYP_InitStructure.CRYP_KeySize = CRYP_KeySize_192b;
-                AES_CRYP_KeyInitStructure.CRYP_Key1Left  = enc_key[0];
-                AES_CRYP_KeyInitStructure.CRYP_Key1Right = enc_key[1];
-                AES_CRYP_KeyInitStructure.CRYP_Key2Left  = enc_key[2];
-                AES_CRYP_KeyInitStructure.CRYP_Key2Right = enc_key[3];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Left  = enc_key[4];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Right = enc_key[5];
-                break;
-
-            case 14: /* 256-bit key */
-                AES_CRYP_InitStructure.CRYP_KeySize = CRYP_KeySize_256b;
-                AES_CRYP_KeyInitStructure.CRYP_Key0Left  = enc_key[0];
-                AES_CRYP_KeyInitStructure.CRYP_Key0Right = enc_key[1];
-                AES_CRYP_KeyInitStructure.CRYP_Key1Left  = enc_key[2];
-                AES_CRYP_KeyInitStructure.CRYP_Key1Right = enc_key[3];
-                AES_CRYP_KeyInitStructure.CRYP_Key2Left  = enc_key[4];
-                AES_CRYP_KeyInitStructure.CRYP_Key2Right = enc_key[5];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Left  = enc_key[6];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Right = enc_key[7];
-                break;
-
-            default:
-                break;
-        }
-        CRYP_KeyInit(&AES_CRYP_KeyInitStructure);
-
-        /* set direction, key, and datatype */
-        AES_CRYP_InitStructure.CRYP_AlgoDir  = CRYP_AlgoDir_Decrypt;
-        AES_CRYP_InitStructure.CRYP_AlgoMode = CRYP_AlgoMode_AES_Key;
-        AES_CRYP_InitStructure.CRYP_DataType = CRYP_DataType_8b;
-        CRYP_Init(&AES_CRYP_InitStructure);
+        /* set direction and key */
+        CRYP_KeyInit(&keyInit);
+        cryptInit.CRYP_AlgoDir  = CRYP_AlgoDir_Decrypt;
+        cryptInit.CRYP_AlgoMode = CRYP_AlgoMode_AES_Key;
+        CRYP_Init(&cryptInit);
 
         /* enable crypto processor */
         CRYP_Cmd(ENABLE);
 
-        /* wait until decrypt key has been intialized */
+        /* wait until decrypt key has been initialized */
         while (CRYP_GetFlagStatus(CRYP_FLAG_BUSY) != RESET) {}
 
-        /* set direction, mode, and datatype */
-        AES_CRYP_InitStructure.CRYP_AlgoDir  = CRYP_AlgoDir_Decrypt;
-        AES_CRYP_InitStructure.CRYP_AlgoMode = CRYP_AlgoMode_AES_ECB;
-        AES_CRYP_InitStructure.CRYP_DataType = CRYP_DataType_8b;
-        CRYP_Init(&AES_CRYP_InitStructure);
+        /* set direction and mode */
+        cryptInit.CRYP_AlgoDir  = CRYP_AlgoDir_Decrypt;
+        cryptInit.CRYP_AlgoMode = CRYP_AlgoMode_AES_ECB;
+        CRYP_Init(&cryptInit);
 
         /* enable crypto processor */
@@ -782,7 +730,18 @@
     #endif /* HAVE_AES_DECRYPT */
 
+#elif defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_AES)
+        static int wc_AesEncrypt(Aes* aes, const byte* inBlock, byte* outBlock)
+        {
+            wc_AesEncryptDirect(aes, outBlock, inBlock);
+            return 0;
+        }
+
+#elif defined(WOLFSSL_AFALG)
+#elif defined(WOLFSSL_DEVCRYPTO_AES)
+    /* if all AES is enabled with devcrypto then tables are not needed */
+
 #else
 
-    /* using wolfCrypt software AES implementation */
+    /* using wolfCrypt software implementation */
     #define NEED_AES_TABLES
 #endif
@@ -1336,4 +1295,5 @@
 
 
+#if defined(HAVE_AES_CBC) || defined(WOLFSSL_AES_DIRECT)
 static const byte Td4[256] =
 {
@@ -1371,4 +1331,5 @@
     0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU,
 };
+#endif /* HAVE_AES_CBC || WOLFSSL_AES_DIRECT */
 #endif /* HAVE_AES_DECRYPT */
 
@@ -1391,5 +1352,5 @@
 
 /* load 4 Te Tables into cache by cache line stride */
-static INLINE word32 PreFetchTe(void)
+static WC_INLINE word32 PreFetchTe(void)
 {
     word32 x = 0;
@@ -1405,5 +1366,5 @@
 }
 
-
+/* Software AES - ECB Encrypt */
 static void wc_AesEncrypt(Aes* aes, const byte* inBlock, byte* outBlock)
 {
@@ -1415,5 +1376,5 @@
     if (r > 7 || r == 0) {
         WOLFSSL_MSG("AesEncrypt encountered improper key, set it up");
-        return;  /* stop instead of segfaulting, set up your keys! */
+        return;  /* stop instead of seg-faulting, set up your keys! */
     }
 
@@ -1594,8 +1555,9 @@
 
 #if defined(HAVE_AES_DECRYPT)
-#if defined(HAVE_AES_CBC) || defined(WOLFSSL_AES_DIRECT)
+#if (defined(HAVE_AES_CBC) || defined(WOLFSSL_AES_DIRECT)) && \
+    !defined(WOLFSSL_DEVCRYPTO_CBC)
 
 /* load 4 Td Tables into cache by cache line stride */
-static INLINE word32 PreFetchTd(void)
+static WC_INLINE word32 PreFetchTd(void)
 {
     word32 x = 0;
@@ -1612,5 +1574,5 @@
 
 /* load Td Table4 into cache by cache line stride */
-static INLINE word32 PreFetchTd4(void)
+static WC_INLINE word32 PreFetchTd4(void)
 {
     word32 x = 0;
@@ -1623,4 +1585,5 @@
 }
 
+/* Software AES - ECB Decrypt */
 static void wc_AesDecrypt(Aes* aes, const byte* inBlock, byte* outBlock)
 {
@@ -1632,5 +1595,5 @@
     if (r > 7 || r == 0) {
         WOLFSSL_MSG("AesDecrypt encountered improper key, set it up");
-        return;  /* stop instead of segfaulting, set up your keys! */
+        return;  /* stop instead of seg-faulting, set up your keys! */
     }
 #ifdef WOLFSSL_AESNI
@@ -1803,6 +1766,11 @@
         (void)dir;
 
-        if (!((keylen == 16) || (keylen == 24) || (keylen == 32)))
+        if (keylen != 16 &&
+        #ifdef WOLFSSL_AES_192
+            keylen != 24 &&
+        #endif
+            keylen != 32) {
             return BAD_FUNC_ARG;
+        }
 
         aes->keylen = keylen;
@@ -1812,5 +1780,5 @@
         ByteReverseWords(rk, rk, keylen);
     #endif
-    #ifdef WOLFSSL_AES_COUNTER
+    #if defined(WOLFSSL_AES_CFB) || defined(WOLFSSL_AES_COUNTER)
         aes->left = 0;
     #endif
@@ -1885,4 +1853,8 @@
             XMEMCPY(aes->reg, iv, AES_BLOCK_SIZE);
 
+    #if defined(WOLFSSL_AES_CFB) || defined(WOLFSSL_AES_COUNTER)
+        aes->left = 0;
+    #endif
+
         return 0;
     }
@@ -1891,10 +1863,11 @@
                   int dir)
     {
-        if (!((keylen == 16) || (keylen == 24) || (keylen == 32)))
+        if (aes == NULL || !((keylen == 16) || (keylen == 24) || (keylen == 32)))
             return BAD_FUNC_ARG;
 
         aes->rounds = keylen/4 + 6;
         XMEMCPY(aes->key, userKey, keylen);
-    #ifdef WOLFSSL_AES_COUNTER
+
+    #if defined(WOLFSSL_AES_CFB) || defined(WOLFSSL_AES_COUNTER)
         aes->left = 0;
     #endif
@@ -1923,8 +1896,8 @@
             return BAD_FUNC_ARG;
 
-    #ifdef WOLFSSL_AES_COUNTER
+    #if defined(WOLFSSL_AES_CFB) || defined(WOLFSSL_AES_COUNTER)
         aes->left = 0;
     #endif
-        aes->keylen = keylen;
+
         aes->rounds = keylen/4 + 6;
 
@@ -1966,4 +1939,8 @@
         ret = nrf51_aes_set_key(userKey);
 
+    #if defined(WOLFSSL_AES_CFB) || defined(WOLFSSL_AES_COUNTER)
+        aes->left = 0;
+    #endif
+
         return ret;
     }
@@ -1975,5 +1952,16 @@
     }
 
+#elif defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_AES)
+      /* implemented in wolfcrypt/src/port/caam/caam_aes.c */
+
+#elif defined(WOLFSSL_AFALG)
+    /* implemented in wolfcrypt/src/port/af_alg/afalg_aes.c */
+
+#elif defined(WOLFSSL_DEVCRYPTO_AES)
+    /* implemented in wolfcrypt/src/port/devcrypto/devcrypto_aes.c */
+
 #else
+
+    /* Software AES - SetKey */
     static int wc_AesSetKeyLocal(Aes* aes, const byte* userKey, word32 keylen,
                 const byte* iv, int dir)
@@ -1988,7 +1976,7 @@
         aes->use_aesni = 0;
     #endif /* WOLFSSL_AESNI */
-    #ifdef WOLFSSL_AES_COUNTER
+        #if defined(WOLFSSL_AES_CFB) || defined(WOLFSSL_AES_COUNTER)
         aes->left = 0;
-    #endif /* WOLFSSL_AES_COUNTER */
+        #endif
 
         aes->keylen = keylen;
@@ -2003,5 +1991,6 @@
 
         switch (keylen) {
-    #if defined(AES_MAX_KEY_SIZE) && AES_MAX_KEY_SIZE >= 128
+    #if defined(AES_MAX_KEY_SIZE) && AES_MAX_KEY_SIZE >= 128 && \
+            defined(WOLFSSL_AES_128)
         case 16:
             while (1)
@@ -2024,5 +2013,6 @@
     #endif /* 128 */
 
-    #if defined(AES_MAX_KEY_SIZE) && AES_MAX_KEY_SIZE >= 192
+    #if defined(AES_MAX_KEY_SIZE) && AES_MAX_KEY_SIZE >= 192 && \
+            defined(WOLFSSL_AES_192)
         case 24:
             /* for (;;) here triggers a bug in VC60 SP4 w/ Pro Pack */
@@ -2048,5 +2038,6 @@
     #endif /* 192 */
 
-    #if defined(AES_MAX_KEY_SIZE) && AES_MAX_KEY_SIZE >= 256
+    #if defined(AES_MAX_KEY_SIZE) && AES_MAX_KEY_SIZE >= 256 && \
+            defined(WOLFSSL_AES_256)
         case 32:
             while (1)
@@ -2132,8 +2123,25 @@
         const byte* iv, int dir)
     {
+        int ret;
     #if defined(AES_MAX_KEY_SIZE)
         const word32 max_key_len = (AES_MAX_KEY_SIZE / 8);
     #endif
 
+    #ifdef WOLFSSL_IMX6_CAAM_BLOB
+        byte   local[32];
+        word32 localSz = 32;
+
+        if (keylen == (16 + WC_CAAM_BLOB_SZ) ||
+                keylen == (24 + WC_CAAM_BLOB_SZ) ||
+                keylen == (32 + WC_CAAM_BLOB_SZ)) {
+            if (wc_caamOpenBlob((byte*)userKey, keylen, local, &localSz) != 0) {
+                return BAD_FUNC_ARG;
+            }
+
+            /* set local values */
+            userKey = local;
+            keylen = localSz;
+        }
+    #endif
         if (aes == NULL ||
                 !((keylen == 16) || (keylen == 24) || (keylen == 32))) {
@@ -2164,5 +2172,5 @@
         }
         if (haveAESNI) {
-            #ifdef WOLFSSL_AES_COUNTER
+            #if defined(WOLFSSL_AES_COUNTER) || defined(WOLFSSL_AES_CFB)
                 aes->left = 0;
             #endif /* WOLFSSL_AES_COUNTER */
@@ -2179,5 +2187,15 @@
     #endif /* WOLFSSL_AESNI */
 
-        return wc_AesSetKeyLocal(aes, userKey, keylen, iv, dir);
+        ret = wc_AesSetKeyLocal(aes, userKey, keylen, iv, dir);
+
+    #if defined(WOLFSSL_DEVCRYPTO) && \
+        (defined(WOLFSSL_DEVCRYPTO_AES) || defined(WOLFSSL_DEVCRYPTO_CBC))
+        aes->ctx.cfd = -1;
+        XMEMCPY(aes->devKey, userKey, keylen);
+    #endif
+    #ifdef WOLFSSL_IMX6_CAAM_BLOB
+        ForceZero(local, sizeof(local));
+    #endif
+        return ret;
     }
 
@@ -2187,5 +2205,30 @@
                             const byte* iv, int dir)
         {
-            return wc_AesSetKeyLocal(aes, userKey, keylen, iv, dir);
+            int ret;
+
+        #ifdef WOLFSSL_IMX6_CAAM_BLOB
+            byte   local[32];
+            word32 localSz = 32;
+
+            if (keylen == (16 + WC_CAAM_BLOB_SZ) ||
+             keylen == (24 + WC_CAAM_BLOB_SZ) ||
+             keylen == (32 + WC_CAAM_BLOB_SZ)) {
+                if (wc_caamOpenBlob((byte*)userKey, keylen, local, &localSz)
+                        != 0) {
+                    return BAD_FUNC_ARG;
+                }
+
+                /* set local values */
+                userKey = local;
+                keylen = localSz;
+            }
+        #endif
+            ret = wc_AesSetKeyLocal(aes, userKey, keylen, iv, dir);
+
+        #ifdef WOLFSSL_IMX6_CAAM_BLOB
+            ForceZero(local, sizeof(local));
+        #endif
+
+            return ret;
         }
     #endif /* WOLFSSL_AES_DIRECT || WOLFSSL_AES_COUNTER */
@@ -2239,4 +2282,13 @@
         }
 
+    #elif defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_AES)
+        /* implemented in wolfcrypt/src/port/caam/caam_aes.c */
+
+    #elif defined(WOLFSSL_AFALG)
+        /* implemented in wolfcrypt/src/port/af_alg/afalg_aes.c */
+
+    #elif defined(WOLFSSL_DEVCRYPTO_AES)
+        /* implemented in wolfcrypt/src/port/devcrypt/devcrypto_aes.c */
+
     #else
         /* Allow direct access to one block encrypt */
@@ -2267,28 +2319,25 @@
         CRYP_HandleTypeDef hcryp;
 
-        XMEMSET(&hcryp, 0, sizeof(CRYP_HandleTypeDef));
-        switch (aes->rounds) {
-            case 10: /* 128-bit key */
-                hcryp.Init.KeySize = CRYP_KEYSIZE_128B;
-                break;
-            case 12: /* 192-bit key */
-                hcryp.Init.KeySize = CRYP_KEYSIZE_192B;
-                break;
-            case 14: /* 256-bit key */
-                hcryp.Init.KeySize = CRYP_KEYSIZE_256B;
-                break;
-            default:
-                break;
-        }
-        hcryp.Instance = CRYP;
-        hcryp.Init.DataType = CRYP_DATATYPE_8B;
-        hcryp.Init.pKey = (uint8_t*)aes->key;
+        ret = wc_Stm32_Aes_Init(aes, &hcryp);
+        if (ret != 0)
+            return ret;
+
+    #ifdef STM32_CRYPTO_AES_ONLY
+        hcryp.Init.OperatingMode = CRYP_ALGOMODE_ENCRYPT;
+        hcryp.Init.ChainingMode  = CRYP_CHAINMODE_AES_CBC;
+        hcryp.Init.KeyWriteFlag  = CRYP_KEY_WRITE_ENABLE;
+    #endif
         hcryp.Init.pInitVect = (uint8_t*)aes->reg;
-
         HAL_CRYP_Init(&hcryp);
 
         while (blocks--) {
-            if (HAL_CRYP_AESCBC_Encrypt(&hcryp, (uint8_t*)in, AES_BLOCK_SIZE,
-                                           out, STM32_HAL_TIMEOUT) != HAL_OK) {
+        #ifdef STM32_CRYPTO_AES_ONLY
+            ret = HAL_CRYPEx_AES(&hcryp, (uint8_t*)in, AES_BLOCK_SIZE,
+                out, STM32_HAL_TIMEOUT);
+        #else
+            ret = HAL_CRYP_AESCBC_Encrypt(&hcryp, (uint8_t*)in, AES_BLOCK_SIZE,
+                out, STM32_HAL_TIMEOUT);
+        #endif
+            if (ret != HAL_OK) {
                 ret = WC_TIMEOUT_E;
                 break;
@@ -2314,29 +2363,31 @@
         CRYP_HandleTypeDef hcryp;
 
-        XMEMSET(&hcryp, 0, sizeof(CRYP_HandleTypeDef));
-        switch (aes->rounds) {
-            case 10: /* 128-bit key */
-                hcryp.Init.KeySize = CRYP_KEYSIZE_128B;
+        ret = wc_Stm32_Aes_Init(aes, &hcryp);
+        if (ret != 0)
+            return ret;
+
+        /* if input and output same will overwrite input iv */
+        XMEMCPY(aes->tmp, in + sz - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+
+    #ifdef STM32_CRYPTO_AES_ONLY
+        hcryp.Init.OperatingMode = CRYP_ALGOMODE_KEYDERIVATION_DECRYPT;
+        hcryp.Init.ChainingMode  = CRYP_CHAINMODE_AES_CBC;
+        hcryp.Init.KeyWriteFlag  = CRYP_KEY_WRITE_ENABLE;
+    #endif
+
+        hcryp.Init.pInitVect = (uint8_t*)aes->reg;
+        HAL_CRYP_Init(&hcryp);
+
+        while (blocks--) {
+        #ifdef STM32_CRYPTO_AES_ONLY
+            ret = HAL_CRYPEx_AES(&hcryp, (uint8_t*)in, AES_BLOCK_SIZE,
+                out, STM32_HAL_TIMEOUT);
+        #else
+            ret = HAL_CRYP_AESCBC_Decrypt(&hcryp, (uint8_t*)in, AES_BLOCK_SIZE,
+                out, STM32_HAL_TIMEOUT);
+        #endif
+            if (ret != HAL_OK) {
+                ret = WC_TIMEOUT_E;
                 break;
-            case 12: /* 192-bit key */
-                hcryp.Init.KeySize = CRYP_KEYSIZE_192B;
-                break;
-            case 14: /* 256-bit key */
-                hcryp.Init.KeySize = CRYP_KEYSIZE_256B;
-                break;
-            default:
-                break;
-        }
-        hcryp.Instance = CRYP;
-        hcryp.Init.DataType = CRYP_DATATYPE_8B;
-        hcryp.Init.pKey = (uint8_t*)aes->key;
-        hcryp.Init.pInitVect = (uint8_t*)aes->reg;
-
-        HAL_CRYP_Init(&hcryp);
-
-        while (blocks--) {
-            if (HAL_CRYP_AESCBC_Decrypt(&hcryp, (uint8_t*)in, AES_BLOCK_SIZE,
-                                           out, STM32_HAL_TIMEOUT) != HAL_OK) {
-                ret = WC_TIMEOUT_E;
             }
 
@@ -2353,74 +2404,39 @@
     }
     #endif /* HAVE_AES_DECRYPT */
-#else
+
+#else /* STD_PERI_LIB */
     int wc_AesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
     {
-        word32 *enc_key, *iv;
+    	int ret;
+        word32 *iv;
         word32 blocks = (sz / AES_BLOCK_SIZE);
-        CRYP_InitTypeDef AES_CRYP_InitStructure;
-        CRYP_KeyInitTypeDef AES_CRYP_KeyInitStructure;
-        CRYP_IVInitTypeDef AES_CRYP_IVInitStructure;
-
-        enc_key = aes->key;
-        iv = aes->reg;
-
-        /* crypto structure initialization */
-        CRYP_KeyStructInit(&AES_CRYP_KeyInitStructure);
-        CRYP_StructInit(&AES_CRYP_InitStructure);
-        CRYP_IVStructInit(&AES_CRYP_IVInitStructure);
+        CRYP_InitTypeDef cryptInit;
+        CRYP_KeyInitTypeDef keyInit;
+        CRYP_IVInitTypeDef ivInit;
+
+        ret = wc_Stm32_Aes_Init(aes, &cryptInit, &keyInit);
+        if (ret != 0)
+            return ret;
 
         /* reset registers to their default values */
         CRYP_DeInit();
 
-        /* load key into correct registers */
-        switch (aes->rounds) {
-            case 10: /* 128-bit key */
-                AES_CRYP_InitStructure.CRYP_KeySize = CRYP_KeySize_128b;
-                AES_CRYP_KeyInitStructure.CRYP_Key2Left  = enc_key[0];
-                AES_CRYP_KeyInitStructure.CRYP_Key2Right = enc_key[1];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Left  = enc_key[2];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Right = enc_key[3];
-                break;
-
-            case 12: /* 192-bit key */
-                AES_CRYP_InitStructure.CRYP_KeySize = CRYP_KeySize_192b;
-                AES_CRYP_KeyInitStructure.CRYP_Key1Left  = enc_key[0];
-                AES_CRYP_KeyInitStructure.CRYP_Key1Right = enc_key[1];
-                AES_CRYP_KeyInitStructure.CRYP_Key2Left  = enc_key[2];
-                AES_CRYP_KeyInitStructure.CRYP_Key2Right = enc_key[3];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Left  = enc_key[4];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Right = enc_key[5];
-                break;
-
-            case 14: /* 256-bit key */
-                AES_CRYP_InitStructure.CRYP_KeySize = CRYP_KeySize_256b;
-                AES_CRYP_KeyInitStructure.CRYP_Key0Left  = enc_key[0];
-                AES_CRYP_KeyInitStructure.CRYP_Key0Right = enc_key[1];
-                AES_CRYP_KeyInitStructure.CRYP_Key1Left  = enc_key[2];
-                AES_CRYP_KeyInitStructure.CRYP_Key1Right = enc_key[3];
-                AES_CRYP_KeyInitStructure.CRYP_Key2Left  = enc_key[4];
-                AES_CRYP_KeyInitStructure.CRYP_Key2Right = enc_key[5];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Left  = enc_key[6];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Right = enc_key[7];
-                break;
-
-            default:
-                break;
-        }
-        CRYP_KeyInit(&AES_CRYP_KeyInitStructure);
+        /* set key */
+        CRYP_KeyInit(&keyInit);
 
         /* set iv */
+        iv = aes->reg;
+        CRYP_IVStructInit(&ivInit);
         ByteReverseWords(iv, iv, AES_BLOCK_SIZE);
-        AES_CRYP_IVInitStructure.CRYP_IV0Left  = iv[0];
-        AES_CRYP_IVInitStructure.CRYP_IV0Right = iv[1];
-        AES_CRYP_IVInitStructure.CRYP_IV1Left  = iv[2];
-        AES_CRYP_IVInitStructure.CRYP_IV1Right = iv[3];
-        CRYP_IVInit(&AES_CRYP_IVInitStructure);
-
-        /* set direction, mode, and datatype */
-        AES_CRYP_InitStructure.CRYP_AlgoDir  = CRYP_AlgoDir_Encrypt;
-        AES_CRYP_InitStructure.CRYP_AlgoMode = CRYP_AlgoMode_AES_CBC;
-        AES_CRYP_InitStructure.CRYP_DataType = CRYP_DataType_8b;
-        CRYP_Init(&AES_CRYP_InitStructure);
+        ivInit.CRYP_IV0Left  = iv[0];
+        ivInit.CRYP_IV0Right = iv[1];
+        ivInit.CRYP_IV1Left  = iv[2];
+        ivInit.CRYP_IV1Right = iv[3];
+        CRYP_IVInit(&ivInit);
+
+        /* set direction and mode */
+        cryptInit.CRYP_AlgoDir  = CRYP_AlgoDir_Encrypt;
+        cryptInit.CRYP_AlgoMode = CRYP_AlgoMode_AES_CBC;
+        CRYP_Init(&cryptInit);
 
         /* enable crypto processor */
@@ -2455,5 +2471,5 @@
         CRYP_Cmd(DISABLE);
 
-        return 0;
+        return ret;
     }
 
@@ -2461,17 +2477,14 @@
     int wc_AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
     {
-        word32 *dec_key, *iv;
+    	int ret;
+        word32 *iv;
         word32 blocks = (sz / AES_BLOCK_SIZE);
-        CRYP_InitTypeDef AES_CRYP_InitStructure;
-        CRYP_KeyInitTypeDef AES_CRYP_KeyInitStructure;
-        CRYP_IVInitTypeDef AES_CRYP_IVInitStructure;
-
-        dec_key = aes->key;
-        iv = aes->reg;
-
-        /* crypto structure initialization */
-        CRYP_KeyStructInit(&AES_CRYP_KeyInitStructure);
-        CRYP_StructInit(&AES_CRYP_InitStructure);
-        CRYP_IVStructInit(&AES_CRYP_IVInitStructure);
+        CRYP_InitTypeDef cryptInit;
+        CRYP_KeyInitTypeDef keyInit;
+        CRYP_IVInitTypeDef ivInit;
+
+        ret = wc_Stm32_Aes_Init(aes, &cryptInit, &keyInit);
+        if (ret != 0)
+            return ret;
 
         /* if input and output same will overwrite input iv */
@@ -2481,46 +2494,9 @@
         CRYP_DeInit();
 
-        /* load key into correct registers */
-        switch (aes->rounds) {
-            case 10: /* 128-bit key */
-                AES_CRYP_InitStructure.CRYP_KeySize = CRYP_KeySize_128b;
-                AES_CRYP_KeyInitStructure.CRYP_Key2Left  = dec_key[0];
-                AES_CRYP_KeyInitStructure.CRYP_Key2Right = dec_key[1];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Left  = dec_key[2];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Right = dec_key[3];
-                break;
-
-            case 12: /* 192-bit key */
-                AES_CRYP_InitStructure.CRYP_KeySize = CRYP_KeySize_192b;
-                AES_CRYP_KeyInitStructure.CRYP_Key1Left  = dec_key[0];
-                AES_CRYP_KeyInitStructure.CRYP_Key1Right = dec_key[1];
-                AES_CRYP_KeyInitStructure.CRYP_Key2Left  = dec_key[2];
-                AES_CRYP_KeyInitStructure.CRYP_Key2Right = dec_key[3];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Left  = dec_key[4];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Right = dec_key[5];
-                break;
-
-            case 14: /* 256-bit key */
-                AES_CRYP_InitStructure.CRYP_KeySize = CRYP_KeySize_256b;
-                AES_CRYP_KeyInitStructure.CRYP_Key0Left  = dec_key[0];
-                AES_CRYP_KeyInitStructure.CRYP_Key0Right = dec_key[1];
-                AES_CRYP_KeyInitStructure.CRYP_Key1Left  = dec_key[2];
-                AES_CRYP_KeyInitStructure.CRYP_Key1Right = dec_key[3];
-                AES_CRYP_KeyInitStructure.CRYP_Key2Left  = dec_key[4];
-                AES_CRYP_KeyInitStructure.CRYP_Key2Right = dec_key[5];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Left  = dec_key[6];
-                AES_CRYP_KeyInitStructure.CRYP_Key3Right = dec_key[7];
-                break;
-
-            default:
-                break;
-        }
-
-        /* set direction, mode, and datatype for key preparation */
-        AES_CRYP_InitStructure.CRYP_AlgoDir  = CRYP_AlgoDir_Decrypt;
-        AES_CRYP_InitStructure.CRYP_AlgoMode = CRYP_AlgoMode_AES_Key;
-        AES_CRYP_InitStructure.CRYP_DataType = CRYP_DataType_32b;
-        CRYP_Init(&AES_CRYP_InitStructure);
-        CRYP_KeyInit(&AES_CRYP_KeyInitStructure);
+        /* set direction and key */
+        CRYP_KeyInit(&keyInit);
+        cryptInit.CRYP_AlgoDir  = CRYP_AlgoDir_Decrypt;
+        cryptInit.CRYP_AlgoMode = CRYP_AlgoMode_AES_Key;
+        CRYP_Init(&cryptInit);
 
         /* enable crypto processor */
@@ -2530,18 +2506,18 @@
         while (CRYP_GetFlagStatus(CRYP_FLAG_BUSY) != RESET) {}
 
-        /* set direction, mode, and datatype for decryption */
-        AES_CRYP_InitStructure.CRYP_AlgoDir  = CRYP_AlgoDir_Decrypt;
-        AES_CRYP_InitStructure.CRYP_AlgoMode = CRYP_AlgoMode_AES_CBC;
-        AES_CRYP_InitStructure.CRYP_DataType = CRYP_DataType_8b;
-        CRYP_Init(&AES_CRYP_InitStructure);
+        /* set direction and mode */
+        cryptInit.CRYP_AlgoDir  = CRYP_AlgoDir_Decrypt;
+        cryptInit.CRYP_AlgoMode = CRYP_AlgoMode_AES_CBC;
+        CRYP_Init(&cryptInit);
 
         /* set iv */
+        iv = aes->reg;
+        CRYP_IVStructInit(&ivInit);
         ByteReverseWords(iv, iv, AES_BLOCK_SIZE);
-
-        AES_CRYP_IVInitStructure.CRYP_IV0Left  = iv[0];
-        AES_CRYP_IVInitStructure.CRYP_IV0Right = iv[1];
-        AES_CRYP_IVInitStructure.CRYP_IV1Left  = iv[2];
-        AES_CRYP_IVInitStructure.CRYP_IV1Right = iv[3];
-        CRYP_IVInit(&AES_CRYP_IVInitStructure);
+        ivInit.CRYP_IV0Left  = iv[0];
+        ivInit.CRYP_IV0Right = iv[1];
+        ivInit.CRYP_IV1Left  = iv[2];
+        ivInit.CRYP_IV1Right = iv[3];
+        CRYP_IVInit(&ivInit);
 
         /* enable crypto processor */
@@ -2575,5 +2551,5 @@
         CRYP_Cmd(DISABLE);
 
-        return 0;
+        return ret;
     }
     #endif /* HAVE_AES_DECRYPT */
@@ -2704,4 +2680,10 @@
         status = LTC_AES_EncryptCbc(LTC_BASE, in, out, blocks * AES_BLOCK_SIZE,
             iv, enc_key, keySize);
+
+        /* store iv for next call */
+        if (status == kStatus_Success) {
+            XMEMCPY(iv, out + sz - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+        }
+
         return (status == kStatus_Success) ? 0 : -1;
     }
@@ -2714,4 +2696,5 @@
         byte* iv, *dec_key;
         word32 blocks = (sz / AES_BLOCK_SIZE);
+        byte temp_block[AES_BLOCK_SIZE];
 
         iv      = (byte*)aes->reg;
@@ -2723,6 +2706,15 @@
         }
 
+        /* get IV for next call */
+        XMEMCPY(temp_block, in + sz - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+
         status = LTC_AES_DecryptCbc(LTC_BASE, in, out, blocks * AES_BLOCK_SIZE,
             iv, dec_key, keySize, kLTC_EncryptKey);
+
+        /* store IV for next call */
+        if (status == kStatus_Success) {
+            XMEMCPY(iv, temp_block, AES_BLOCK_SIZE);
+        }
+
         return (status == kStatus_Success) ? 0 : -1;
     }
@@ -2791,21 +2783,61 @@
     int wc_AesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
     {
-        return wc_Pic32AesCrypt(
+        int ret;
+
+        /* hardware fails on input that is not a multiple of AES block size */
+        if (sz % AES_BLOCK_SIZE != 0) {
+            return BAD_FUNC_ARG;
+        }
+
+        ret = wc_Pic32AesCrypt(
             aes->key, aes->keylen, aes->reg, AES_BLOCK_SIZE,
             out, in, sz, PIC32_ENCRYPTION,
             PIC32_ALGO_AES, PIC32_CRYPTOALGO_RCBC);
+
+        /* store iv for next call */
+        if (ret == 0) {
+            XMEMCPY(aes->reg, out + sz - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+        }
+
+        return ret;
     }
     #ifdef HAVE_AES_DECRYPT
     int wc_AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
     {
-        return wc_Pic32AesCrypt(
+        int ret;
+        byte scratch[AES_BLOCK_SIZE];
+
+        /* hardware fails on input that is not a multiple of AES block size */
+        if (sz % AES_BLOCK_SIZE != 0) {
+            return BAD_FUNC_ARG;
+        }
+        XMEMCPY(scratch, in + sz - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+
+        ret = wc_Pic32AesCrypt(
             aes->key, aes->keylen, aes->reg, AES_BLOCK_SIZE,
             out, in, sz, PIC32_DECRYPTION,
             PIC32_ALGO_AES, PIC32_CRYPTOALGO_RCBC);
+
+        /* store iv for next call */
+        if (ret == 0) {
+            XMEMCPY((byte*)aes->reg, scratch, AES_BLOCK_SIZE);
+        }
+
+        return ret;
     }
     #endif /* HAVE_AES_DECRYPT */
 
+#elif defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_AES)
+      /* implemented in wolfcrypt/src/port/caam/caam_aes.c */
+
+#elif defined(WOLFSSL_AFALG)
+    /* implemented in wolfcrypt/src/port/af_alg/afalg_aes.c */
+
+#elif defined(WOLFSSL_DEVCRYPTO_CBC)
+    /* implemented in wolfcrypt/src/port/devcrypt/devcrypto_aes.c */
+
 #else
 
+    /* Software AES - CBC Encrypt */
     int wc_AesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
     {
@@ -2897,4 +2929,5 @@
 
     #ifdef HAVE_AES_DECRYPT
+    /* Software AES - CBC Decrypt */
     int wc_AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
     {
@@ -2977,31 +3010,4 @@
 #endif /* HAVE_AES_CBC */
 
-#ifdef HAVE_AES_ECB
-int wc_AesEcbEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
-{
-    if ((in == NULL) || (out == NULL) || (aes == NULL))
-      return BAD_FUNC_ARG;
-    while (sz>0) {
-      wc_AesEncryptDirect(aes, out, in);
-      out += AES_BLOCK_SIZE;
-      in  += AES_BLOCK_SIZE;
-      sz  -= AES_BLOCK_SIZE;
-    }
-    return 0;
-}
-int wc_AesEcbDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
-{
-    if ((in == NULL) || (out == NULL) || (aes == NULL))
-      return BAD_FUNC_ARG;
-    while (sz>0) {
-      wc_AesDecryptDirect(aes, out, in);
-      out += AES_BLOCK_SIZE;
-      in  += AES_BLOCK_SIZE;
-      sz  -= AES_BLOCK_SIZE;
-    }
-    return 0;
-}
-#endif
-
 /* AES-CTR */
 #if defined(WOLFSSL_AES_COUNTER)
@@ -3016,97 +3022,60 @@
         #ifdef WOLFSSL_STM32_CUBEMX
             CRYP_HandleTypeDef hcryp;
-
-            XMEMSET(&hcryp, 0, sizeof(CRYP_HandleTypeDef));
-            switch (aes->rounds) {
-                case 10: /* 128-bit key */
-                    hcryp.Init.KeySize = CRYP_KEYSIZE_128B;
-                    break;
-                case 12: /* 192-bit key */
-                    hcryp.Init.KeySize = CRYP_KEYSIZE_192B;
-                    break;
-                case 14: /* 256-bit key */
-                    hcryp.Init.KeySize = CRYP_KEYSIZE_256B;
-                    break;
-                default:
-                    break;
-            }
-            hcryp.Instance = CRYP;
-            hcryp.Init.DataType = CRYP_DATATYPE_8B;
-            hcryp.Init.pKey = (byte*)aes->key;
-            hcryp.Init.pInitVect = (byte*)aes->reg;
-
+        #else
+            word32 *iv;
+            CRYP_InitTypeDef cryptInit;
+            CRYP_KeyInitTypeDef keyInit;
+            CRYP_IVInitTypeDef ivInit;
+        #endif
+
+        #ifdef WOLFSSL_STM32_CUBEMX
+            ret = wc_Stm32_Aes_Init(aes, &hcryp);
+            if (ret != 0)
+                return ret;
+
+        #ifdef STM32_CRYPTO_AES_ONLY
+            hcryp.Init.OperatingMode = CRYP_ALGOMODE_ENCRYPT;
+            hcryp.Init.ChainingMode  = CRYP_CHAINMODE_AES_CTR;
+            hcryp.Init.KeyWriteFlag  = CRYP_KEY_WRITE_ENABLE;
+        #endif
+            hcryp.Init.pInitVect = (uint8_t*)aes->reg;
             HAL_CRYP_Init(&hcryp);
 
-            if (HAL_CRYP_AESCTR_Encrypt(&hcryp, (byte*)in, AES_BLOCK_SIZE, out,
-                                                STM32_HAL_TIMEOUT) != HAL_OK) {
-                /* failed */
+        #ifdef STM32_CRYPTO_AES_ONLY
+            ret = HAL_CRYPEx_AES(&hcryp, (byte*)in, AES_BLOCK_SIZE,
+                out, STM32_HAL_TIMEOUT);
+        #else
+            ret = HAL_CRYP_AESCTR_Encrypt(&hcryp, (byte*)in, AES_BLOCK_SIZE,
+                out, STM32_HAL_TIMEOUT);
+        #endif
+            if (ret != HAL_OK) {
                 ret = WC_TIMEOUT_E;
             }
-
             HAL_CRYP_DeInit(&hcryp);
 
         #else /* STD_PERI_LIB */
-            word32 *enc_key, *iv;
-            CRYP_InitTypeDef AES_CRYP_InitStructure;
-            CRYP_KeyInitTypeDef AES_CRYP_KeyInitStructure;
-            CRYP_IVInitTypeDef AES_CRYP_IVInitStructure;
-
-            enc_key = aes->key;
-            iv = aes->reg;
-
-            /* crypto structure initialization */
-            CRYP_KeyStructInit(&AES_CRYP_KeyInitStructure);
-            CRYP_StructInit(&AES_CRYP_InitStructure);
-            CRYP_IVStructInit(&AES_CRYP_IVInitStructure);
+            ret = wc_Stm32_Aes_Init(aes, &cryptInit, &keyInit);
+            if (ret != 0)
+                return ret;
 
             /* reset registers to their default values */
             CRYP_DeInit();
 
-            /* load key into correct registers */
-            switch (aes->rounds) {
-                case 10: /* 128-bit key */
-                    AES_CRYP_InitStructure.CRYP_KeySize = CRYP_KeySize_128b;
-                    AES_CRYP_KeyInitStructure.CRYP_Key2Left  = enc_key[0];
-                    AES_CRYP_KeyInitStructure.CRYP_Key2Right = enc_key[1];
-                    AES_CRYP_KeyInitStructure.CRYP_Key3Left  = enc_key[2];
-                    AES_CRYP_KeyInitStructure.CRYP_Key3Right = enc_key[3];
-                    break;
-                case 12: /* 192-bit key */
-                    AES_CRYP_InitStructure.CRYP_KeySize = CRYP_KeySize_192b;
-                    AES_CRYP_KeyInitStructure.CRYP_Key1Left  = enc_key[0];
-                    AES_CRYP_KeyInitStructure.CRYP_Key1Right = enc_key[1];
-                    AES_CRYP_KeyInitStructure.CRYP_Key2Left  = enc_key[2];
-                    AES_CRYP_KeyInitStructure.CRYP_Key2Right = enc_key[3];
-                    AES_CRYP_KeyInitStructure.CRYP_Key3Left  = enc_key[4];
-                    AES_CRYP_KeyInitStructure.CRYP_Key3Right = enc_key[5];
-                    break;
-                case 14: /* 256-bit key */
-                    AES_CRYP_InitStructure.CRYP_KeySize = CRYP_KeySize_256b;
-                    AES_CRYP_KeyInitStructure.CRYP_Key0Left  = enc_key[0];
-                    AES_CRYP_KeyInitStructure.CRYP_Key0Right = enc_key[1];
-                    AES_CRYP_KeyInitStructure.CRYP_Key1Left  = enc_key[2];
-                    AES_CRYP_KeyInitStructure.CRYP_Key1Right = enc_key[3];
-                    AES_CRYP_KeyInitStructure.CRYP_Key2Left  = enc_key[4];
-                    AES_CRYP_KeyInitStructure.CRYP_Key2Right = enc_key[5];
-                    AES_CRYP_KeyInitStructure.CRYP_Key3Left  = enc_key[6];
-                    AES_CRYP_KeyInitStructure.CRYP_Key3Right = enc_key[7];
-                    break;
-                default:
-                    break;
-            }
-            CRYP_KeyInit(&AES_CRYP_KeyInitStructure);
+            /* set key */
+            CRYP_KeyInit(&keyInit);
 
             /* set iv */
-            AES_CRYP_IVInitStructure.CRYP_IV0Left  = ByteReverseWord32(iv[0]);
-            AES_CRYP_IVInitStructure.CRYP_IV0Right = ByteReverseWord32(iv[1]);
-            AES_CRYP_IVInitStructure.CRYP_IV1Left  = ByteReverseWord32(iv[2]);
-            AES_CRYP_IVInitStructure.CRYP_IV1Right = ByteReverseWord32(iv[3]);
-            CRYP_IVInit(&AES_CRYP_IVInitStructure);
-
-            /* set direction, mode, and datatype */
-            AES_CRYP_InitStructure.CRYP_AlgoDir  = CRYP_AlgoDir_Encrypt;
-            AES_CRYP_InitStructure.CRYP_AlgoMode = CRYP_AlgoMode_AES_CTR;
-            AES_CRYP_InitStructure.CRYP_DataType = CRYP_DataType_8b;
-            CRYP_Init(&AES_CRYP_InitStructure);
+            iv = aes->reg;
+            CRYP_IVStructInit(&ivInit);
+            ivInit.CRYP_IV0Left  = ByteReverseWord32(iv[0]);
+            ivInit.CRYP_IV0Right = ByteReverseWord32(iv[1]);
+            ivInit.CRYP_IV1Left  = ByteReverseWord32(iv[2]);
+            ivInit.CRYP_IV1Right = ByteReverseWord32(iv[3]);
+            CRYP_IVInit(&ivInit);
+
+            /* set direction and mode */
+            cryptInit.CRYP_AlgoDir  = CRYP_AlgoDir_Encrypt;
+            cryptInit.CRYP_AlgoMode = CRYP_AlgoMode_AES_CTR;
+            CRYP_Init(&cryptInit);
 
             /* enable crypto processor */
@@ -3188,4 +3157,13 @@
         }
 
+    #elif defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_AES)
+        /* implemented in wolfcrypt/src/port/caam/caam_aes.c */
+
+    #elif defined(WOLFSSL_AFALG)
+        /* implemented in wolfcrypt/src/port/af_alg/afalg_aes.c */
+
+    #elif defined(WOLFSSL_DEVCRYPTO_AES)
+        /* implemented in wolfcrypt/src/port/devcrypt/devcrypto_aes.c */
+
     #else
 
@@ -3196,5 +3174,5 @@
     #ifdef NEED_AES_CTR_SOFT
         /* Increment AES counter */
-        static INLINE void IncrementAesCounter(byte* inOutCtr)
+        static WC_INLINE void IncrementAesCounter(byte* inOutCtr)
         {
             /* in network byte order so start at end and work back */
@@ -3206,4 +3184,5 @@
         }
 
+        /* Software AES - CTR Encrypt */
         int wc_AesCtrEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
         {
@@ -3258,19 +3237,32 @@
 
 #endif /* WOLFSSL_AES_COUNTER */
+#endif /* !WOLFSSL_ARMASM */
+
+
+/*
+ * The IV for AES GCM and CCM, stored in struct Aes's member reg, is comprised
+ * of two parts in order:
+ *   1. The fixed field which may be 0 or 4 bytes long. In TLS, this is set
+ *      to the implicit IV.
+ *   2. The explicit IV is generated by wolfCrypt. It needs to be managed
+ *      by wolfCrypt to ensure the IV is unique for each call to encrypt.
+ * The IV may be a 96-bit random value, or the 32-bit fixed value and a
+ * 64-bit set of 0 or random data. The final 32-bits of reg is used as a
+ * block counter during the encryption.
+ */
+
+#if (defined(HAVE_AESGCM) && !defined(WC_NO_RNG)) || defined(HAVE_AESCCM)
+static WC_INLINE void IncCtr(byte* ctr, word32 ctrSz)
+{
+    int i;
+    for (i = ctrSz-1; i >= 0; i--) {
+        if (++ctr[i])
+            break;
+    }
+}
+#endif /* HAVE_AESGCM || HAVE_AESCCM */
 
 
 #ifdef HAVE_AESGCM
-
-/*
- * The IV for AES GCM, stored in struct Aes's member reg, is comprised of
- * three parts in order:
- *   1. The implicit IV. This is generated from the PRF using the shared
- *      secrets between endpoints. It is 4 bytes long.
- *   2. The explicit IV. This is set by the user of the AES. It needs to be
- *      unique for each call to encrypt. The explicit IV is shared with the
- *      other end of the transaction in the clear.
- *   3. The counter. Each block of data is encrypted with its own sequence
- *      number counter.
- */
 
 #if defined(HAVE_COLDFIRE_SEC)
@@ -3282,11 +3274,17 @@
 #endif
 
-enum {
-    NONCE_SZ = 12,
-    CTR_SZ   = 4
-};
+#ifdef WOLFSSL_ARMASM
+    /* implementation is located in wolfcrypt/src/port/arm/armv8-aes.c */
+
+#elif defined(WOLFSSL_AFALG)
+    /* implemented in wolfcrypt/src/port/afalg/afalg_aes.c */
+
+#elif defined(WOLFSSL_DEVCRYPTO_AES)
+    /* implemented in wolfcrypt/src/port/devcrypt/devcrypto_aes.c */
+
+#else /* software + AESNI implementation */
 
 #if !defined(FREESCALE_LTC_AES_GCM)
-static INLINE void IncrementGcmCounter(byte* inOutCtr)
+static WC_INLINE void IncrementGcmCounter(byte* inOutCtr)
 {
     int i;
@@ -3302,5 +3300,5 @@
 #if defined(GCM_SMALL) || defined(GCM_TABLE)
 
-static INLINE void FlattenSzInBits(byte* buf, word32 sz)
+static WC_INLINE void FlattenSzInBits(byte* buf, word32 sz)
 {
     /* Multiply the sz by 8 */
@@ -3320,5 +3318,5 @@
 
 
-static INLINE void RIGHTSHIFTX(byte* x)
+static WC_INLINE void RIGHTSHIFTX(byte* x)
 {
     int i;
@@ -3364,9 +3362,26 @@
 #endif /* GCM_TABLE */
 
-
+/* Software AES - GCM SetKey */
 int wc_AesGcmSetKey(Aes* aes, const byte* key, word32 len)
 {
     int  ret;
     byte iv[AES_BLOCK_SIZE];
+
+    #ifdef WOLFSSL_IMX6_CAAM_BLOB
+        byte   local[32];
+        word32 localSz = 32;
+
+        if (len == (16 + WC_CAAM_BLOB_SZ) ||
+          len == (24 + WC_CAAM_BLOB_SZ) ||
+          len == (32 + WC_CAAM_BLOB_SZ)) {
+            if (wc_caamOpenBlob((byte*)key, len, local, &localSz) != 0) {
+                 return BAD_FUNC_ARG;
+            }
+
+            /* set local values */
+            key = local;
+            len = localSz;
+        }
+    #endif
 
     if (!((len == 16) || (len == 24) || (len == 32)))
@@ -3393,4 +3408,8 @@
 #if defined(WOLFSSL_XILINX_CRYPT)
     wc_AesGcmSetKey_ex(aes, key, len, XSECURE_CSU_AES_KEY_SRC_KUP);
+#endif
+
+#ifdef WOLFSSL_IMX6_CAAM_BLOB
+    ForceZero(local, sizeof(local));
 #endif
 
@@ -3416,42 +3435,3294 @@
 #endif
 
-static const __m128i MOD2_128 = M128_INIT(0x1, 0xc200000000000000UL);
+static const __m128i MOD2_128 = M128_INIT(0x1,
+                                           (long long int)0xc200000000000000UL);
+
+
+/* See Intel® Carry-Less Multiplication Instruction
+ * and its Usage for Computing the GCM Mode White Paper
+ * by Shay Gueron, Intel Mobility Group, Israel Development Center;
+ * and Michael E. Kounavis, Intel Labs, Circuits and Systems Research */
+
+
+/* Figure 9. AES-GCM – Encrypt With Single Block Ghash at a Time */
+
+static const __m128i ONE   = M128_INIT(0x0, 0x1);
+#ifndef AES_GCM_AESNI_NO_UNROLL
+static const __m128i TWO   = M128_INIT(0x0, 0x2);
+static const __m128i THREE = M128_INIT(0x0, 0x3);
+static const __m128i FOUR  = M128_INIT(0x0, 0x4);
+static const __m128i FIVE  = M128_INIT(0x0, 0x5);
+static const __m128i SIX   = M128_INIT(0x0, 0x6);
+static const __m128i SEVEN = M128_INIT(0x0, 0x7);
+static const __m128i EIGHT = M128_INIT(0x0, 0x8);
+#endif
+static const __m128i BSWAP_EPI64 = M128_INIT(0x0001020304050607, 0x08090a0b0c0d0e0f);
+static const __m128i BSWAP_MASK  = M128_INIT(0x08090a0b0c0d0e0f, 0x0001020304050607);
+
+
+#ifndef _MSC_VER
+
+#define _VAR(a) "" #a ""
+#define VAR(a) _VAR(a)
+
+#define HR     %%xmm14
+#define XR     %%xmm15
+#define KR     %%ebx
+#define KR64   %%rbx
+#if !defined(AES_GCM_AESNI_NO_UNROLL) && !defined(AES_GCM_AVX1_NO_UNROLL)
+#define CTR1   128(%%rsp)
+#define TR     144(%%rsp)
+#define HTR    %%rsp
+#define STACK_OFFSET    160
+#else
+#define CTR1   (%%rsp)
+#define TR     16(%%rsp)
+#define STACK_OFFSET    32
+#endif
+
+#define AESENC()                      \
+    "aesenc	%%xmm12, %%xmm4\n\t"  \
+    "aesenc	%%xmm12, %%xmm5\n\t"  \
+    "aesenc	%%xmm12, %%xmm6\n\t"  \
+    "aesenc	%%xmm12, %%xmm7\n\t"  \
+    "aesenc	%%xmm12, %%xmm8\n\t"  \
+    "aesenc	%%xmm12, %%xmm9\n\t"  \
+    "aesenc	%%xmm12, %%xmm10\n\t" \
+    "aesenc	%%xmm12, %%xmm11\n\t"
+
+#define AESENC_SET(o)                        \
+    "movdqa	" #o "(%[KEY]), %%xmm12\n\t" \
+    AESENC()
+
+#define AESENC_CTR()                        \
+    "movdqu	" VAR(CTR1) ", %%xmm4\n\t"  \
+    "movdqa	%[BSWAP_EPI64], %%xmm1\n\t" \
+    "movdqu	%%xmm4, %%xmm0\n\t"         \
+    "pshufb	%%xmm1, %%xmm4\n\t"         \
+    "movdqa	%%xmm0, %%xmm5\n\t"         \
+    "paddd	%[ONE], %%xmm5\n\t"         \
+    "pshufb	%%xmm1, %%xmm5\n\t"         \
+    "movdqa	%%xmm0, %%xmm6\n\t"         \
+    "paddd	%[TWO], %%xmm6\n\t"         \
+    "pshufb	%%xmm1, %%xmm6\n\t"         \
+    "movdqa	%%xmm0, %%xmm7\n\t"         \
+    "paddd	%[THREE], %%xmm7\n\t"       \
+    "pshufb	%%xmm1, %%xmm7\n\t"         \
+    "movdqa	%%xmm0, %%xmm8\n\t"         \
+    "paddd	%[FOUR], %%xmm8\n\t"        \
+    "pshufb	%%xmm1, %%xmm8\n\t"         \
+    "movdqa	%%xmm0, %%xmm9\n\t"         \
+    "paddd	%[FIVE], %%xmm9\n\t"        \
+    "pshufb	%%xmm1, %%xmm9\n\t"         \
+    "movdqa	%%xmm0, %%xmm10\n\t"        \
+    "paddd	%[SIX], %%xmm10\n\t"        \
+    "pshufb	%%xmm1, %%xmm10\n\t"        \
+    "movdqa	%%xmm0, %%xmm11\n\t"        \
+    "paddd	%[SEVEN], %%xmm11\n\t"      \
+    "pshufb	%%xmm1, %%xmm11\n\t"        \
+    "paddd	%[EIGHT], %%xmm0\n\t"
+
+#define AESENC_XOR()                       \
+    "movdqa	(%[KEY]), %%xmm12\n\t"     \
+    "movdqu	%%xmm0, " VAR(CTR1) "\n\t" \
+    "pxor	%%xmm12, %%xmm4\n\t"       \
+    "pxor	%%xmm12, %%xmm5\n\t"       \
+    "pxor	%%xmm12, %%xmm6\n\t"       \
+    "pxor	%%xmm12, %%xmm7\n\t"       \
+    "pxor	%%xmm12, %%xmm8\n\t"       \
+    "pxor	%%xmm12, %%xmm9\n\t"       \
+    "pxor	%%xmm12, %%xmm10\n\t"      \
+    "pxor	%%xmm12, %%xmm11\n\t"
+
+/* Encrypt and carry-less multiply for AVX1. */
+#define AESENC_PCLMUL_1(src, o1, o2, o3)            \
+    "movdqu	" #o3 "(" VAR(HTR) "), %%xmm12\n\t" \
+    "movdqu	" #o2 "(" #src "), %%xmm0\n\t"      \
+    "aesenc	" #o1 "(%[KEY]), %%xmm4\n\t"        \
+    "pshufb	%[BSWAP_MASK], %%xmm0\n\t"          \
+    "pxor	%%xmm2, %%xmm0\n\t"                 \
+    "pshufd	$0x4e, %%xmm12, %%xmm1\n\t"         \
+    "pshufd	$0x4e, %%xmm0, %%xmm14\n\t"         \
+    "pxor	%%xmm12, %%xmm1\n\t"                \
+    "pxor	%%xmm0, %%xmm14\n\t"                \
+    "movdqa	%%xmm0, %%xmm3\n\t"                 \
+    "pclmulqdq	$0x11, %%xmm12, %%xmm3\n\t"         \
+    "aesenc	" #o1 "(%[KEY]), %%xmm5\n\t"        \
+    "aesenc	" #o1 "(%[KEY]), %%xmm6\n\t"        \
+    "movdqa	%%xmm0, %%xmm2\n\t"                 \
+    "pclmulqdq	$0x00, %%xmm12, %%xmm2\n\t"         \
+    "aesenc	" #o1 "(%[KEY]), %%xmm7\n\t"        \
+    "aesenc	" #o1 "(%[KEY]), %%xmm8\n\t"        \
+    "pclmulqdq	$0x00, %%xmm14, %%xmm1\n\t"         \
+    "aesenc	" #o1 "(%[KEY]), %%xmm9\n\t"        \
+    "aesenc	" #o1 "(%[KEY]), %%xmm10\n\t"       \
+    "aesenc	" #o1 "(%[KEY]), %%xmm11\n\t"       \
+    "pxor      %%xmm2, %%xmm1\n\t"                  \
+    "pxor      %%xmm3, %%xmm1\n\t"                  \
+
+#define AESENC_PCLMUL_N(src, o1, o2, o3)            \
+    "movdqu	" #o3 "(" VAR(HTR) "), %%xmm12\n\t" \
+    "movdqu	" #o2 "(" #src" ), %%xmm0\n\t"      \
+    "pshufd	$0x4e, %%xmm12, %%xmm13\n\t"        \
+    "pshufb	%[BSWAP_MASK], %%xmm0\n\t"          \
+    "aesenc	" #o1 "(%[KEY]), %%xmm4\n\t"        \
+    "pxor	%%xmm12, %%xmm13\n\t"               \
+    "pshufd	$0x4e, %%xmm0, %%xmm14\n\t"         \
+    "pxor	%%xmm0, %%xmm14\n\t"                \
+    "movdqa	%%xmm0, %%xmm15\n\t"                \
+    "pclmulqdq	$0x11, %%xmm12, %%xmm15\n\t"        \
+    "aesenc	" #o1 "(%[KEY]), %%xmm5\n\t"        \
+    "aesenc	" #o1 "(%[KEY]), %%xmm6\n\t"        \
+    "pclmulqdq	$0x00, %%xmm0, %%xmm12\n\t"         \
+    "aesenc	" #o1 "(%[KEY]), %%xmm7\n\t"        \
+    "aesenc	" #o1 "(%[KEY]), %%xmm8\n\t"        \
+    "pclmulqdq	$0x00, %%xmm14, %%xmm13\n\t"        \
+    "aesenc	" #o1 "(%[KEY]), %%xmm9\n\t"        \
+    "aesenc	" #o1 "(%[KEY]), %%xmm10\n\t"       \
+    "aesenc	" #o1 "(%[KEY]), %%xmm11\n\t"       \
+    "pxor      %%xmm12, %%xmm1\n\t"                 \
+    "pxor      %%xmm12, %%xmm2\n\t"                 \
+    "pxor      %%xmm15, %%xmm1\n\t"                 \
+    "pxor      %%xmm15, %%xmm3\n\t"                 \
+    "pxor      %%xmm13, %%xmm1\n\t"                 \
+
+#define AESENC_PCLMUL_L(o)                   \
+    "movdqa	%%xmm1, %%xmm14\n\t"         \
+    "psrldq	$8, %%xmm1\n\t"              \
+    "pslldq	$8, %%xmm14\n\t"             \
+    "aesenc	" #o "(%[KEY]), %%xmm4\n\t"  \
+    "pxor      %%xmm14, %%xmm2\n\t"          \
+    "pxor      %%xmm1, %%xmm3\n\t"           \
+    "movdqa	%%xmm2, %%xmm12\n\t"         \
+    "movdqa	%%xmm2, %%xmm13\n\t"         \
+    "movdqa	%%xmm2, %%xmm14\n\t"         \
+    "aesenc	" #o "(%[KEY]), %%xmm5\n\t"  \
+    "pslld	$31, %%xmm12\n\t"            \
+    "pslld	$30, %%xmm13\n\t"            \
+    "pslld	$25, %%xmm14\n\t"            \
+    "aesenc	" #o "(%[KEY]), %%xmm6\n\t"  \
+    "pxor	%%xmm13, %%xmm12\n\t"        \
+    "pxor	%%xmm14, %%xmm12\n\t"        \
+    "aesenc	" #o "(%[KEY]), %%xmm7\n\t"  \
+    "movdqa	%%xmm12, %%xmm13\n\t"        \
+    "pslldq	$12, %%xmm12\n\t"            \
+    "psrldq	$4, %%xmm13\n\t"             \
+    "aesenc	" #o "(%[KEY]), %%xmm8\n\t"  \
+    "pxor	%%xmm12, %%xmm2\n\t"         \
+    "movdqa	%%xmm2, %%xmm14\n\t"         \
+    "movdqa	%%xmm2, %%xmm1\n\t"          \
+    "movdqa	%%xmm2, %%xmm0\n\t"          \
+    "aesenc	" #o "(%[KEY]), %%xmm9\n\t"  \
+    "psrld	$1, %%xmm14\n\t"             \
+    "psrld	$2, %%xmm1\n\t"              \
+    "psrld	$7, %%xmm0\n\t"              \
+    "aesenc	" #o "(%[KEY]), %%xmm10\n\t" \
+    "pxor	%%xmm1, %%xmm14\n\t"         \
+    "pxor	%%xmm0, %%xmm14\n\t"         \
+    "aesenc	" #o "(%[KEY]), %%xmm11\n\t" \
+    "pxor	%%xmm13, %%xmm14\n\t"        \
+    "pxor	%%xmm14, %%xmm2\n\t"         \
+    "pxor	%%xmm3, %%xmm2\n\t"          \
+
+/* Encrypt and carry-less multiply with last key. */
+#define AESENC_LAST(in, out)                \
+    "aesenclast	%%xmm12, %%xmm4\n\t"        \
+    "aesenclast	%%xmm12, %%xmm5\n\t"        \
+    "movdqu	   (" #in "),%%xmm0\n\t"    \
+    "movdqu	 16(" #in "),%%xmm1\n\t"    \
+    "pxor	%%xmm0, %%xmm4\n\t"         \
+    "pxor	%%xmm1, %%xmm5\n\t"         \
+    "movdqu	%%xmm4,    (" #out ")\n\t"  \
+    "movdqu	%%xmm5,  16(" #out ")\n\t"  \
+    "aesenclast	%%xmm12, %%xmm6\n\t"        \
+    "aesenclast	%%xmm12, %%xmm7\n\t"        \
+    "movdqu	 32(" #in "),%%xmm0\n\t"    \
+    "movdqu	 48(" #in "),%%xmm1\n\t"    \
+    "pxor	%%xmm0, %%xmm6\n\t"         \
+    "pxor	%%xmm1, %%xmm7\n\t"         \
+    "movdqu	%%xmm6,  32(" #out ")\n\t"  \
+    "movdqu	%%xmm7,  48(" #out ")\n\t"  \
+    "aesenclast	%%xmm12, %%xmm8\n\t"        \
+    "aesenclast	%%xmm12, %%xmm9\n\t"        \
+    "movdqu	 64(" #in "),%%xmm0\n\t"    \
+    "movdqu	 80(" #in "),%%xmm1\n\t"    \
+    "pxor	%%xmm0, %%xmm8\n\t"         \
+    "pxor	%%xmm1, %%xmm9\n\t"         \
+    "movdqu	%%xmm8,  64(" #out ")\n\t"  \
+    "movdqu	%%xmm9,  80(" #out ")\n\t"  \
+    "aesenclast	%%xmm12, %%xmm10\n\t"       \
+    "aesenclast	%%xmm12, %%xmm11\n\t"       \
+    "movdqu	 96(" #in "),%%xmm0\n\t"    \
+    "movdqu	112(" #in "),%%xmm1\n\t"    \
+    "pxor	%%xmm0, %%xmm10\n\t"        \
+    "pxor	%%xmm1, %%xmm11\n\t"        \
+    "movdqu	%%xmm10,  96(" #out ")\n\t" \
+    "movdqu	%%xmm11, 112(" #out ")\n\t"
+
+#define _AESENC_AVX(r)                    \
+    "aesenc	16(%[KEY]), " #r "\n\t"   \
+    "aesenc	32(%[KEY]), " #r "\n\t"   \
+    "aesenc	48(%[KEY]), " #r "\n\t"   \
+    "aesenc	64(%[KEY]), " #r "\n\t"   \
+    "aesenc	80(%[KEY]), " #r "\n\t"   \
+    "aesenc	96(%[KEY]), " #r "\n\t"   \
+    "aesenc	112(%[KEY]), " #r "\n\t"  \
+    "aesenc	128(%[KEY]), " #r "\n\t"  \
+    "aesenc	144(%[KEY]), " #r "\n\t"  \
+    "cmpl	$11, %[nr]\n\t"           \
+    "movdqa	160(%[KEY]), %%xmm5\n\t"  \
+    "jl		%=f\n\t"                  \
+    "aesenc	%%xmm5, " #r "\n\t"       \
+    "aesenc	176(%[KEY]), " #r "\n\t"  \
+    "cmpl	$13, %[nr]\n\t"           \
+    "movdqa	192(%[KEY]), %%xmm5\n\t"  \
+    "jl		%=f\n\t"                  \
+    "aesenc	%%xmm5, " #r "\n\t"       \
+    "aesenc	208(%[KEY]), " #r "\n\t"  \
+    "movdqa	224(%[KEY]), %%xmm5\n\t"  \
+    "%=:\n\t"                             \
+    "aesenclast	%%xmm5, " #r "\n\t"
+#define AESENC_AVX(r)                     \
+        _AESENC_AVX(r)
+
+#define AESENC_BLOCK(in, out)               \
+    "movdqu	" VAR(CTR1) ", %%xmm4\n\t"  \
+    "movdqu	%%xmm4, %%xmm5\n\t"         \
+    "pshufb	%[BSWAP_EPI64], %%xmm4\n\t" \
+    "paddd	%[ONE], %%xmm5\n\t"         \
+    "pxor	(%[KEY]), %%xmm4\n\t"       \
+    "movdqu	%%xmm5, " VAR(CTR1) "\n\t"  \
+    AESENC_AVX(%%xmm4)                      \
+    "movdqu	(" #in "), %%xmm5\n\t"      \
+    "pxor	%%xmm5, %%xmm4\n\t"         \
+    "movdqu	%%xmm4, (" #out ")\n\t"     \
+    "pshufb	%[BSWAP_MASK], %%xmm4\n\t"  \
+    "pxor	%%xmm4, " VAR(XR) "\n\t"
+
+#define _AESENC_GFMUL(in, out, H, X)            \
+    "movdqu	" VAR(CTR1) ", %%xmm4\n\t"      \
+    "movdqu	%%xmm4, %%xmm5\n\t"             \
+    "pshufb	%[BSWAP_EPI64], %%xmm4\n\t"     \
+    "paddd	%[ONE], %%xmm5\n\t"             \
+    "pxor	(%[KEY]), %%xmm4\n\t"           \
+    "movdqu	%%xmm5, " VAR(CTR1) "\n\t"      \
+    "movdqa	" #X ", %%xmm6\n\t"             \
+    "pclmulqdq	$0x10, " #H ", %%xmm6\n\t"      \
+    "aesenc	16(%[KEY]), %%xmm4\n\t"         \
+    "aesenc	32(%[KEY]), %%xmm4\n\t"         \
+    "movdqa	" #X ", %%xmm7\n\t"             \
+    "pclmulqdq	$0x01, " #H ", %%xmm7\n\t"      \
+    "aesenc	48(%[KEY]), %%xmm4\n\t"         \
+    "aesenc	64(%[KEY]), %%xmm4\n\t"         \
+    "movdqa	" #X ", %%xmm8\n\t"             \
+    "pclmulqdq	$0x00, " #H ", %%xmm8\n\t"      \
+    "aesenc	80(%[KEY]), %%xmm4\n\t"         \
+    "movdqa	" #X ", %%xmm1\n\t"             \
+    "pclmulqdq	$0x11, " #H ", %%xmm1\n\t"      \
+    "aesenc	96(%[KEY]), %%xmm4\n\t"         \
+    "pxor	%%xmm7, %%xmm6\n\t"             \
+    "movdqa	%%xmm6, %%xmm2\n\t"             \
+    "psrldq	$8, %%xmm6\n\t"                 \
+    "pslldq	$8, %%xmm2\n\t"                 \
+    "aesenc	112(%[KEY]), %%xmm4\n\t"        \
+    "movdqa	%%xmm1, %%xmm3\n\t"             \
+    "pxor	%%xmm8, %%xmm2\n\t"             \
+    "pxor	%%xmm6, %%xmm3\n\t"             \
+    "movdqa	%[MOD2_128], %%xmm0\n\t"        \
+    "movdqa	%%xmm2, %%xmm7\n\t"             \
+    "pclmulqdq	$0x10, %%xmm0, %%xmm7\n\t"      \
+    "aesenc	128(%[KEY]), %%xmm4\n\t"        \
+    "pshufd	$0x4e, %%xmm2, %%xmm6\n\t"      \
+    "pxor	%%xmm7, %%xmm6\n\t"             \
+    "movdqa	%%xmm6, %%xmm7\n\t"             \
+    "pclmulqdq	$0x10, %%xmm0, %%xmm7\n\t"      \
+    "aesenc	144(%[KEY]), %%xmm4\n\t"        \
+    "pshufd	$0x4e, %%xmm6, " VAR(XR) "\n\t" \
+    "pxor	%%xmm7, " VAR(XR) "\n\t"        \
+    "pxor	%%xmm3, " VAR(XR) "\n\t"        \
+    "cmpl	$11, %[nr]\n\t"                 \
+    "movdqu	160(%[KEY]), %%xmm5\n\t"        \
+    "jl		%=f\n\t"                        \
+    "aesenc	%%xmm5, %%xmm4\n\t"             \
+    "aesenc	176(%[KEY]), %%xmm4\n\t"        \
+    "cmpl	$13, %[nr]\n\t"                 \
+    "movdqu	192(%[KEY]), %%xmm5\n\t"        \
+    "jl		%=f\n\t"                        \
+    "aesenc	%%xmm5, %%xmm4\n\t"             \
+    "aesenc	208(%[KEY]), %%xmm4\n\t"        \
+    "movdqa	224(%[KEY]), %%xmm5\n\t"        \
+    "%=:\n\t"                                   \
+    "aesenclast	%%xmm5, %%xmm4\n\t"             \
+    "movdqu	(" #in "), %%xmm5\n\t"          \
+    "pxor	%%xmm5, %%xmm4\n\t"             \
+    "movdqu	%%xmm4, (" #out ")\n\t"
+#define AESENC_GFMUL(in, out, H, X)             \
+       _AESENC_GFMUL(in, out, H, X)
+
+#define _GHASH_GFMUL_AVX(r, r2, a, b)      \
+    "pshufd	$0x4e, "#a", %%xmm1\n\t"   \
+    "pshufd	$0x4e, "#b", %%xmm2\n\t"   \
+    "movdqa	"#b", %%xmm3\n\t"          \
+    "movdqa	"#b", %%xmm0\n\t"          \
+    "pclmulqdq	$0x11, "#a", %%xmm3\n\t"   \
+    "pclmulqdq	$0x00, "#a", %%xmm0\n\t"   \
+    "pxor	"#a", %%xmm1\n\t"          \
+    "pxor	"#b", %%xmm2\n\t"          \
+    "pclmulqdq	$0x00, %%xmm2, %%xmm1\n\t" \
+    "pxor	%%xmm0, %%xmm1\n\t"        \
+    "pxor	%%xmm3, %%xmm1\n\t"        \
+    "movdqa	%%xmm1, %%xmm2\n\t"        \
+    "movdqa	%%xmm0, "#r2"\n\t"         \
+    "movdqa	%%xmm3, " #r "\n\t"        \
+    "pslldq	$8, %%xmm2\n\t"            \
+    "psrldq	$8, %%xmm1\n\t"            \
+    "pxor	%%xmm2, "#r2"\n\t"         \
+    "pxor	%%xmm1, " #r "\n\t"
+#define GHASH_GFMUL_AVX(r, r2, a, b)       \
+       _GHASH_GFMUL_AVX(r, r2, a, b)
+
+#define _GHASH_GFMUL_XOR_AVX(r, r2, a, b)  \
+    "pshufd	$0x4e, "#a", %%xmm1\n\t"   \
+    "pshufd	$0x4e, "#b", %%xmm2\n\t"   \
+    "movdqa	"#b", %%xmm3\n\t"          \
+    "movdqa	"#b", %%xmm0\n\t"          \
+    "pclmulqdq	$0x11, "#a", %%xmm3\n\t"   \
+    "pclmulqdq	$0x00, "#a", %%xmm0\n\t"   \
+    "pxor	"#a", %%xmm1\n\t"          \
+    "pxor	"#b", %%xmm2\n\t"          \
+    "pclmulqdq	$0x00, %%xmm2, %%xmm1\n\t" \
+    "pxor	%%xmm0, %%xmm1\n\t"        \
+    "pxor	%%xmm3, %%xmm1\n\t"        \
+    "movdqa	%%xmm1, %%xmm2\n\t"        \
+    "pxor	%%xmm0, "#r2"\n\t"         \
+    "pxor	%%xmm3, " #r "\n\t"        \
+    "pslldq	$8, %%xmm2\n\t"            \
+    "psrldq	$8, %%xmm1\n\t"            \
+    "pxor	%%xmm2, "#r2"\n\t"         \
+    "pxor	%%xmm1, " #r "\n\t"
+#define GHASH_GFMUL_XOR_AVX(r, r2, a, b)   \
+       _GHASH_GFMUL_XOR_AVX(r, r2, a, b)
+
+#define GHASH_MID_AVX(r, r2)        \
+    "movdqa	"#r2", %%xmm0\n\t"  \
+    "movdqa	" #r ", %%xmm1\n\t" \
+    "psrld	$31, %%xmm0\n\t"    \
+    "psrld	$31, %%xmm1\n\t"    \
+    "pslld	$1, "#r2"\n\t"      \
+    "pslld	$1, " #r "\n\t"     \
+    "movdqa	%%xmm0, %%xmm2\n\t" \
+    "pslldq	$4, %%xmm0\n\t"     \
+    "psrldq	$12, %%xmm2\n\t"    \
+    "pslldq	$4, %%xmm1\n\t"     \
+    "por	%%xmm2, " #r "\n\t" \
+    "por	%%xmm0, "#r2"\n\t"  \
+    "por	%%xmm1, " #r "\n\t"
+
+#define _GHASH_GFMUL_RED_AVX(r, a, b)      \
+    "pshufd	$0x4e, "#a", %%xmm5\n\t"   \
+    "pshufd	$0x4e, "#b", %%xmm6\n\t"   \
+    "movdqa	"#b", %%xmm7\n\t"          \
+    "movdqa	"#b", %%xmm4\n\t"          \
+    "pclmulqdq	$0x11, "#a", %%xmm7\n\t"   \
+    "pclmulqdq	$0x00, "#a", %%xmm4\n\t"   \
+    "pxor	"#a", %%xmm5\n\t"          \
+    "pxor	"#b", %%xmm6\n\t"          \
+    "pclmulqdq	$0x00, %%xmm6, %%xmm5\n\t" \
+    "pxor	%%xmm4, %%xmm5\n\t"        \
+    "pxor	%%xmm7, %%xmm5\n\t"        \
+    "movdqa	%%xmm5, %%xmm6\n\t"        \
+    "movdqa	%%xmm7, " #r "\n\t"        \
+    "pslldq	$8, %%xmm6\n\t"            \
+    "psrldq	$8, %%xmm5\n\t"            \
+    "pxor	%%xmm6, %%xmm4\n\t"        \
+    "pxor	%%xmm5, " #r "\n\t"        \
+    "movdqa	%%xmm4, %%xmm8\n\t"        \
+    "movdqa	%%xmm4, %%xmm9\n\t"        \
+    "movdqa	%%xmm4, %%xmm10\n\t"       \
+    "pslld	$31, %%xmm8\n\t"           \
+    "pslld	$30, %%xmm9\n\t"           \
+    "pslld	$25, %%xmm10\n\t"          \
+    "pxor	%%xmm9, %%xmm8\n\t"        \
+    "pxor	%%xmm10, %%xmm8\n\t"       \
+    "movdqa	%%xmm8, %%xmm9\n\t"        \
+    "psrldq	$4, %%xmm9\n\t"            \
+    "pslldq	$12, %%xmm8\n\t"           \
+    "pxor	%%xmm8, %%xmm4\n\t"        \
+    "movdqa	%%xmm4, %%xmm10\n\t"       \
+    "movdqa	%%xmm4, %%xmm6\n\t"        \
+    "movdqa	%%xmm4, %%xmm5\n\t"        \
+    "psrld	$1, %%xmm10\n\t"           \
+    "psrld	$2, %%xmm6\n\t"            \
+    "psrld	$7, %%xmm5\n\t"            \
+    "pxor	%%xmm6, %%xmm10\n\t"       \
+    "pxor	%%xmm5, %%xmm10\n\t"       \
+    "pxor	%%xmm9, %%xmm10\n\t"       \
+    "pxor	%%xmm4, %%xmm10\n\t"       \
+    "pxor	%%xmm10, " #r "\n\t"
+#define GHASH_GFMUL_RED_AVX(r, a, b)       \
+       _GHASH_GFMUL_RED_AVX(r, a, b)
+
+#define GHASH_RED_AVX(r, r2)           \
+    "movdqa	"#r2", %%xmm0\n\t"     \
+    "movdqa	"#r2", %%xmm1\n\t"     \
+    "movdqa	"#r2", %%xmm2\n\t"     \
+    "pslld	$31, %%xmm0\n\t"       \
+    "pslld	$30, %%xmm1\n\t"       \
+    "pslld	$25, %%xmm2\n\t"       \
+    "pxor	%%xmm1, %%xmm0\n\t"    \
+    "pxor	%%xmm2, %%xmm0\n\t"    \
+    "movdqa	%%xmm0, %%xmm1\n\t"    \
+    "psrldq	$4, %%xmm1\n\t"        \
+    "pslldq	$12, %%xmm0\n\t"       \
+    "pxor	%%xmm0, "#r2"\n\t"     \
+    "movdqa	"#r2", %%xmm2\n\t"     \
+    "movdqa	"#r2", %%xmm3\n\t"     \
+    "movdqa	"#r2", %%xmm0\n\t"     \
+    "psrld	$1, %%xmm2\n\t"        \
+    "psrld	$2, %%xmm3\n\t"        \
+    "psrld	$7, %%xmm0\n\t"        \
+    "pxor	%%xmm3, %%xmm2\n\t"    \
+    "pxor	%%xmm0, %%xmm2\n\t"    \
+    "pxor	%%xmm1, %%xmm2\n\t"    \
+    "pxor	"#r2", %%xmm2\n\t"     \
+    "pxor	%%xmm2, " #r "\n\t"
+
+#define GHASH_GFMUL_RED_XOR_AVX(r, r2, a, b) \
+    GHASH_GFMUL_XOR_AVX(r, r2, a, b)         \
+    GHASH_RED_AVX(r, r2)
+
+#define GHASH_FULL_AVX(r, r2, a, b) \
+    GHASH_GFMUL_AVX(r, r2, a, b)    \
+    GHASH_MID_AVX(r, r2)            \
+    GHASH_RED_AVX(r, r2)
+
+#define CALC_IV_12() \
+    "# Calculate values when IV is 12 bytes\n\t"      \
+    "# Set counter based on IV\n\t"                   \
+    "movl	$0x01000000, %%ecx\n\t"               \
+    "pinsrq	$0, 0(%%rax), %%xmm13\n\t"            \
+    "pinsrd	$2, 8(%%rax), %%xmm13\n\t"            \
+    "pinsrd	$3, %%ecx, %%xmm13\n\t"               \
+    "# H = Encrypt X(=0) and T = Encrypt counter\n\t" \
+    "movdqu	%%xmm13, %%xmm1\n\t"                  \
+    "movdqa	  0(%[KEY]), " VAR(HR) "\n\t"         \
+    "pxor	" VAR(HR) ", %%xmm1\n\t"              \
+    "movdqa	 16(%[KEY]), %%xmm12\n\t"             \
+    "aesenc	%%xmm12, " VAR(HR) "\n\t"             \
+    "aesenc	%%xmm12, %%xmm1\n\t"                  \
+    "movdqa	 32(%[KEY]), %%xmm12\n\t"             \
+    "aesenc	%%xmm12, " VAR(HR) "\n\t"             \
+    "aesenc	%%xmm12, %%xmm1\n\t"                  \
+    "movdqa	 48(%[KEY]), %%xmm12\n\t"             \
+    "aesenc	%%xmm12, " VAR(HR) "\n\t"             \
+    "aesenc	%%xmm12, %%xmm1\n\t"                  \
+    "movdqa	 64(%[KEY]), %%xmm12\n\t"             \
+    "aesenc	%%xmm12, " VAR(HR) "\n\t"             \
+    "aesenc	%%xmm12, %%xmm1\n\t"                  \
+    "movdqa	 80(%[KEY]), %%xmm12\n\t"             \
+    "aesenc	%%xmm12, " VAR(HR) "\n\t"             \
+    "aesenc	%%xmm12, %%xmm1\n\t"                  \
+    "movdqa	 96(%[KEY]), %%xmm12\n\t"             \
+    "aesenc	%%xmm12, " VAR(HR) "\n\t"             \
+    "aesenc	%%xmm12, %%xmm1\n\t"                  \
+    "movdqa	112(%[KEY]), %%xmm12\n\t"             \
+    "aesenc	%%xmm12, " VAR(HR) "\n\t"             \
+    "aesenc	%%xmm12, %%xmm1\n\t"                  \
+    "movdqa	128(%[KEY]), %%xmm12\n\t"             \
+    "aesenc	%%xmm12, " VAR(HR) "\n\t"             \
+    "aesenc	%%xmm12, %%xmm1\n\t"                  \
+    "movdqa	144(%[KEY]), %%xmm12\n\t"             \
+    "aesenc	%%xmm12, " VAR(HR) "\n\t"             \
+    "aesenc	%%xmm12, %%xmm1\n\t"                  \
+    "cmpl	$11, %[nr]\n\t"                       \
+    "movdqa	160(%[KEY]), %%xmm12\n\t"             \
+    "jl	31f\n\t"                                      \
+    "aesenc	%%xmm12, " VAR(HR) "\n\t"             \
+    "aesenc	%%xmm12, %%xmm1\n\t"                  \
+    "movdqa	176(%[KEY]), %%xmm12\n\t"             \
+    "aesenc	%%xmm12, " VAR(HR) "\n\t"             \
+    "aesenc	%%xmm12, %%xmm1\n\t"                  \
+    "cmpl	$13, %[nr]\n\t"                       \
+    "movdqa	192(%[KEY]), %%xmm12\n\t"             \
+    "jl	31f\n\t"                                      \
+    "aesenc	%%xmm12, " VAR(HR) "\n\t"             \
+    "aesenc	%%xmm12, %%xmm1\n\t"                  \
+    "movdqu	208(%[KEY]), %%xmm12\n\t"             \
+    "aesenc	%%xmm12, " VAR(HR) "\n\t"             \
+    "aesenc	%%xmm12, %%xmm1\n\t"                  \
+    "movdqu	224(%[KEY]), %%xmm12\n\t"             \
+    "31:\n\t"                                         \
+    "aesenclast	%%xmm12, " VAR(HR) "\n\t"             \
+    "aesenclast	%%xmm12, %%xmm1\n\t"                  \
+    "pshufb	%[BSWAP_MASK], " VAR(HR) "\n\t"       \
+    "movdqu	%%xmm1, " VAR(TR) "\n\t"              \
+    "jmp	39f\n\t"
+
+#define CALC_IV()                                    \
+    "# Calculate values when IV is not 12 bytes\n\t" \
+    "# H = Encrypt X(=0)\n\t"                        \
+    "movdqa	0(%[KEY]), " VAR(HR) "\n\t"          \
+    AESENC_AVX(HR)                                   \
+    "pshufb	%[BSWAP_MASK], " VAR(HR) "\n\t"      \
+    "# Calc counter\n\t"                             \
+    "# Initialization vector\n\t"                    \
+    "cmpl	$0, %%edx\n\t"                       \
+    "movq	$0, %%rcx\n\t"                       \
+    "je	45f\n\t"                                     \
+    "cmpl	$16, %%edx\n\t"                      \
+    "jl	44f\n\t"                                     \
+    "andl	$0xfffffff0, %%edx\n\t"              \
+    "\n"                                             \
+    "43:\n\t"                                        \
+    "movdqu	(%%rax,%%rcx,1), %%xmm4\n\t"         \
+    "pshufb	%[BSWAP_MASK], %%xmm4\n\t"           \
+    "pxor	%%xmm4, %%xmm13\n\t"                 \
+    GHASH_FULL_AVX(%%xmm13, %%xmm12, %%xmm13, HR)    \
+    "addl	$16, %%ecx\n\t"                      \
+    "cmpl	%%edx, %%ecx\n\t"                    \
+    "jl	43b\n\t"                                     \
+    "movl	%[ibytes], %%edx\n\t"                \
+    "cmpl	%%edx, %%ecx\n\t"                    \
+    "je	45f\n\t"                                     \
+    "\n"                                             \
+    "44:\n\t"                                        \
+    "subq	$16, %%rsp\n\t"                      \
+    "pxor	%%xmm4, %%xmm4\n\t"                  \
+    "xorl	%%ebx, %%ebx\n\t"                    \
+    "movdqu	%%xmm4, (%%rsp)\n\t"                 \
+    "42:\n\t"                                        \
+    "movzbl	(%%rax,%%rcx,1), %%r13d\n\t"         \
+    "movb	%%r13b, (%%rsp,%%rbx,1)\n\t"         \
+    "incl	%%ecx\n\t"                           \
+    "incl	%%ebx\n\t"                           \
+    "cmpl	%%edx, %%ecx\n\t"                    \
+    "jl	42b\n\t"                                     \
+    "movdqu	(%%rsp), %%xmm4\n\t"                 \
+    "addq	$16, %%rsp\n\t"                      \
+    "pshufb	%[BSWAP_MASK], %%xmm4\n\t"           \
+    "pxor	%%xmm4, %%xmm13\n\t"                 \
+    GHASH_FULL_AVX(%%xmm13, %%xmm12, %%xmm13, HR)    \
+    "\n"                                             \
+    "45:\n\t"                                        \
+    "# T = Encrypt counter\n\t"                      \
+    "pxor	%%xmm0, %%xmm0\n\t"                  \
+    "shll	$3, %%edx\n\t"                       \
+    "pinsrq	$0, %%rdx, %%xmm0\n\t"               \
+    "pxor	%%xmm0, %%xmm13\n\t"                 \
+    GHASH_FULL_AVX(%%xmm13, %%xmm12, %%xmm13, HR)    \
+    "pshufb	%[BSWAP_MASK], %%xmm13\n\t"          \
+    "#   Encrypt counter\n\t"                        \
+    "movdqa	0(%[KEY]), %%xmm4\n\t"               \
+    "pxor	%%xmm13, %%xmm4\n\t"                 \
+    AESENC_AVX(%%xmm4)                               \
+    "movdqu	%%xmm4, " VAR(TR) "\n\t"
+
+#define CALC_AAD()                           \
+    "# Additional authentication data\n\t"   \
+    "movl	%[abytes], %%edx\n\t"        \
+    "cmpl	$0, %%edx\n\t"               \
+    "je		25f\n\t"                     \
+    "movq	%[addt], %%rax\n\t"          \
+    "xorl	%%ecx, %%ecx\n\t"            \
+    "cmpl	$16, %%edx\n\t"              \
+    "jl		24f\n\t"                     \
+    "andl	$0xfffffff0, %%edx\n\t"      \
+    "\n"                                     \
+    "23:\n\t"                                \
+    "movdqu	(%%rax,%%rcx,1), %%xmm4\n\t" \
+    "pshufb	%[BSWAP_MASK], %%xmm4\n\t"   \
+    "pxor	%%xmm4, " VAR(XR) "\n\t"     \
+    GHASH_FULL_AVX(XR, %%xmm12, XR, HR)      \
+    "addl	$16, %%ecx\n\t"              \
+    "cmpl	%%edx, %%ecx\n\t"            \
+    "jl		23b\n\t"                     \
+    "movl	%[abytes], %%edx\n\t"        \
+    "cmpl	%%edx, %%ecx\n\t"            \
+    "je		25f\n\t"                     \
+    "\n"                                     \
+    "24:\n\t"                                \
+    "subq	$16, %%rsp\n\t"              \
+    "pxor	%%xmm4, %%xmm4\n\t"          \
+    "xorl	%%ebx, %%ebx\n\t"            \
+    "movdqu	%%xmm4, (%%rsp)\n\t"         \
+    "22:\n\t"                                \
+    "movzbl	(%%rax,%%rcx,1), %%r13d\n\t" \
+    "movb	%%r13b, (%%rsp,%%rbx,1)\n\t" \
+    "incl	%%ecx\n\t"                   \
+    "incl	%%ebx\n\t"                   \
+    "cmpl	%%edx, %%ecx\n\t"            \
+    "jl		22b\n\t"                     \
+    "movdqu	(%%rsp), %%xmm4\n\t"         \
+    "addq	$16, %%rsp\n\t"              \
+    "pshufb	%[BSWAP_MASK], %%xmm4\n\t"   \
+    "pxor	%%xmm4, " VAR(XR) "\n\t"     \
+    GHASH_FULL_AVX(XR, %%xmm12, XR, HR)      \
+    "\n"                                     \
+    "25:\n\t"
+
+#define CALC_HT_8_AVX()                            \
+    "movdqa	" VAR(XR) ", %%xmm2\n\t"           \
+    "# H ^ 1\n\t"                                  \
+    "movdqu	" VAR(HR) ", 0(" VAR(HTR) ")\n\t"  \
+    "# H ^ 2\n\t"                                  \
+    GHASH_GFMUL_RED_AVX(%%xmm0, HR, HR)            \
+    "movdqu	%%xmm0 ,  16(" VAR(HTR) ")\n\t"    \
+    "# H ^ 3\n\t"                                  \
+    GHASH_GFMUL_RED_AVX(%%xmm1, HR, %%xmm0)        \
+    "movdqu	%%xmm1 ,  32(" VAR(HTR) ")\n\t"    \
+    "# H ^ 4\n\t"                                  \
+    GHASH_GFMUL_RED_AVX(%%xmm3, %%xmm0, %%xmm0)    \
+    "movdqu	%%xmm3 ,  48(" VAR(HTR) ")\n\t"    \
+    "# H ^ 5\n\t"                                  \
+    GHASH_GFMUL_RED_AVX(%%xmm12, %%xmm0, %%xmm1)   \
+    "movdqu	%%xmm12,  64(" VAR(HTR) ")\n\t"    \
+    "# H ^ 6\n\t"                                  \
+    GHASH_GFMUL_RED_AVX(%%xmm12, %%xmm1, %%xmm1)   \
+    "movdqu	%%xmm12,  80(" VAR(HTR) ")\n\t"    \
+    "# H ^ 7\n\t"                                  \
+    GHASH_GFMUL_RED_AVX(%%xmm12, %%xmm1, %%xmm3)   \
+    "movdqu	%%xmm12,  96(" VAR(HTR) ")\n\t"    \
+    "# H ^ 8\n\t"                                  \
+    GHASH_GFMUL_RED_AVX(%%xmm12, %%xmm3, %%xmm3)   \
+    "movdqu	%%xmm12, 112(" VAR(HTR) ")\n\t"
+
+#define AESENC_128_GHASH_AVX(src, o)                 \
+    "leaq	(%[in]," VAR(KR64) ",1), %%rcx\n\t"  \
+    "leaq	(%[out]," VAR(KR64) ",1), %%rdx\n\t" \
+    /* src is either %%rcx or %%rdx */               \
+    AESENC_CTR()                                     \
+    AESENC_XOR()                                     \
+    AESENC_PCLMUL_1(src,  16, o-128, 112)            \
+    AESENC_PCLMUL_N(src,  32, o-112,  96)            \
+    AESENC_PCLMUL_N(src,  48, o -96,  80)            \
+    AESENC_PCLMUL_N(src,  64, o -80,  64)            \
+    AESENC_PCLMUL_N(src,  80, o -64,  48)            \
+    AESENC_PCLMUL_N(src,  96, o -48,  32)            \
+    AESENC_PCLMUL_N(src, 112, o -32,  16)            \
+    AESENC_PCLMUL_N(src, 128, o -16,   0)            \
+    AESENC_PCLMUL_L(144)                             \
+    "cmpl	$11, %[nr]\n\t"                      \
+    "movdqa	160(%[KEY]), %%xmm12\n\t"            \
+    "jl		4f\n\t"                              \
+    AESENC()                                         \
+    AESENC_SET(176)                                  \
+    "cmpl	$13, %[nr]\n\t"                      \
+    "movdqa	192(%[KEY]), %%xmm12\n\t"            \
+    "jl		4f\n\t"                              \
+    AESENC()                                         \
+    AESENC_SET(208)                                  \
+    "movdqa	224(%[KEY]), %%xmm12\n\t"            \
+    "\n"                                             \
+"4:\n\t"                                             \
+    AESENC_LAST(%%rcx, %%rdx)
+
+#define AESENC_LAST15_ENC_AVX()                       \
+    "movl	%[nbytes], %%ecx\n\t"                 \
+    "movl	%%ecx, %%edx\n\t"                     \
+    "andl	$0x0f, %%ecx\n\t"                     \
+    "jz		55f\n\t"                              \
+    "movdqu	" VAR(CTR1) ", %%xmm13\n\t"           \
+    "pshufb	%[BSWAP_EPI64], %%xmm13\n\t"          \
+    "pxor	0(%[KEY]), %%xmm13\n\t"               \
+    AESENC_AVX(%%xmm13)                               \
+    "subq	$16, %%rsp\n\t"                       \
+    "xorl	%%ecx, %%ecx\n\t"                     \
+    "movdqu	%%xmm13, (%%rsp)\n\t"                 \
+    "\n"                                              \
+    "51:\n\t"                                         \
+    "movzbl	(%[in]," VAR(KR64) ",1), %%r13d\n\t"  \
+    "xorb	(%%rsp,%%rcx,1), %%r13b\n\t"          \
+    "movb	%%r13b, (%[out]," VAR(KR64) ",1)\n\t" \
+    "movb	%%r13b, (%%rsp,%%rcx,1)\n\t"          \
+    "incl	" VAR(KR) "\n\t"                      \
+    "incl	%%ecx\n\t"                            \
+    "cmpl	%%edx, " VAR(KR) "\n\t"               \
+    "jl		51b\n\t"                              \
+    "xorq	%%r13, %%r13\n\t"                     \
+    "cmpl	$16, %%ecx\n\t"                       \
+    "je		53f\n\t"                              \
+    "\n"                                              \
+    "52:\n\t"                                         \
+    "movb	%%r13b, (%%rsp,%%rcx,1)\n\t"          \
+    "incl	%%ecx\n\t"                            \
+    "cmpl	$16, %%ecx\n\t"                       \
+    "jl		52b\n\t"                              \
+    "53:\n\t"                                         \
+    "movdqu	(%%rsp), %%xmm13\n\t"                 \
+    "addq	$16, %%rsp\n\t"                       \
+    "pshufb	%[BSWAP_MASK], %%xmm13\n\t"           \
+    "pxor	%%xmm13, " VAR(XR) "\n\t"             \
+    GHASH_GFMUL_RED_AVX(XR, HR, XR)                   \
+
+#define AESENC_LAST15_DEC_AVX()                       \
+    "movl	%[nbytes], %%ecx\n\t"                 \
+    "movl	%%ecx, %%edx\n\t"                     \
+    "andl	$0x0f, %%ecx\n\t"                     \
+    "jz		55f\n\t"                              \
+    "movdqu	" VAR(CTR1) ", %%xmm13\n\t"           \
+    "pshufb	%[BSWAP_EPI64], %%xmm13\n\t"          \
+    "pxor	0(%[KEY]), %%xmm13\n\t"               \
+    AESENC_AVX(%%xmm13)                               \
+    "subq	$32, %%rsp\n\t"                       \
+    "xorl	%%ecx, %%ecx\n\t"                     \
+    "movdqu	%%xmm13, (%%rsp)\n\t"                 \
+    "pxor	%%xmm0, %%xmm0\n\t"                   \
+    "movdqu	%%xmm0, 16(%%rsp)\n\t"                \
+    "\n"                                              \
+    "51:\n\t"                                         \
+    "movzbl	(%[in]," VAR(KR64) ",1), %%r13d\n\t"  \
+    "movb	%%r13b, 16(%%rsp,%%rcx,1)\n\t"        \
+    "xorb	(%%rsp,%%rcx,1), %%r13b\n\t"          \
+    "movb	%%r13b, (%[out]," VAR(KR64) ",1)\n\t" \
+    "incl	" VAR(KR) "\n\t"                      \
+    "incl	%%ecx\n\t"                            \
+    "cmpl	%%edx, " VAR(KR) "\n\t"               \
+    "jl		51b\n\t"                              \
+    "53:\n\t"                                         \
+    "movdqu	16(%%rsp), %%xmm13\n\t"               \
+    "addq	$32, %%rsp\n\t"                       \
+    "pshufb	%[BSWAP_MASK], %%xmm13\n\t"           \
+    "pxor	%%xmm13, " VAR(XR) "\n\t"             \
+    GHASH_GFMUL_RED_AVX(XR, HR, XR)                   \
+
+#define CALC_TAG()                              \
+    "movl	%[nbytes], %%edx\n\t"           \
+    "movl	%[abytes], %%ecx\n\t"           \
+    "shlq	$3, %%rdx\n\t"                  \
+    "shlq	$3, %%rcx\n\t"                  \
+    "pinsrq	$0, %%rdx, %%xmm0\n\t"          \
+    "pinsrq	$1, %%rcx, %%xmm0\n\t"          \
+    "pxor	%%xmm0, " VAR(XR) "\n\t"        \
+    GHASH_GFMUL_RED_AVX(XR, HR, XR)             \
+    "pshufb	%[BSWAP_MASK], " VAR(XR) "\n\t" \
+    "movdqu	" VAR(TR) ", %%xmm0\n\t"        \
+    "pxor	" VAR(XR) ", %%xmm0\n\t"        \
+
+#define STORE_TAG()                           \
+    "cmpl	$16, %[tbytes]\n\t"           \
+    "je		71f\n\t"                      \
+    "xorq	%%rcx, %%rcx\n\t"             \
+    "movdqu	%%xmm0, (%%rsp)\n\t"          \
+    "73:\n\t"                                 \
+    "movzbl	(%%rsp,%%rcx,1), %%r13d\n\t"  \
+    "movb	%%r13b, (%[tag],%%rcx,1)\n\t" \
+    "incl	%%ecx\n\t"                    \
+    "cmpl	%[tbytes], %%ecx\n\t"         \
+    "jne	73b\n\t"                      \
+    "jmp	72f\n\t"                      \
+    "\n"                                      \
+    "71:\n\t"                                 \
+    "movdqu	%%xmm0, (%[tag])\n\t"         \
+    "\n"                                      \
+    "72:\n\t"
+
+#define CMP_TAG()                                          \
+    "cmpl	$16, %[tbytes]\n\t"                        \
+    "je		71f\n\t"                                   \
+    "subq	$16, %%rsp\n\t"                            \
+    "xorq	%%rcx, %%rcx\n\t"                          \
+    "xorq	%%rax, %%rax\n\t"                          \
+    "movdqu	%%xmm0, (%%rsp)\n\t"                       \
+    "\n"                                                   \
+    "73:\n\t"                                              \
+    "movzbl	(%%rsp,%%rcx,1), %%r13d\n\t"               \
+    "xorb	(%[tag],%%rcx,1), %%r13b\n\t"              \
+    "orb	%%r13b, %%al\n\t"                          \
+    "incl	%%ecx\n\t"                                 \
+    "cmpl	%[tbytes], %%ecx\n\t"                      \
+    "jne	73b\n\t"                                   \
+    "cmpb	$0x00, %%al\n\t"                           \
+    "sete	%%al\n\t"                                  \
+    "addq	$16, %%rsp\n\t"                            \
+    "xorq	%%rcx, %%rcx\n\t"                          \
+    "jmp	72f\n\t"                                   \
+    "\n"                                                   \
+    "71:\n\t"                                              \
+    "movdqu	(%[tag]), %%xmm1\n\t"                      \
+    "pcmpeqb	%%xmm1, %%xmm0\n\t"                        \
+    "pmovmskb	%%xmm0, %%edx\n\t"                         \
+    "# %%edx == 0xFFFF then return 1 else => return 0\n\t" \
+    "xorl	%%eax, %%eax\n\t"                          \
+    "cmpl	$0xffff, %%edx\n\t"                        \
+    "sete	%%al\n\t"                                  \
+    "\n"                                                   \
+    "72:\n\t"                                              \
+    "movl	%%eax, (%[res])\n\t"
+
+static void AES_GCM_encrypt(const unsigned char *in, unsigned char *out,
+                            const unsigned char* addt,
+                            const unsigned char* ivec, unsigned char *tag,
+                            unsigned int nbytes, unsigned int abytes,
+                            unsigned int ibytes, unsigned int tbytes,
+                            const unsigned char* key, int nr)
+{
+    register const unsigned char* iv asm("rax") = ivec;
+    register unsigned int ivLen asm("ebx") = ibytes;
+
+    __asm__ __volatile__ (
+        "subq	$" VAR(STACK_OFFSET) ", %%rsp\n\t"
+        /* Counter is xmm13 */
+        "pxor	%%xmm13, %%xmm13\n\t"
+        "pxor	" VAR(XR) ", " VAR(XR) "\n\t"
+        "movl	%[ibytes], %%edx\n\t"
+        "cmpl	$12, %%edx\n\t"
+        "jne	35f\n\t"
+        CALC_IV_12()
+        "\n"
+        "35:\n\t"
+        CALC_IV()
+        "\n"
+        "39:\n\t"
+
+        CALC_AAD()
+
+        "# Calculate counter and H\n\t"
+        "pshufb	%[BSWAP_EPI64], %%xmm13\n\t"
+        "movdqa	" VAR(HR) ", %%xmm5\n\t"
+        "paddd	%[ONE], %%xmm13\n\t"
+        "movdqa	" VAR(HR) ", %%xmm4\n\t"
+        "movdqu	%%xmm13, " VAR(CTR1) "\n\t"
+        "psrlq	$63, %%xmm5\n\t"
+        "psllq	$1, %%xmm4\n\t"
+        "pslldq	$8, %%xmm5\n\t"
+        "por	%%xmm5, %%xmm4\n\t"
+        "pshufd	$0xff, " VAR(HR) ", " VAR(HR) "\n\t"
+        "psrad	$31, " VAR(HR) "\n\t"
+        "pand	%[MOD2_128], " VAR(HR) "\n\t"
+        "pxor	%%xmm4, " VAR(HR) "\n\t"
+
+        "xorl	" VAR(KR) ", " VAR(KR) "\n\t"
+
+#if !defined(AES_GCM_AESNI_NO_UNROLL) && !defined(AES_GCM_AVX1_NO_UNROLL)
+        "cmpl	$128, %[nbytes]\n\t"
+        "movl	%[nbytes], %%r13d\n\t"
+        "jl	5f\n\t"
+        "andl	$0xffffff80, %%r13d\n\t"
+
+        CALC_HT_8_AVX()
+
+        "# First 128 bytes of input\n\t"
+        AESENC_CTR()
+        AESENC_XOR()
+        AESENC_SET(16)
+        AESENC_SET(32)
+        AESENC_SET(48)
+        AESENC_SET(64)
+        AESENC_SET(80)
+        AESENC_SET(96)
+        AESENC_SET(112)
+        AESENC_SET(128)
+        AESENC_SET(144)
+        "cmpl	$11, %[nr]\n\t"
+        "movdqa	160(%[KEY]), %%xmm12\n\t"
+        "jl	1f\n\t"
+        AESENC()
+        AESENC_SET(176)
+        "cmpl	$13, %[nr]\n\t"
+        "movdqa	192(%[KEY]), %%xmm12\n\t"
+        "jl	1f\n\t"
+        AESENC()
+        AESENC_SET(208)
+        "movdqa	224(%[KEY]), %%xmm12\n\t"
+        "\n"
+    "1:\n\t"
+        AESENC_LAST(%[in], %[out])
+
+        "cmpl	$128, %%r13d\n\t"
+        "movl	$128, " VAR(KR) "\n\t"
+        "jle	2f\n\t"
+
+        "# More 128 bytes of input\n\t"
+        "\n"
+    "3:\n\t"
+        AESENC_128_GHASH_AVX(%%rdx, 0)
+        "addl	$128, " VAR(KR) "\n\t"
+        "cmpl	%%r13d, " VAR(KR) "\n\t"
+        "jl	3b\n\t"
+        "\n"
+    "2:\n\t"
+        "movdqa	%[BSWAP_MASK], %%xmm13\n\t"
+        "pshufb	%%xmm13, %%xmm4\n\t"
+        "pshufb	%%xmm13, %%xmm5\n\t"
+        "pshufb	%%xmm13, %%xmm6\n\t"
+        "pshufb	%%xmm13, %%xmm7\n\t"
+        "pxor	%%xmm2, %%xmm4\n\t"
+        "pshufb	%%xmm13, %%xmm8\n\t"
+        "pshufb	%%xmm13, %%xmm9\n\t"
+        "pshufb	%%xmm13, %%xmm10\n\t"
+        "pshufb	%%xmm13, %%xmm11\n\t"
+
+        "movdqu	112(" VAR(HTR) "), %%xmm12\n\t"
+        GHASH_GFMUL_AVX(XR, %%xmm13, %%xmm4, %%xmm12)
+        "movdqu	 96(" VAR(HTR) "), %%xmm12\n\t"
+        GHASH_GFMUL_XOR_AVX(XR, %%xmm13, %%xmm5, %%xmm12)
+        "movdqu	 80(" VAR(HTR) "), %%xmm12\n\t"
+        GHASH_GFMUL_XOR_AVX(XR, %%xmm13, %%xmm6, %%xmm12)
+        "movdqu	 64(" VAR(HTR) "), %%xmm12\n\t"
+        GHASH_GFMUL_XOR_AVX(XR, %%xmm13, %%xmm7, %%xmm12)
+        "movdqu	 48(" VAR(HTR) "), %%xmm12\n\t"
+        GHASH_GFMUL_XOR_AVX(XR, %%xmm13, %%xmm8, %%xmm12)
+        "movdqu	 32(" VAR(HTR) "), %%xmm12\n\t"
+        GHASH_GFMUL_XOR_AVX(XR, %%xmm13, %%xmm9, %%xmm12)
+        "movdqu	 16(" VAR(HTR) "), %%xmm12\n\t"
+        GHASH_GFMUL_XOR_AVX(XR, %%xmm13, %%xmm10, %%xmm12)
+        "movdqu	   (" VAR(HTR) "), %%xmm12\n\t"
+        GHASH_GFMUL_RED_XOR_AVX(XR, %%xmm13, %%xmm11, %%xmm12)
+
+        "movdqu	0(" VAR(HTR) "), " VAR(HR) "\n\t"
+        "\n"
+    "5:\n\t"
+        "movl	%[nbytes], %%edx\n\t"
+        "cmpl	%%edx, " VAR(KR) "\n\t"
+        "jge	55f\n\t"
+#endif
+
+        "movl	%[nbytes], %%r13d\n\t"
+        "andl	$0xfffffff0, %%r13d\n\t"
+        "cmpl	%%r13d, " VAR(KR) "\n\t"
+        "jge	14f\n\t"
+
+        "leaq	(%[in]," VAR(KR64) ",1), %%rcx\n\t"
+        "leaq	(%[out]," VAR(KR64) ",1), %%rdx\n\t"
+        AESENC_BLOCK(%%rcx, %%rdx)
+        "addl	$16, " VAR(KR) "\n\t"
+        "cmpl	%%r13d, " VAR(KR) "\n\t"
+        "jge	13f\n\t"
+        "\n"
+        "12:\n\t"
+        "leaq	(%[in]," VAR(KR64) ",1), %%rcx\n\t"
+        "leaq	(%[out]," VAR(KR64) ",1), %%rdx\n\t"
+        AESENC_GFMUL(%%rcx, %%rdx, HR, XR)
+        "pshufb	%[BSWAP_MASK], %%xmm4\n\t"
+        "pxor	%%xmm4, " VAR(XR) "\n\t"
+        "addl	$16, " VAR(KR) "\n\t"
+        "cmpl	%%r13d, " VAR(KR) "\n\t"
+        "jl	12b\n\t"
+        "\n"
+        "13:\n\t"
+        GHASH_GFMUL_RED_AVX(XR, HR, XR)
+        "\n"
+        "14:\n\t"
+
+        AESENC_LAST15_ENC_AVX()
+        "\n"
+        "55:\n\t"
+
+        CALC_TAG()
+        STORE_TAG()
+        "addq	$" VAR(STACK_OFFSET) ", %%rsp\n\t"
+
+        :
+        : [KEY] "r" (key),
+          [in] "r" (in), [out] "r" (out), [nr] "r" (nr),
+          [nbytes] "r" (nbytes), [abytes] "r" (abytes), [addt] "r" (addt),
+          [ivec] "r" (iv), [ibytes] "r" (ivLen), [tbytes] "r" (tbytes),
+          [tag] "r" (tag),
+          [BSWAP_MASK] "m" (BSWAP_MASK),
+          [BSWAP_EPI64] "m" (BSWAP_EPI64),
+          [ONE] "m" (ONE),
+#if !defined(AES_GCM_AESNI_NO_UNROLL) && !defined(AES_GCM_AVX1_NO_UNROLL)
+          [TWO] "m" (TWO), [THREE] "m" (THREE), [FOUR] "m" (FOUR),
+          [FIVE] "m" (FIVE), [SIX] "m" (SIX), [SEVEN] "m" (SEVEN),
+          [EIGHT] "m" (EIGHT),
+#endif
+          [MOD2_128] "m" (MOD2_128)
+        : "xmm15", "xmm14", "xmm13", "xmm12",
+          "xmm0", "xmm1", "xmm2", "xmm3", "memory",
+          "xmm4", "xmm5", "xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11",
+          "rcx", "rdx", "r13"
+    );
+}
+
+#ifdef HAVE_INTEL_AVX1
+/* Encrypt with key in xmm12. */
+#define VAESENC()                              \
+    "vaesenc	%%xmm12, %%xmm4, %%xmm4\n\t"   \
+    "vaesenc	%%xmm12, %%xmm5, %%xmm5\n\t"   \
+    "vaesenc	%%xmm12, %%xmm6, %%xmm6\n\t"   \
+    "vaesenc	%%xmm12, %%xmm7, %%xmm7\n\t"   \
+    "vaesenc	%%xmm12, %%xmm8, %%xmm8\n\t"   \
+    "vaesenc	%%xmm12, %%xmm9, %%xmm9\n\t"   \
+    "vaesenc	%%xmm12, %%xmm10, %%xmm10\n\t" \
+    "vaesenc	%%xmm12, %%xmm11, %%xmm11\n\t"
+
+#define VAESENC_SET(o)                         \
+    "vmovdqa	"#o"(%[KEY]), %%xmm12\n\t"     \
+    VAESENC()
+
+#define VAESENC_CTR()                          \
+    "vmovdqu	" VAR(CTR1) ", %%xmm0\n\t"     \
+    "vmovdqa	%[BSWAP_EPI64], %%xmm1\n\t"    \
+    "vpshufb	%%xmm1, %%xmm0, %%xmm4\n\t"    \
+    "vpaddd	%[ONE], %%xmm0, %%xmm5\n\t"    \
+    "vpshufb	%%xmm1, %%xmm5, %%xmm5\n\t"    \
+    "vpaddd	%[TWO], %%xmm0, %%xmm6\n\t"    \
+    "vpshufb	%%xmm1, %%xmm6, %%xmm6\n\t"    \
+    "vpaddd	%[THREE], %%xmm0, %%xmm7\n\t"  \
+    "vpshufb	%%xmm1, %%xmm7, %%xmm7\n\t"    \
+    "vpaddd	%[FOUR], %%xmm0, %%xmm8\n\t"   \
+    "vpshufb	%%xmm1, %%xmm8, %%xmm8\n\t"    \
+    "vpaddd	%[FIVE], %%xmm0, %%xmm9\n\t"   \
+    "vpshufb	%%xmm1, %%xmm9, %%xmm9\n\t"    \
+    "vpaddd	%[SIX], %%xmm0, %%xmm10\n\t"   \
+    "vpshufb	%%xmm1, %%xmm10, %%xmm10\n\t"  \
+    "vpaddd	%[SEVEN], %%xmm0, %%xmm11\n\t" \
+    "vpshufb	%%xmm1, %%xmm11, %%xmm11\n\t"  \
+    "vpaddd	%[EIGHT], %%xmm0, %%xmm0\n\t"
+
+#define VAESENC_XOR()                          \
+    "vmovdqa	(%[KEY]), %%xmm12\n\t"         \
+    "vmovdqu	%%xmm0, " VAR(CTR1) "\n\t"     \
+    "vpxor	%%xmm12, %%xmm4, %%xmm4\n\t"   \
+    "vpxor	%%xmm12, %%xmm5, %%xmm5\n\t"   \
+    "vpxor	%%xmm12, %%xmm6, %%xmm6\n\t"   \
+    "vpxor	%%xmm12, %%xmm7, %%xmm7\n\t"   \
+    "vpxor	%%xmm12, %%xmm8, %%xmm8\n\t"   \
+    "vpxor	%%xmm12, %%xmm9, %%xmm9\n\t"   \
+    "vpxor	%%xmm12, %%xmm10, %%xmm10\n\t" \
+    "vpxor	%%xmm12, %%xmm11, %%xmm11\n\t"
+
+#define VAESENC_128()                     \
+    VAESENC_CTR()                         \
+    VAESENC_XOR()                         \
+    VAESENC_SET(16)                       \
+    VAESENC_SET(32)                       \
+    VAESENC_SET(48)                       \
+    VAESENC_SET(64)                       \
+    VAESENC_SET(80)                       \
+    VAESENC_SET(96)                       \
+    VAESENC_SET(112)                      \
+    VAESENC_SET(128)                      \
+    VAESENC_SET(144)                      \
+    "cmpl	$11, %[nr]\n\t"           \
+    "vmovdqa	160(%[KEY]), %%xmm12\n\t" \
+    "jl	1f\n\t"                           \
+    VAESENC()                             \
+    VAESENC_SET(176)                      \
+    "cmpl	$13, %[nr]\n\t"           \
+    "vmovdqa	192(%[KEY]), %%xmm12\n\t" \
+    "jl	1f\n\t"                           \
+    VAESENC()                             \
+    VAESENC_SET(208)                      \
+    "vmovdqa	224(%[KEY]), %%xmm12\n\t" \
+    "\n"                                  \
+"1:\n\t"                                  \
+    VAESENC_LAST(%[in], %[out])
+
+/* Encrypt and carry-less multiply for AVX1. */
+#define VAESENC_PCLMUL_1(src, o1, o2, o3)              \
+    "vmovdqu	" #o3 "(" VAR(HTR) "), %%xmm12\n\t"    \
+    "vmovdqu	" #o2 "(" #src "), %%xmm0\n\t"         \
+    "vaesenc	" #o1 "(%[KEY]), %%xmm4, %%xmm4\n\t"   \
+    "vpshufb	%[BSWAP_MASK], %%xmm0, %%xmm0\n\t"     \
+    "vpxor	%%xmm2, %%xmm0, %%xmm0\n\t"            \
+    "vpshufd	$0x4e, %%xmm12, %%xmm1\n\t"            \
+    "vpshufd	$0x4e, %%xmm0, %%xmm14\n\t"            \
+    "vpxor	%%xmm12, %%xmm1, %%xmm1\n\t"           \
+    "vpxor	%%xmm0, %%xmm14, %%xmm14\n\t"          \
+    "vpclmulqdq	$0x11, %%xmm12, %%xmm0, %%xmm3\n\t"    \
+    "vaesenc	" #o1 "(%[KEY]), %%xmm5, %%xmm5\n\t"   \
+    "vaesenc	" #o1 "(%[KEY]), %%xmm6, %%xmm6\n\t"   \
+    "vpclmulqdq	$0x00, %%xmm12, %%xmm0, %%xmm2\n\t"    \
+    "vaesenc	" #o1 "(%[KEY]), %%xmm7, %%xmm7\n\t"   \
+    "vaesenc	" #o1 "(%[KEY]), %%xmm8, %%xmm8\n\t"   \
+    "vpclmulqdq	$0x00, %%xmm14, %%xmm1, %%xmm1\n\t"    \
+    "vaesenc	" #o1 "(%[KEY]), %%xmm9, %%xmm9\n\t"   \
+    "vaesenc	" #o1 "(%[KEY]), %%xmm10, %%xmm10\n\t" \
+    "vaesenc	" #o1 "(%[KEY]), %%xmm11, %%xmm11\n\t" \
+    "vpxor      %%xmm2, %%xmm1, %%xmm1\n\t"            \
+    "vpxor      %%xmm3, %%xmm1, %%xmm1\n\t"            \
+
+#define VAESENC_PCLMUL_N(src, o1, o2, o3)               \
+    "vmovdqu	" #o3 "(" VAR(HTR) "), %%xmm12\n\t"     \
+    "vmovdqu	" #o2 "(" #src "), %%xmm0\n\t"          \
+    "vpshufd	$0x4e, %%xmm12, %%xmm13\n\t"            \
+    "vpshufb	%[BSWAP_MASK], %%xmm0, %%xmm0\n\t"      \
+    "vaesenc	" #o1 "(%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "vpxor	%%xmm12, %%xmm13, %%xmm13\n\t"          \
+    "vpshufd	$0x4e, %%xmm0, %%xmm14\n\t"             \
+    "vpxor	%%xmm0, %%xmm14, %%xmm14\n\t"           \
+    "vpclmulqdq	$0x11, %%xmm12, %%xmm0, %%xmm15\n\t"    \
+    "vaesenc	" #o1 "(%[KEY]), %%xmm5, %%xmm5\n\t"    \
+    "vaesenc	" #o1 "(%[KEY]), %%xmm6, %%xmm6\n\t"    \
+    "vpclmulqdq	$0x00, %%xmm12, %%xmm0, %%xmm12\n\t"    \
+    "vaesenc	" #o1 "(%[KEY]), %%xmm7, %%xmm7\n\t"    \
+    "vaesenc	" #o1 "(%[KEY]), %%xmm8, %%xmm8\n\t"    \
+    "vpclmulqdq	$0x00, %%xmm14, %%xmm13, %%xmm13\n\t"   \
+    "vaesenc	" #o1 "(%[KEY]), %%xmm9, %%xmm9\n\t"    \
+    "vaesenc	" #o1 "(%[KEY]), %%xmm10, %%xmm10\n\t"  \
+    "vaesenc	" #o1 "(%[KEY]), %%xmm11, %%xmm11\n\t"  \
+    "vpxor      %%xmm12, %%xmm1, %%xmm1\n\t"            \
+    "vpxor      %%xmm12, %%xmm2, %%xmm2\n\t"            \
+    "vpxor      %%xmm15, %%xmm1, %%xmm1\n\t"            \
+    "vpxor      %%xmm15, %%xmm3, %%xmm3\n\t"            \
+    "vpxor      %%xmm13, %%xmm1, %%xmm1\n\t"            \
+
+#define VAESENC_PCLMUL_L(o)                         \
+    "vpslldq	$8, %%xmm1, %%xmm14\n\t"            \
+    "vpsrldq	$8, %%xmm1, %%xmm1\n\t"             \
+    "vaesenc	"#o"(%[KEY]), %%xmm4, %%xmm4\n\t"   \
+    "vpxor      %%xmm14, %%xmm2, %%xmm2\n\t"        \
+    "vpxor      %%xmm1, %%xmm3, %%xmm3\n\t"         \
+    "vaesenc	"#o"(%[KEY]), %%xmm5, %%xmm5\n\t"   \
+    "vpslld	$31, %%xmm2, %%xmm12\n\t"           \
+    "vpslld	$30, %%xmm2, %%xmm13\n\t"           \
+    "vpslld	$25, %%xmm2, %%xmm14\n\t"           \
+    "vaesenc	"#o"(%[KEY]), %%xmm6, %%xmm6\n\t"   \
+    "vpxor	%%xmm13, %%xmm12, %%xmm12\n\t"      \
+    "vpxor	%%xmm14, %%xmm12, %%xmm12\n\t"      \
+    "vaesenc	"#o"(%[KEY]), %%xmm7, %%xmm7\n\t"   \
+    "vpsrldq	$4, %%xmm12, %%xmm13\n\t"           \
+    "vpslldq	$12, %%xmm12, %%xmm12\n\t"          \
+    "vaesenc	"#o"(%[KEY]), %%xmm8, %%xmm8\n\t"   \
+    "vpxor	%%xmm12, %%xmm2, %%xmm2\n\t"        \
+    "vpsrld	$1, %%xmm2, %%xmm14\n\t"            \
+    "vaesenc	"#o"(%[KEY]), %%xmm9, %%xmm9\n\t"   \
+    "vpsrld	$2, %%xmm2, %%xmm1\n\t"             \
+    "vpsrld	$7, %%xmm2, %%xmm0\n\t"             \
+    "vaesenc	"#o"(%[KEY]), %%xmm10, %%xmm10\n\t" \
+    "vpxor	%%xmm1, %%xmm14, %%xmm14\n\t"       \
+    "vpxor	%%xmm0, %%xmm14, %%xmm14\n\t"       \
+    "vaesenc	"#o"(%[KEY]), %%xmm11, %%xmm11\n\t" \
+    "vpxor	%%xmm13, %%xmm14, %%xmm14\n\t"      \
+    "vpxor	%%xmm14, %%xmm2, %%xmm2\n\t"        \
+    "vpxor	%%xmm3, %%xmm2, %%xmm2\n\t"         \
+
+
+/* Encrypt and carry-less multiply with last key. */
+#define VAESENC_LAST(in, out)                          \
+    "vaesenclast	%%xmm12, %%xmm4, %%xmm4\n\t"   \
+    "vaesenclast	%%xmm12, %%xmm5, %%xmm5\n\t"   \
+    "vmovdqu		   (" #in "), %%xmm0\n\t"      \
+    "vmovdqu		 16(" #in "), %%xmm1\n\t"      \
+    "vpxor		%%xmm0, %%xmm4, %%xmm4\n\t"    \
+    "vpxor		%%xmm1, %%xmm5, %%xmm5\n\t"    \
+    "vmovdqu		%%xmm4,    (" #out ")\n\t"     \
+    "vmovdqu		%%xmm5,  16(" #out ")\n\t"     \
+    "vaesenclast	%%xmm12, %%xmm6, %%xmm6\n\t"   \
+    "vaesenclast	%%xmm12, %%xmm7, %%xmm7\n\t"   \
+    "vmovdqu		 32(" #in "), %%xmm0\n\t"      \
+    "vmovdqu		 48(" #in "), %%xmm1\n\t"      \
+    "vpxor		%%xmm0, %%xmm6, %%xmm6\n\t"    \
+    "vpxor		%%xmm1, %%xmm7, %%xmm7\n\t"    \
+    "vmovdqu		%%xmm6,  32(" #out ")\n\t"     \
+    "vmovdqu		%%xmm7,  48(" #out ")\n\t"     \
+    "vaesenclast	%%xmm12, %%xmm8, %%xmm8\n\t"   \
+    "vaesenclast	%%xmm12, %%xmm9, %%xmm9\n\t"   \
+    "vmovdqu		 64(" #in "), %%xmm0\n\t"      \
+    "vmovdqu		 80(" #in "), %%xmm1\n\t"      \
+    "vpxor		%%xmm0, %%xmm8, %%xmm8\n\t"    \
+    "vpxor		%%xmm1, %%xmm9, %%xmm9\n\t"    \
+    "vmovdqu		%%xmm8,  64(" #out ")\n\t"     \
+    "vmovdqu		%%xmm9,  80(" #out ")\n\t"     \
+    "vaesenclast	%%xmm12, %%xmm10, %%xmm10\n\t" \
+    "vaesenclast	%%xmm12, %%xmm11, %%xmm11\n\t" \
+    "vmovdqu		 96(" #in "), %%xmm0\n\t"      \
+    "vmovdqu		112(" #in "), %%xmm1\n\t"      \
+    "vpxor		%%xmm0, %%xmm10, %%xmm10\n\t"  \
+    "vpxor		%%xmm1, %%xmm11, %%xmm11\n\t"  \
+    "vmovdqu		%%xmm10,  96(" #out ")\n\t"    \
+    "vmovdqu		%%xmm11, 112(" #out ")\n\t"
+
+#define VAESENC_BLOCK()                                       \
+    "vmovdqu		" VAR(CTR1) ", %%xmm5\n\t"            \
+    "vpshufb		%[BSWAP_EPI64], %%xmm5, %%xmm4\n\t"   \
+    "vpaddd		%[ONE], %%xmm5, %%xmm5\n\t"           \
+    "vmovdqu		%%xmm5, " VAR(CTR1) "\n\t"            \
+    "vpxor		(%[KEY]), %%xmm4, %%xmm4\n\t"         \
+    "vaesenc		16(%[KEY]), %%xmm4, %%xmm4\n\t"       \
+    "vaesenc		32(%[KEY]), %%xmm4, %%xmm4\n\t"       \
+    "vaesenc		48(%[KEY]), %%xmm4, %%xmm4\n\t"       \
+    "vaesenc		64(%[KEY]), %%xmm4, %%xmm4\n\t"       \
+    "vaesenc		80(%[KEY]), %%xmm4, %%xmm4\n\t"       \
+    "vaesenc		96(%[KEY]), %%xmm4, %%xmm4\n\t"       \
+    "vaesenc		112(%[KEY]), %%xmm4, %%xmm4\n\t"      \
+    "vaesenc		128(%[KEY]), %%xmm4, %%xmm4\n\t"      \
+    "vaesenc		144(%[KEY]), %%xmm4, %%xmm4\n\t"      \
+    "cmpl		$11, %[nr]\n\t"                       \
+    "vmovdqa		160(%[KEY]), %%xmm5\n\t"              \
+    "jl			%=f\n\t"                              \
+    "vaesenc		%%xmm5, %%xmm4, %%xmm4\n\t"           \
+    "vaesenc		176(%[KEY]), %%xmm4, %%xmm4\n\t"      \
+    "cmpl		$13, %[nr]\n\t"                       \
+    "vmovdqa		192(%[KEY]), %%xmm5\n\t"              \
+    "jl			%=f\n\t"                              \
+    "vaesenc		%%xmm5, %%xmm4, %%xmm4\n\t"           \
+    "vaesenc		208(%[KEY]), %%xmm4, %%xmm4\n\t"      \
+    "vmovdqa		224(%[KEY]), %%xmm5\n\t"              \
+    "%=:\n\t"                                                 \
+    "vaesenclast	%%xmm5, %%xmm4, %%xmm4\n\t"           \
+    "vmovdqu		(%[in]," VAR(KR64) ",1), %%xmm5\n\t"  \
+    "vpxor		%%xmm5, %%xmm4, %%xmm4\n\t"           \
+    "vmovdqu		%%xmm4, (%[out]," VAR(KR64) ",1)\n\t" \
+    "vpshufb		%[BSWAP_MASK], %%xmm4, %%xmm4\n\t"    \
+    "vpxor		%%xmm4, " VAR(XR) ", " VAR(XR) "\n\t"
+
+#define _VAESENC_GFMUL(in, H, X)                              \
+    "vmovdqu		" VAR(CTR1) ", %%xmm5\n\t"            \
+    "vpshufb		%[BSWAP_EPI64], %%xmm5, %%xmm4\n\t"   \
+    "vpaddd		%[ONE], %%xmm5, %%xmm5\n\t"           \
+    "vmovdqu		%%xmm5, " VAR(CTR1) "\n\t"            \
+    "vpxor		(%[KEY]), %%xmm4, %%xmm4\n\t"         \
+    "vpclmulqdq		$0x10, " #H ", " #X ", %%xmm6\n\t"    \
+    "vaesenc		16(%[KEY]), %%xmm4, %%xmm4\n\t"       \
+    "vaesenc		32(%[KEY]), %%xmm4, %%xmm4\n\t"       \
+    "vpclmulqdq		$0x01, " #H ", " #X ", %%xmm7\n\t"    \
+    "vaesenc		48(%[KEY]), %%xmm4, %%xmm4\n\t"       \
+    "vaesenc		64(%[KEY]), %%xmm4, %%xmm4\n\t"       \
+    "vpclmulqdq		$0x00, " #H ", " #X ", %%xmm8\n\t"    \
+    "vaesenc		80(%[KEY]), %%xmm4, %%xmm4\n\t"       \
+    "vpclmulqdq		$0x11, " #H ", " #X ", %%xmm1\n\t"    \
+    "vaesenc		96(%[KEY]), %%xmm4, %%xmm4\n\t"       \
+    "vpxor		%%xmm7, %%xmm6, %%xmm6\n\t"           \
+    "vpslldq		$8, %%xmm6, %%xmm2\n\t"               \
+    "vpsrldq		$8, %%xmm6, %%xmm6\n\t"               \
+    "vaesenc		112(%[KEY]), %%xmm4, %%xmm4\n\t"      \
+    "vpxor		%%xmm8, %%xmm2, %%xmm2\n\t"           \
+    "vpxor		%%xmm6, %%xmm1, %%xmm3\n\t"           \
+    "vmovdqa		%[MOD2_128], %%xmm0\n\t"              \
+    "vpclmulqdq		$0x10, %%xmm0, %%xmm2, %%xmm7\n\t"    \
+    "vaesenc		128(%[KEY]), %%xmm4, %%xmm4\n\t"      \
+    "vpshufd		$0x4e, %%xmm2, %%xmm6\n\t"            \
+    "vpxor		%%xmm7, %%xmm6, %%xmm6\n\t"           \
+    "vpclmulqdq		$0x10, %%xmm0, %%xmm6, %%xmm7\n\t"    \
+    "vaesenc		144(%[KEY]), %%xmm4, %%xmm4\n\t"      \
+    "vpshufd		$0x4e, %%xmm6, %%xmm6\n\t"            \
+    "vpxor		%%xmm7, %%xmm6, %%xmm6\n\t"           \
+    "vpxor		%%xmm3, %%xmm6, " VAR(XR) "\n\t"      \
+    "cmpl		$11, %[nr]\n\t"                       \
+    "vmovdqa		160(%[KEY]), %%xmm5\n\t"              \
+    "jl			1f\n\t"                               \
+    "vaesenc		%%xmm5, %%xmm4, %%xmm4\n\t"           \
+    "vaesenc		176(%[KEY]), %%xmm4, %%xmm4\n\t"      \
+    "cmpl		$13, %[nr]\n\t"                       \
+    "vmovdqa		192(%[KEY]), %%xmm5\n\t"              \
+    "jl			1f\n\t"                               \
+    "vaesenc		%%xmm5, %%xmm4, %%xmm4\n\t"           \
+    "vaesenc		208(%[KEY]), %%xmm4, %%xmm4\n\t"      \
+    "vmovdqa		224(%[KEY]), %%xmm5\n\t"              \
+    "1:\n\t"                                                  \
+    "vaesenclast	%%xmm5, %%xmm4, %%xmm4\n\t"           \
+    "vmovdqu		" #in ", %%xmm0\n\t"                  \
+    "vpxor		%%xmm0, %%xmm4, %%xmm4\n\t"           \
+    "vmovdqu		%%xmm4, (%[out]," VAR(KR64) ",1)\n\t"
+#define VAESENC_GFMUL(in, H, X)                               \
+       _VAESENC_GFMUL(in, H, X)
+
+
+#define _GHASH_GFMUL_AVX1(r, r2, a, b)             \
+    "vpshufd	$0x4e, "#a", %%xmm1\n\t"           \
+    "vpshufd	$0x4e, "#b", %%xmm2\n\t"           \
+    "vpclmulqdq	$0x11, "#a", "#b", %%xmm3\n\t"     \
+    "vpclmulqdq	$0x00, "#a", "#b", %%xmm0\n\t"     \
+    "vpxor	"#a", %%xmm1, %%xmm1\n\t"          \
+    "vpxor	"#b", %%xmm2, %%xmm2\n\t"          \
+    "vpclmulqdq	$0x00, %%xmm2, %%xmm1, %%xmm1\n\t" \
+    "vpxor	%%xmm0, %%xmm1, %%xmm1\n\t"        \
+    "vpxor	%%xmm3, %%xmm1, %%xmm1\n\t"        \
+    "vmovdqa	%%xmm0, "#r2"\n\t"                 \
+    "vmovdqa	%%xmm3, " #r "\n\t"                \
+    "vpslldq	$8, %%xmm1, %%xmm2\n\t"            \
+    "vpsrldq	$8, %%xmm1, %%xmm1\n\t"            \
+    "vpxor	%%xmm2, "#r2", "#r2"\n\t"          \
+    "vpxor	%%xmm1, " #r ", " #r "\n\t"
+#define GHASH_GFMUL_AVX1(r, r2, a, b)              \
+       _GHASH_GFMUL_AVX1(r, r2, a, b)
+
+#define _GHASH_GFMUL_XOR_AVX1(r, r2, a, b)         \
+    "vpshufd	$0x4e, "#a", %%xmm1\n\t"           \
+    "vpshufd	$0x4e, "#b", %%xmm2\n\t"           \
+    "vpclmulqdq	$0x11, "#a", "#b", %%xmm3\n\t"     \
+    "vpclmulqdq	$0x00, "#a", "#b", %%xmm0\n\t"     \
+    "vpxor	"#a", %%xmm1, %%xmm1\n\t"          \
+    "vpxor	"#b", %%xmm2, %%xmm2\n\t"          \
+    "vpclmulqdq	$0x00, %%xmm2, %%xmm1, %%xmm1\n\t" \
+    "vpxor	%%xmm0, %%xmm1, %%xmm1\n\t"        \
+    "vpxor	%%xmm3, %%xmm1, %%xmm1\n\t"        \
+    "vpxor	%%xmm0, "#r2", "#r2"\n\t"          \
+    "vpxor	%%xmm3, " #r ", " #r "\n\t"        \
+    "vpslldq	$8, %%xmm1, %%xmm2\n\t"            \
+    "vpsrldq	$8, %%xmm1, %%xmm1\n\t"            \
+    "vpxor	%%xmm2, "#r2", "#r2"\n\t"          \
+    "vpxor	%%xmm1, " #r ", " #r "\n\t"
+#define GHASH_GFMUL_XOR_AVX1(r, r2, a, b)          \
+       _GHASH_GFMUL_XOR_AVX1(r, r2, a, b)
+
+#define GHASH_MID_AVX1(r, r2)               \
+    "vpsrld	$31, "#r2", %%xmm0\n\t"     \
+    "vpsrld	$31, " #r ", %%xmm1\n\t"    \
+    "vpslld	$1, "#r2", "#r2"\n\t"       \
+    "vpslld	$1, " #r ", " #r "\n\t"     \
+    "vpsrldq	$12, %%xmm0, %%xmm2\n\t"    \
+    "vpslldq	$4, %%xmm0, %%xmm0\n\t"     \
+    "vpslldq	$4, %%xmm1, %%xmm1\n\t"     \
+    "vpor	%%xmm2, " #r ", " #r "\n\t" \
+    "vpor	%%xmm0, "#r2", "#r2"\n\t"   \
+    "vpor	%%xmm1, " #r ", " #r "\n\t"
+
+#define _GHASH_GFMUL_RED_AVX1(r, a, b)             \
+    "vpshufd	$0x4e, "#a", %%xmm5\n\t"           \
+    "vpshufd	$0x4e, "#b", %%xmm6\n\t"           \
+    "vpclmulqdq	$0x11, "#a", "#b", %%xmm7\n\t"     \
+    "vpclmulqdq	$0x00, "#a", "#b", %%xmm4\n\t"     \
+    "vpxor	"#a", %%xmm5, %%xmm5\n\t"          \
+    "vpxor	"#b", %%xmm6, %%xmm6\n\t"          \
+    "vpclmulqdq	$0x00, %%xmm6, %%xmm5, %%xmm5\n\t" \
+    "vpxor	%%xmm4, %%xmm5, %%xmm5\n\t"        \
+    "vpxor	%%xmm7, %%xmm5, %%xmm5\n\t"        \
+    "vpslldq	$8, %%xmm5, %%xmm6\n\t"            \
+    "vpsrldq	$8, %%xmm5, %%xmm5\n\t"            \
+    "vpxor	%%xmm6, %%xmm4, %%xmm4\n\t"        \
+    "vpxor	%%xmm5, %%xmm7, " #r "\n\t"        \
+    "vpslld	$31, %%xmm4, %%xmm8\n\t"           \
+    "vpslld	$30, %%xmm4, %%xmm9\n\t"           \
+    "vpslld	$25, %%xmm4, %%xmm10\n\t"          \
+    "vpxor	%%xmm9, %%xmm8, %%xmm8\n\t"        \
+    "vpxor	%%xmm10, %%xmm8, %%xmm8\n\t"       \
+    "vpsrldq	$4, %%xmm8, %%xmm9\n\t"            \
+    "vpslldq	$12, %%xmm8, %%xmm8\n\t"           \
+    "vpxor	%%xmm8, %%xmm4, %%xmm4\n\t"        \
+    "vpsrld	$1, %%xmm4, %%xmm10\n\t"           \
+    "vpsrld	$2, %%xmm4, %%xmm6\n\t"            \
+    "vpsrld	$7, %%xmm4, %%xmm5\n\t"            \
+    "vpxor	%%xmm6, %%xmm10, %%xmm10\n\t"      \
+    "vpxor	%%xmm5, %%xmm10, %%xmm10\n\t"      \
+    "vpxor	%%xmm9, %%xmm10, %%xmm10\n\t"      \
+    "vpxor	%%xmm4, %%xmm10, %%xmm10\n\t"      \
+    "vpxor	%%xmm10, " #r ", " #r "\n\t"
+#define GHASH_GFMUL_RED_AVX1(r, a, b)              \
+       _GHASH_GFMUL_RED_AVX1(r, a, b)
+
+#define _GHASH_GFSQR_RED_AVX1(r, a)                \
+    "vpclmulqdq	$0x00, "#a", "#a", %%xmm4\n\t"     \
+    "vpclmulqdq	$0x11, "#a", "#a", " #r "\n\t"     \
+    "vpslld	$31, %%xmm4, %%xmm8\n\t"           \
+    "vpslld	$30, %%xmm4, %%xmm9\n\t"           \
+    "vpslld	$25, %%xmm4, %%xmm10\n\t"          \
+    "vpxor	%%xmm9, %%xmm8, %%xmm8\n\t"        \
+    "vpxor	%%xmm10, %%xmm8, %%xmm8\n\t"       \
+    "vpsrldq	$4, %%xmm8, %%xmm9\n\t"            \
+    "vpslldq	$12, %%xmm8, %%xmm8\n\t"           \
+    "vpxor	%%xmm8, %%xmm4, %%xmm4\n\t"        \
+    "vpsrld	$1, %%xmm4, %%xmm10\n\t"           \
+    "vpsrld	$2, %%xmm4, %%xmm6\n\t"            \
+    "vpsrld	$7, %%xmm4, %%xmm5\n\t"            \
+    "vpxor	%%xmm6, %%xmm10, %%xmm10\n\t"      \
+    "vpxor	%%xmm5, %%xmm10, %%xmm10\n\t"      \
+    "vpxor	%%xmm9, %%xmm10, %%xmm10\n\t"      \
+    "vpxor	%%xmm4, %%xmm10, %%xmm10\n\t"      \
+    "vpxor	%%xmm10, " #r ", " #r "\n\t"
+#define GHASH_GFSQR_RED_AVX1(r, a)                 \
+       _GHASH_GFSQR_RED_AVX1(r, a)
+
+#define GHASH_RED_AVX1(r, r2)                \
+    "vpslld	$31, "#r2", %%xmm0\n\t"      \
+    "vpslld	$30, "#r2", %%xmm1\n\t"      \
+    "vpslld	$25, "#r2", %%xmm2\n\t"      \
+    "vpxor	%%xmm1, %%xmm0, %%xmm0\n\t"  \
+    "vpxor	%%xmm2, %%xmm0, %%xmm0\n\t"  \
+    "vmovdqa	%%xmm0, %%xmm1\n\t"          \
+    "vpsrldq	$4, %%xmm1, %%xmm1\n\t"      \
+    "vpslldq	$12, %%xmm0, %%xmm0\n\t"     \
+    "vpxor	%%xmm0, "#r2", "#r2"\n\t"    \
+    "vpsrld	$1, "#r2", %%xmm2\n\t"       \
+    "vpsrld	$2, "#r2", %%xmm3\n\t"       \
+    "vpsrld	$7, "#r2", %%xmm0\n\t"       \
+    "vpxor	%%xmm3, %%xmm2, %%xmm2\n\t"  \
+    "vpxor	%%xmm0, %%xmm2, %%xmm2\n\t"  \
+    "vpxor	%%xmm1, %%xmm2, %%xmm2\n\t"  \
+    "vpxor	"#r2", %%xmm2, %%xmm2\n\t"   \
+    "vpxor	%%xmm2, " #r ", " #r "\n\t"
+
+#define GHASH_GFMUL_RED_XOR_AVX1(r, r2, a, b) \
+    GHASH_GFMUL_XOR_AVX1(r, r2, a, b)         \
+    GHASH_RED_AVX1(r, r2)
+
+#define GHASH_FULL_AVX1(r, r2, a, b) \
+    GHASH_GFMUL_AVX1(r, r2, a, b)    \
+    GHASH_MID_AVX1(r, r2)            \
+    GHASH_RED_AVX1(r, r2)
+
+#define CALC_IV_12_AVX1()                                            \
+    "# Calculate values when IV is 12 bytes\n\t"                     \
+    "# Set counter based on IV\n\t"                                  \
+    "movl		$0x01000000, %%ecx\n\t"                      \
+    "vpinsrq		$0, 0(%%rax), %%xmm13, %%xmm13\n\t"          \
+    "vpinsrd		$2, 8(%%rax), %%xmm13, %%xmm13\n\t"          \
+    "vpinsrd		$3, %%ecx, %%xmm13, %%xmm13\n\t"             \
+    "# H = Encrypt X(=0) and T = Encrypt counter\n\t"                \
+    "vmovdqa		  0(%[KEY]), " VAR(HR) "\n\t"                \
+    "vpxor		" VAR(HR) ", %%xmm13, %%xmm1\n\t"            \
+    "vmovdqa		 16(%[KEY]), %%xmm12\n\t"                    \
+    "vaesenc		%%xmm12, " VAR(HR) ", " VAR(HR) "\n\t"       \
+    "vaesenc		%%xmm12, %%xmm1, %%xmm1\n\t"                 \
+    "vmovdqa		 32(%[KEY]), %%xmm12\n\t"                    \
+    "vaesenc		%%xmm12, " VAR(HR) ", " VAR(HR) "\n\t"       \
+    "vaesenc		%%xmm12, %%xmm1, %%xmm1\n\t"                 \
+    "vmovdqa		 48(%[KEY]), %%xmm12\n\t"                    \
+    "vaesenc		%%xmm12, " VAR(HR) ", " VAR(HR) "\n\t"       \
+    "vaesenc		%%xmm12, %%xmm1, %%xmm1\n\t"                 \
+    "vmovdqa		 64(%[KEY]), %%xmm12\n\t"                    \
+    "vaesenc		%%xmm12, " VAR(HR) ", " VAR(HR) "\n\t"       \
+    "vaesenc		%%xmm12, %%xmm1, %%xmm1\n\t"                 \
+    "vmovdqa		 80(%[KEY]), %%xmm12\n\t"                    \
+    "vaesenc		%%xmm12, " VAR(HR) ", " VAR(HR) "\n\t"       \
+    "vaesenc		%%xmm12, %%xmm1, %%xmm1\n\t"                 \
+    "vmovdqa		 96(%[KEY]), %%xmm12\n\t"                    \
+    "vaesenc		%%xmm12, " VAR(HR) ", " VAR(HR) "\n\t"       \
+    "vaesenc		%%xmm12, %%xmm1, %%xmm1\n\t"                 \
+    "vmovdqa		112(%[KEY]), %%xmm12\n\t"                    \
+    "vaesenc		%%xmm12, " VAR(HR) ", " VAR(HR) "\n\t"       \
+    "vaesenc		%%xmm12, %%xmm1, %%xmm1\n\t"                 \
+    "vmovdqa		128(%[KEY]), %%xmm12\n\t"                    \
+    "vaesenc		%%xmm12, " VAR(HR) ", " VAR(HR) "\n\t"       \
+    "vaesenc		%%xmm12, %%xmm1, %%xmm1\n\t"                 \
+    "vmovdqa		144(%[KEY]), %%xmm12\n\t"                    \
+    "vaesenc		%%xmm12, " VAR(HR) ", " VAR(HR) "\n\t"       \
+    "vaesenc		%%xmm12, %%xmm1, %%xmm1\n\t"                 \
+    "cmpl		$11, %[nr]\n\t"                              \
+    "vmovdqa		160(%[KEY]), %%xmm12\n\t"                    \
+    "jl	31f\n\t"                                                     \
+    "vaesenc		%%xmm12, " VAR(HR) ", " VAR(HR) "\n\t"       \
+    "vaesenc		%%xmm12, %%xmm1, %%xmm1\n\t"                 \
+    "vmovdqa		176(%[KEY]), %%xmm12\n\t"                    \
+    "vaesenc		%%xmm12, " VAR(HR) ", " VAR(HR) "\n\t"       \
+    "vaesenc		%%xmm12, %%xmm1, %%xmm1\n\t"                 \
+    "cmpl		$13, %[nr]\n\t"                              \
+    "vmovdqa		192(%[KEY]), %%xmm12\n\t"                    \
+    "jl	31f\n\t"                                                     \
+    "vaesenc		%%xmm12, " VAR(HR) ", " VAR(HR) "\n\t"       \
+    "vaesenc		%%xmm12, %%xmm1, %%xmm1\n\t"                 \
+    "vmovdqa		208(%[KEY]), %%xmm12\n\t"                    \
+    "vaesenc		%%xmm12, " VAR(HR) ", " VAR(HR) "\n\t"       \
+    "vaesenc		%%xmm12, %%xmm1, %%xmm1\n\t"                 \
+    "vmovdqu		224(%[KEY]), %%xmm12\n\t"                    \
+    "31:\n\t"                                                        \
+    "vaesenclast	%%xmm12, " VAR(HR) ", " VAR(HR) "\n\t"       \
+    "vaesenclast	%%xmm12, %%xmm1, %%xmm1\n\t"                 \
+    "vpshufb		%[BSWAP_MASK], " VAR(HR) ", " VAR(HR) "\n\t" \
+    "vmovdqu		%%xmm1, " VAR(TR) "\n\t"                     \
+    "jmp		39f\n\t"
+
+#define CALC_IV_AVX1()                                       \
+    "# Calculate values when IV is not 12 bytes\n\t"         \
+    "# H = Encrypt X(=0)\n\t"                                \
+    "vmovdqa	0(%[KEY]), " VAR(HR) "\n\t"                  \
+    VAESENC_AVX(HR)                                          \
+    "vpshufb	%[BSWAP_MASK], " VAR(HR) ", " VAR(HR) "\n\t" \
+    "# Calc counter\n\t"                                     \
+    "# Initialization vector\n\t"                            \
+    "cmpl	$0, %%edx\n\t"                               \
+    "movq	$0, %%rcx\n\t"                               \
+    "je	45f\n\t"                                             \
+    "cmpl	$16, %%edx\n\t"                              \
+    "jl	44f\n\t"                                             \
+    "andl	$0xfffffff0, %%edx\n\t"                      \
+    "\n"                                                     \
+    "43:\n\t"                                                \
+    "vmovdqu	(%%rax,%%rcx,1), %%xmm4\n\t"                 \
+    "vpshufb	%[BSWAP_MASK], %%xmm4, %%xmm4\n\t"           \
+    "vpxor	%%xmm4, %%xmm13, %%xmm13\n\t"                \
+    GHASH_FULL_AVX1(%%xmm13, %%xmm12, %%xmm13, HR)           \
+    "addl	$16, %%ecx\n\t"                              \
+    "cmpl	%%edx, %%ecx\n\t"                            \
+    "jl	43b\n\t"                                             \
+    "movl	%[ibytes], %%edx\n\t"                        \
+    "cmpl	%%edx, %%ecx\n\t"                            \
+    "je	45f\n\t"                                             \
+    "\n"                                                     \
+    "44:\n\t"                                                \
+    "subq	$16, %%rsp\n\t"                              \
+    "vpxor	%%xmm4, %%xmm4, %%xmm4\n\t"                  \
+    "xorl	%%ebx, %%ebx\n\t"                            \
+    "vmovdqu	%%xmm4, (%%rsp)\n\t"                         \
+    "42:\n\t"                                                \
+    "movzbl	(%%rax,%%rcx,1), %%r13d\n\t"                 \
+    "movb	%%r13b, (%%rsp,%%rbx,1)\n\t"                 \
+    "incl	%%ecx\n\t"                                   \
+    "incl	%%ebx\n\t"                                   \
+    "cmpl	%%edx, %%ecx\n\t"                            \
+    "jl	42b\n\t"                                             \
+    "vmovdqu	(%%rsp), %%xmm4\n\t"                         \
+    "addq	$16, %%rsp\n\t"                              \
+    "vpshufb	%[BSWAP_MASK], %%xmm4, %%xmm4\n\t"           \
+    "vpxor	%%xmm4, %%xmm13, %%xmm13\n\t"                \
+    GHASH_FULL_AVX1(%%xmm13, %%xmm12, %%xmm13, HR)           \
+    "\n"                                                     \
+    "45:\n\t"                                                \
+    "# T = Encrypt counter\n\t"                              \
+    "vpxor	%%xmm0, %%xmm0, %%xmm0\n\t"                  \
+    "shll	$3, %%edx\n\t"                               \
+    "vpinsrq	$0, %%rdx, %%xmm0, %%xmm0\n\t"               \
+    "vpxor	%%xmm0, %%xmm13, %%xmm13\n\t"                \
+    GHASH_FULL_AVX1(%%xmm13, %%xmm12, %%xmm13, HR)           \
+    "vpshufb	%[BSWAP_MASK], %%xmm13, %%xmm13\n\t"         \
+    "#   Encrypt counter\n\t"                                \
+    "vmovdqa	0(%[KEY]), %%xmm4\n\t"                       \
+    "vpxor	%%xmm13, %%xmm4, %%xmm4\n\t"                 \
+    VAESENC_AVX(%%xmm4)                                      \
+    "vmovdqu	%%xmm4, " VAR(TR) "\n\t"
+
+#define CALC_AAD_AVX1()                                \
+    "# Additional authentication data\n\t"             \
+    "movl	%[abytes], %%edx\n\t"                  \
+    "cmpl	$0, %%edx\n\t"                         \
+    "je		25f\n\t"                               \
+    "movq	%[addt], %%rax\n\t"                    \
+    "xorl	%%ecx, %%ecx\n\t"                      \
+    "cmpl	$16, %%edx\n\t"                        \
+    "jl		24f\n\t"                               \
+    "andl	$0xfffffff0, %%edx\n\t"                \
+    "\n"                                               \
+    "23:\n\t"                                          \
+    "vmovdqu	(%%rax,%%rcx,1), %%xmm4\n\t"           \
+    "vpshufb	%[BSWAP_MASK], %%xmm4, %%xmm4\n\t"     \
+    "vpxor	%%xmm4, " VAR(XR) ", " VAR(XR) "\n\t"  \
+    GHASH_FULL_AVX1(XR, %%xmm12, XR, HR)               \
+    "addl	$16, %%ecx\n\t"                        \
+    "cmpl	%%edx, %%ecx\n\t"                      \
+    "jl		23b\n\t"                               \
+    "movl	%[abytes], %%edx\n\t"                  \
+    "cmpl	%%edx, %%ecx\n\t"                      \
+    "je		25f\n\t"                               \
+    "\n"                                               \
+    "24:\n\t"                                          \
+    "subq	$16, %%rsp\n\t"                        \
+    "vpxor	%%xmm4, %%xmm4, %%xmm4\n\t"            \
+    "xorl	%%ebx, %%ebx\n\t"                      \
+    "vmovdqu	%%xmm4, (%%rsp)\n\t"                   \
+    "22:\n\t"                                          \
+    "movzbl	(%%rax,%%rcx,1), %%r13d\n\t"           \
+    "movb	%%r13b, (%%rsp,%%rbx,1)\n\t"           \
+    "incl	%%ecx\n\t"                             \
+    "incl	%%ebx\n\t"                             \
+    "cmpl	%%edx, %%ecx\n\t"                      \
+    "jl		22b\n\t"                               \
+    "vmovdqu	(%%rsp), %%xmm4\n\t"                   \
+    "addq	$16, %%rsp\n\t"                        \
+    "vpshufb	%[BSWAP_MASK], %%xmm4, %%xmm4\n\t"     \
+    "vpxor	%%xmm4, " VAR(XR) ", " VAR(XR) "\n\t"  \
+    GHASH_FULL_AVX1(XR, %%xmm12, XR, HR)               \
+    "\n"                                               \
+    "25:\n\t"
+
+#define CALC_HT_8_AVX1()                          \
+    "vmovdqa	" VAR(XR) ", %%xmm2\n\t"          \
+    "# H ^ 1\n\t"                                 \
+    "vmovdqu	" VAR(HR) ", 0(" VAR(HTR) ")\n\t" \
+    "# H ^ 2\n\t"                                 \
+    GHASH_GFSQR_RED_AVX1(%%xmm0, HR)              \
+    "vmovdqu	%%xmm0 ,  16(" VAR(HTR) ")\n\t"   \
+    "# H ^ 3\n\t"                                 \
+    GHASH_GFMUL_RED_AVX1(%%xmm1, HR, %%xmm0)      \
+    "vmovdqu	%%xmm1 ,  32(" VAR(HTR) ")\n\t"   \
+    "# H ^ 4\n\t"                                 \
+    GHASH_GFSQR_RED_AVX1(%%xmm3, %%xmm0)          \
+    "vmovdqu	%%xmm3 ,  48(" VAR(HTR) ")\n\t"   \
+    "# H ^ 5\n\t"                                 \
+    GHASH_GFMUL_RED_AVX1(%%xmm12, %%xmm0, %%xmm1) \
+    "vmovdqu	%%xmm12,  64(" VAR(HTR) ")\n\t"   \
+    "# H ^ 6\n\t"                                 \
+    GHASH_GFSQR_RED_AVX1(%%xmm12, %%xmm1)         \
+    "vmovdqu	%%xmm12,  80(" VAR(HTR) ")\n\t"   \
+    "# H ^ 7\n\t"                                 \
+    GHASH_GFMUL_RED_AVX1(%%xmm12, %%xmm1, %%xmm3) \
+    "vmovdqu	%%xmm12,  96(" VAR(HTR) ")\n\t"   \
+    "# H ^ 8\n\t"                                 \
+    GHASH_GFSQR_RED_AVX1(%%xmm12, %%xmm3)         \
+    "vmovdqu	%%xmm12, 112(" VAR(HTR) ")\n\t"
+
+#define VAESENC_128_GHASH_AVX1(src, o)               \
+    "leaq	(%[in]," VAR(KR64) ",1), %%rcx\n\t"  \
+    "leaq	(%[out]," VAR(KR64) ",1), %%rdx\n\t" \
+    /* src is either %%rcx or %%rdx */             \
+    VAESENC_CTR()                                  \
+    VAESENC_XOR()                                  \
+    VAESENC_PCLMUL_1(src,  16, (o-128), 112)       \
+    VAESENC_PCLMUL_N(src,  32, (o-112),  96)       \
+    VAESENC_PCLMUL_N(src,  48, (o- 96),  80)       \
+    VAESENC_PCLMUL_N(src,  64, (o- 80),  64)       \
+    VAESENC_PCLMUL_N(src,  80, (o- 64),  48)       \
+    VAESENC_PCLMUL_N(src,  96, (o- 48),  32)       \
+    VAESENC_PCLMUL_N(src, 112, (o- 32),  16)       \
+    VAESENC_PCLMUL_N(src, 128, (o- 16),   0)       \
+    VAESENC_PCLMUL_L(144)                          \
+    "cmpl	$11, %[nr]\n\t"                    \
+    "vmovdqa	160(%[KEY]), %%xmm12\n\t"          \
+    "jl		4f\n\t"                            \
+    VAESENC()                                      \
+    VAESENC_SET(176)                               \
+    "cmpl	$13, %[nr]\n\t"                    \
+    "vmovdqa	192(%[KEY]), %%xmm12\n\t"          \
+    "jl		4f\n\t"                            \
+    VAESENC()                                      \
+    VAESENC_SET(208)                               \
+    "vmovdqa	224(%[KEY]), %%xmm12\n\t"          \
+    "\n"                                           \
+"4:\n\t"                                           \
+    VAESENC_LAST(%%rcx, %%rdx)
+
+#define _VAESENC_AVX(r)                                  \
+    "vaesenc		16(%[KEY]), " #r ", " #r "\n\t"  \
+    "vaesenc		32(%[KEY]), " #r ", " #r "\n\t"  \
+    "vaesenc		48(%[KEY]), " #r ", " #r "\n\t"  \
+    "vaesenc		64(%[KEY]), " #r ", " #r "\n\t"  \
+    "vaesenc		80(%[KEY]), " #r ", " #r "\n\t"  \
+    "vaesenc		96(%[KEY]), " #r ", " #r "\n\t"  \
+    "vaesenc		112(%[KEY]), " #r ", " #r "\n\t" \
+    "vaesenc		128(%[KEY]), " #r ", " #r "\n\t" \
+    "vaesenc		144(%[KEY]), " #r ", " #r "\n\t" \
+    "cmpl		$11, %[nr]\n\t"                  \
+    "vmovdqa		160(%[KEY]), %%xmm5\n\t"         \
+    "jl			%=f\n\t"                         \
+    "vaesenc		%%xmm5, " #r ", " #r "\n\t"      \
+    "vaesenc		176(%[KEY]), " #r ", " #r "\n\t" \
+    "cmpl		$13, %[nr]\n\t"                  \
+    "vmovdqa		192(%[KEY]), %%xmm5\n\t"         \
+    "jl			%=f\n\t"                         \
+    "vaesenc		%%xmm5, " #r ", " #r "\n\t"      \
+    "vaesenc		208(%[KEY]), " #r ", " #r "\n\t" \
+    "vmovdqa		224(%[KEY]), %%xmm5\n\t"         \
+    "%=:\n\t"                                            \
+    "vaesenclast	%%xmm5, " #r ", " #r "\n\t"
+#define VAESENC_AVX(r)                                   \
+        _VAESENC_AVX(r)
+
+#define AESENC_LAST15_ENC_AVX1()                        \
+    "movl	%[nbytes], %%ecx\n\t"                   \
+    "movl	%%ecx, %%edx\n\t"                       \
+    "andl	$0x0f, %%ecx\n\t"                       \
+    "jz		55f\n\t"                                \
+    "vmovdqu	" VAR(CTR1) ", %%xmm13\n\t"             \
+    "vpshufb	%[BSWAP_EPI64], %%xmm13, %%xmm13\n\t"   \
+    "vpxor	0(%[KEY]), %%xmm13, %%xmm13\n\t"        \
+    VAESENC_AVX(%%xmm13)                                \
+    "subq	$16, %%rsp\n\t"                         \
+    "xorl	%%ecx, %%ecx\n\t"                       \
+    "vmovdqu	%%xmm13, (%%rsp)\n\t"                   \
+    "\n"                                                \
+    "51:\n\t"                                           \
+    "movzbl	(%[in]," VAR(KR64) ",1), %%r13d\n\t"    \
+    "xorb	(%%rsp,%%rcx,1), %%r13b\n\t"            \
+    "movb	%%r13b, (%[out]," VAR(KR64) ",1)\n\t"   \
+    "movb	%%r13b, (%%rsp,%%rcx,1)\n\t"            \
+    "incl	" VAR(KR) "\n\t"                        \
+    "incl	%%ecx\n\t"                              \
+    "cmpl	%%edx, " VAR(KR) "\n\t"                 \
+    "jl		51b\n\t"                                \
+    "xorq	%%r13, %%r13\n\t"                       \
+    "cmpl	$16, %%ecx\n\t"                         \
+    "je		53f\n\t"                                \
+    "\n"                                                \
+    "52:\n\t"                                           \
+    "movb	%%r13b, (%%rsp,%%rcx,1)\n\t"            \
+    "incl	%%ecx\n\t"                              \
+    "cmpl	$16, %%ecx\n\t"                         \
+    "jl		52b\n\t"                                \
+    "53:\n\t"                                           \
+    "vmovdqu	(%%rsp), %%xmm13\n\t"                   \
+    "addq	$16, %%rsp\n\t"                         \
+    "vpshufb	%[BSWAP_MASK], %%xmm13, %%xmm13\n\t"    \
+    "vpxor	%%xmm13, " VAR(XR) ", " VAR(XR) "\n\t"  \
+    GHASH_GFMUL_RED_AVX1(XR, HR, XR)                    \
+
+#define AESENC_LAST15_DEC_AVX1()                        \
+    "movl	%[nbytes], %%ecx\n\t"                   \
+    "movl	%%ecx, %%edx\n\t"                       \
+    "andl	$0x0f, %%ecx\n\t"                       \
+    "jz		55f\n\t"                                \
+    "vmovdqu	" VAR(CTR1) ", %%xmm13\n\t"             \
+    "vpshufb	%[BSWAP_EPI64], %%xmm13, %%xmm13\n\t"   \
+    "vpxor	0(%[KEY]), %%xmm13, %%xmm13\n\t"        \
+    VAESENC_AVX(%%xmm13)                                \
+    "subq	$32, %%rsp\n\t"                         \
+    "xorl	%%ecx, %%ecx\n\t"                       \
+    "vmovdqu	%%xmm13, (%%rsp)\n\t"                   \
+    "vpxor	%%xmm0, %%xmm0, %%xmm0\n\t"             \
+    "vmovdqu	%%xmm0, 16(%%rsp)\n\t"                  \
+    "\n"                                                \
+    "51:\n\t"                                           \
+    "movzbl	(%[in]," VAR(KR64) ",1), %%r13d\n\t"    \
+    "movb	%%r13b, 16(%%rsp,%%rcx,1)\n\t"          \
+    "xorb	(%%rsp,%%rcx,1), %%r13b\n\t"            \
+    "movb	%%r13b, (%[out]," VAR(KR64) ",1)\n\t"   \
+    "incl	" VAR(KR) "\n\t"                        \
+    "incl	%%ecx\n\t"                              \
+    "cmpl	%%edx, " VAR(KR) "\n\t"                 \
+    "jl		51b\n\t"                                \
+    "53:\n\t"                                           \
+    "vmovdqu	16(%%rsp), %%xmm13\n\t"                 \
+    "addq	$32, %%rsp\n\t"                         \
+    "vpshufb	%[BSWAP_MASK], %%xmm13, %%xmm13\n\t"    \
+    "vpxor	%%xmm13, " VAR(XR) ", " VAR(XR) "\n\t"  \
+    GHASH_GFMUL_RED_AVX1(XR, HR, XR)                    \
+
+#define CALC_TAG_AVX1()                                      \
+    "movl	%[nbytes], %%edx\n\t"                        \
+    "movl	%[abytes], %%ecx\n\t"                        \
+    "shlq	$3, %%rdx\n\t"                               \
+    "shlq	$3, %%rcx\n\t"                               \
+    "vpinsrq	$0, %%rdx, %%xmm0, %%xmm0\n\t"               \
+    "vpinsrq	$1, %%rcx, %%xmm0, %%xmm0\n\t"               \
+    "vpxor	%%xmm0, " VAR(XR) ", " VAR(XR) "\n\t"        \
+    GHASH_GFMUL_RED_AVX1(XR, HR, XR)                         \
+    "vpshufb	%[BSWAP_MASK], " VAR(XR) ", " VAR(XR) "\n\t" \
+    "vpxor	" VAR(TR) ", " VAR(XR) ", %%xmm0\n\t"        \
+
+#define STORE_TAG_AVX()                       \
+    "cmpl	$16, %[tbytes]\n\t"           \
+    "je		71f\n\t"                      \
+    "xorq	%%rcx, %%rcx\n\t"             \
+    "vmovdqu	%%xmm0, (%%rsp)\n\t"          \
+    "73:\n\t"                                 \
+    "movzbl	(%%rsp,%%rcx,1), %%r13d\n\t"  \
+    "movb	%%r13b, (%[tag],%%rcx,1)\n\t" \
+    "incl	%%ecx\n\t"                    \
+    "cmpl	%[tbytes], %%ecx\n\t"         \
+    "jne	73b\n\t"                      \
+    "jmp	72f\n\t"                      \
+    "\n"                                      \
+    "71:\n\t"                                 \
+    "vmovdqu	%%xmm0, (%[tag])\n\t"         \
+    "\n"                                      \
+    "72:\n\t"
+
+#define CMP_TAG_AVX()                                      \
+    "cmpl	$16, %[tbytes]\n\t"                        \
+    "je		71f\n\t"                                   \
+    "subq	$16, %%rsp\n\t"                            \
+    "xorq	%%rcx, %%rcx\n\t"                          \
+    "xorq	%%rax, %%rax\n\t"                          \
+    "vmovdqu	%%xmm0, (%%rsp)\n\t"                       \
+    "\n"                                                   \
+    "73:\n\t"                                              \
+    "movzbl	(%%rsp,%%rcx,1), %%r13d\n\t"               \
+    "xorb	(%[tag],%%rcx,1), %%r13b\n\t"              \
+    "orb	%%r13b, %%al\n\t"                          \
+    "incl	%%ecx\n\t"                                 \
+    "cmpl	%[tbytes], %%ecx\n\t"                      \
+    "jne	73b\n\t"                                   \
+    "cmpb	$0x00, %%al\n\t"                           \
+    "sete	%%al\n\t"                                  \
+    "addq	$16, %%rsp\n\t"                            \
+    "jmp	72f\n\t"                                   \
+    "\n"                                                   \
+    "71:\n\t"                                              \
+    "vmovdqu	(%[tag]), %%xmm1\n\t"                      \
+    "vpcmpeqb	%%xmm1, %%xmm0, %%xmm0\n\t"                \
+    "vpmovmskb	%%xmm0, %%edx\n\t"                         \
+    "# %%edx == 0xFFFF then return 1 else => return 0\n\t" \
+    "xorl	%%eax, %%eax\n\t"                          \
+    "cmpl	$0xffff, %%edx\n\t"                        \
+    "sete	%%al\n\t"                                  \
+    "\n"                                                   \
+    "72:\n\t"                                              \
+    "movl	%%eax, (%[res])\n\t"
+
+static void AES_GCM_encrypt_avx1(const unsigned char *in, unsigned char *out,
+                            const unsigned char* addt,
+                                 const unsigned char* ivec, unsigned char *tag,
+                                 unsigned int nbytes, unsigned int abytes,
+                                 unsigned int ibytes, unsigned int tbytes,
+                            const unsigned char* key, int nr)
+{
+    register const unsigned char* iv asm("rax") = ivec;
+    register unsigned int ivLen asm("ebx") = ibytes;
+
+    __asm__ __volatile__ (
+        "subq		$" VAR(STACK_OFFSET) ", %%rsp\n\t"
+        /* Counter is xmm13 */
+        "vpxor		%%xmm13, %%xmm13, %%xmm13\n\t"
+        "vpxor		" VAR(XR) ", " VAR(XR) ", " VAR(XR) "\n\t"
+        "movl		%[ibytes], %%edx\n\t"
+        "cmpl		$12, %%edx\n\t"
+        "jne		35f\n\t"
+        CALC_IV_12_AVX1()
+        "\n"
+        "35:\n\t"
+        CALC_IV_AVX1()
+        "\n"
+        "39:\n\t"
+
+        CALC_AAD_AVX1()
+
+        "# Calculate counter and H\n\t"
+        "vpsrlq		$63, " VAR(HR) ", %%xmm5\n\t"
+        "vpsllq		$1, " VAR(HR) ", %%xmm4\n\t"
+        "vpslldq	$8, %%xmm5, %%xmm5\n\t"
+        "vpor		%%xmm5, %%xmm4, %%xmm4\n\t"
+        "vpshufd	$0xff, " VAR(HR) ", " VAR(HR) "\n\t"
+        "vpsrad		$31, " VAR(HR) ", " VAR(HR) "\n\t"
+        "vpshufb	%[BSWAP_EPI64], %%xmm13, %%xmm13\n\t"
+        "vpand		%[MOD2_128], " VAR(HR) ", " VAR(HR) "\n\t"
+        "vpaddd		%[ONE], %%xmm13, %%xmm13\n\t"
+        "vpxor		%%xmm4, " VAR(HR) ", " VAR(HR) "\n\t"
+        "vmovdqu	%%xmm13, " VAR(CTR1) "\n\t"
+
+        "xorl		" VAR(KR) ", " VAR(KR) "\n\t"
+
+#if !defined(AES_GCM_AESNI_NO_UNROLL) && !defined(AES_GCM_AVX1_NO_UNROLL)
+        "cmpl	$128, %[nbytes]\n\t"
+        "movl	%[nbytes], %%r13d\n\t"
+        "jl	5f\n\t"
+        "andl	$0xffffff80, %%r13d\n\t"
+
+        CALC_HT_8_AVX1()
+
+        "# First 128 bytes of input\n\t"
+        VAESENC_128()
+
+        "cmpl	$128, %%r13d\n\t"
+        "movl	$128, " VAR(KR) "\n\t"
+        "jle	2f\n\t"
+
+        "# More 128 bytes of input\n\t"
+        "\n"
+    "3:\n\t"
+        VAESENC_128_GHASH_AVX1(%%rdx, 0)
+        "addl	$128, " VAR(KR) "\n\t"
+        "cmpl	%%r13d, " VAR(KR) "\n\t"
+        "jl	3b\n\t"
+        "\n"
+    "2:\n\t"
+        "vmovdqa	%[BSWAP_MASK], %%xmm13\n\t"
+        "vpshufb	%%xmm13, %%xmm4, %%xmm4\n\t"
+        "vpshufb	%%xmm13, %%xmm5, %%xmm5\n\t"
+        "vpshufb	%%xmm13, %%xmm6, %%xmm6\n\t"
+        "vpshufb	%%xmm13, %%xmm7, %%xmm7\n\t"
+        "vpxor		%%xmm2, %%xmm4, %%xmm4\n\t"
+        "vpshufb	%%xmm13, %%xmm8, %%xmm8\n\t"
+        "vpshufb	%%xmm13, %%xmm9, %%xmm9\n\t"
+        "vpshufb	%%xmm13, %%xmm10, %%xmm10\n\t"
+        "vpshufb	%%xmm13, %%xmm11, %%xmm11\n\t"
+
+        "vmovdqu	   (" VAR(HTR) "), %%xmm12\n\t"
+        "vmovdqu	 16(" VAR(HTR) "), %%xmm14\n\t"
+        GHASH_GFMUL_AVX1(XR, %%xmm13, %%xmm11, %%xmm12)
+        GHASH_GFMUL_XOR_AVX1(XR, %%xmm13, %%xmm10, %%xmm14)
+        "vmovdqu	 32(" VAR(HTR) "), %%xmm12\n\t"
+        "vmovdqu	 48(" VAR(HTR) "), %%xmm14\n\t"
+        GHASH_GFMUL_XOR_AVX1(XR, %%xmm13, %%xmm9, %%xmm12)
+        GHASH_GFMUL_XOR_AVX1(XR, %%xmm13, %%xmm8, %%xmm14)
+        "vmovdqu	 64(" VAR(HTR) "), %%xmm12\n\t"
+        "vmovdqu	 80(" VAR(HTR) "), %%xmm14\n\t"
+        GHASH_GFMUL_XOR_AVX1(XR, %%xmm13, %%xmm7, %%xmm12)
+        GHASH_GFMUL_XOR_AVX1(XR, %%xmm13, %%xmm6, %%xmm14)
+        "vmovdqu	 96(" VAR(HTR) "), %%xmm12\n\t"
+        "vmovdqu	112(" VAR(HTR) "), %%xmm14\n\t"
+        GHASH_GFMUL_XOR_AVX1(XR, %%xmm13, %%xmm5, %%xmm12)
+        GHASH_GFMUL_RED_XOR_AVX1(XR, %%xmm13, %%xmm4, %%xmm14)
+
+        "vmovdqu	0(" VAR(HTR) "), " VAR(HR) "\n\t"
+        "\n"
+    "5:\n\t"
+        "movl		%[nbytes], %%edx\n\t"
+        "cmpl		%%edx, " VAR(KR) "\n\t"
+        "jge		55f\n\t"
+#endif
+
+        "movl		%[nbytes], %%r13d\n\t"
+        "andl		$0xfffffff0, %%r13d\n\t"
+        "cmpl		%%r13d, " VAR(KR) "\n\t"
+        "jge		14f\n\t"
+
+        VAESENC_BLOCK()
+        "addl		$16, " VAR(KR) "\n\t"
+        "cmpl		%%r13d, " VAR(KR) "\n\t"
+        "jge		13f\n\t"
+        "\n"
+        "12:\n\t"
+        "vmovdqu	(%[in]," VAR(KR64) ",1), %%xmm9\n\t"
+        VAESENC_GFMUL(%%xmm9, HR, XR)
+        "vpshufb	%[BSWAP_MASK], %%xmm4, %%xmm4\n\t"
+        "addl		$16, " VAR(KR) "\n\t"
+        "vpxor		%%xmm4, " VAR(XR) ", " VAR(XR) "\n\t"
+        "cmpl		%%r13d, " VAR(KR) "\n\t"
+        "jl		12b\n\t"
+        "\n"
+        "13:\n\t"
+        GHASH_GFMUL_RED_AVX1(XR, HR, XR)
+        "\n"
+        "14:\n\t"
+
+        AESENC_LAST15_ENC_AVX1()
+        "\n"
+        "55:\n\t"
+
+        CALC_TAG_AVX1()
+        STORE_TAG_AVX()
+        "addq		$" VAR(STACK_OFFSET) ", %%rsp\n\t"
+        "vzeroupper\n\t"
+
+        :
+        : [KEY] "r" (key),
+          [in] "r" (in), [out] "r" (out), [nr] "r" (nr),
+          [nbytes] "r" (nbytes), [abytes] "r" (abytes), [addt] "r" (addt),
+          [ivec] "r" (iv), [ibytes] "r" (ivLen), [tbytes] "r" (tbytes),
+          [tag] "r" (tag),
+          [BSWAP_MASK] "m" (BSWAP_MASK),
+          [BSWAP_EPI64] "m" (BSWAP_EPI64),
+          [ONE] "m" (ONE),
+#if !defined(AES_GCM_AESNI_NO_UNROLL) && !defined(AES_GCM_AVX1_NO_UNROLL)
+          [TWO] "m" (TWO), [THREE] "m" (THREE), [FOUR] "m" (FOUR),
+          [FIVE] "m" (FIVE), [SIX] "m" (SIX), [SEVEN] "m" (SEVEN),
+          [EIGHT] "m" (EIGHT),
+#endif
+          [MOD2_128] "m" (MOD2_128)
+        : "xmm15", "xmm14", "xmm13", "xmm12",
+          "xmm0", "xmm1", "xmm2", "xmm3", "memory",
+          "xmm4", "xmm5", "xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11",
+          "rcx", "rdx", "r13"
+    );
+    }
+
+#ifdef HAVE_INTEL_AVX2
+/* Encrypt and carry-less multiply for AVX2. */
+#define VAESENC_PCLMUL_AVX2_1(src, o1, o2, o3)        \
+    "vmovdqu	" #o2 "(" #src "), %%xmm12\n\t"       \
+    "vmovdqa	" #o1 "(%[KEY]), %%xmm0\n\t"          \
+    "vpshufb	%[BSWAP_MASK], %%xmm12, %%xmm12\n\t"  \
+    "vmovdqu	" #o3 "(" VAR(HTR) "), %%xmm13\n\t"   \
+    "vpxor	%%xmm2, %%xmm12, %%xmm12\n\t"         \
+    "vpclmulqdq	$0x10, %%xmm13, %%xmm12, %%xmm1\n\t"  \
+    "vpclmulqdq	$0x01, %%xmm13, %%xmm12, %%xmm14\n\t" \
+    "vpclmulqdq	$0x00, %%xmm13, %%xmm12, %%xmm2\n\t"  \
+    "vpclmulqdq	$0x11, %%xmm13, %%xmm12, %%xmm3\n\t"  \
+    "vaesenc	%%xmm0, %%xmm4, %%xmm4\n\t"           \
+    "vaesenc	%%xmm0, %%xmm5, %%xmm5\n\t"           \
+    "vaesenc	%%xmm0, %%xmm6, %%xmm6\n\t"           \
+    "vaesenc	%%xmm0, %%xmm7, %%xmm7\n\t"           \
+    "vaesenc	%%xmm0, %%xmm8, %%xmm8\n\t"           \
+    "vaesenc	%%xmm0, %%xmm9, %%xmm9\n\t"           \
+    "vaesenc	%%xmm0, %%xmm10, %%xmm10\n\t"         \
+    "vaesenc	%%xmm0, %%xmm11, %%xmm11\n\t"         \
+
+#define VAESENC_PCLMUL_AVX2_2(src, o1, o2, o3)        \
+    "vmovdqu	" #o2 "(" #src "), %%xmm12\n\t"       \
+    "vmovdqu	" #o3 "(" VAR(HTR) "), %%xmm0\n\t"    \
+    "vpshufb	%[BSWAP_MASK], %%xmm12, %%xmm12\n\t"  \
+    "vpxor	%%xmm14, %%xmm1, %%xmm1\n\t"          \
+    "vpclmulqdq	$0x10, %%xmm0, %%xmm12, %%xmm13\n\t"  \
+    "vpclmulqdq	$0x01, %%xmm0, %%xmm12, %%xmm14\n\t"  \
+    "vpclmulqdq	$0x00, %%xmm0, %%xmm12, %%xmm15\n\t"  \
+    "vpclmulqdq	$0x11, %%xmm0, %%xmm12, %%xmm12\n\t"  \
+    "vmovdqa	" #o1 "(%[KEY]), %%xmm0\n\t"          \
+    "vpxor	%%xmm13, %%xmm1, %%xmm1\n\t"          \
+    "vpxor	%%xmm12, %%xmm3, %%xmm3\n\t"          \
+    "vaesenc	%%xmm0, %%xmm4, %%xmm4\n\t"           \
+    "vaesenc	%%xmm0, %%xmm5, %%xmm5\n\t"           \
+    "vaesenc	%%xmm0, %%xmm6, %%xmm6\n\t"           \
+    "vaesenc	%%xmm0, %%xmm7, %%xmm7\n\t"           \
+    "vaesenc	%%xmm0, %%xmm8, %%xmm8\n\t"           \
+    "vaesenc	%%xmm0, %%xmm9, %%xmm9\n\t"           \
+    "vaesenc	%%xmm0, %%xmm10, %%xmm10\n\t"         \
+    "vaesenc	%%xmm0, %%xmm11, %%xmm11\n\t"         \
+
+#define VAESENC_PCLMUL_AVX2_N(src, o1, o2, o3)        \
+    "vmovdqu	" #o2 "(" #src "), %%xmm12\n\t"       \
+    "vmovdqu	" #o3 "(" VAR(HTR) "), %%xmm0\n\t"    \
+    "vpshufb	%[BSWAP_MASK], %%xmm12, %%xmm12\n\t"  \
+    "vpxor	%%xmm14, %%xmm1, %%xmm1\n\t"          \
+    "vpxor	%%xmm15, %%xmm2, %%xmm2\n\t"          \
+    "vpclmulqdq	$0x10, %%xmm0, %%xmm12, %%xmm13\n\t"  \
+    "vpclmulqdq	$0x01, %%xmm0, %%xmm12, %%xmm14\n\t"  \
+    "vpclmulqdq	$0x00, %%xmm0, %%xmm12, %%xmm15\n\t"  \
+    "vpclmulqdq	$0x11, %%xmm0, %%xmm12, %%xmm12\n\t"  \
+    "vmovdqa	" #o1 "(%[KEY]), %%xmm0\n\t"          \
+    "vpxor	%%xmm13, %%xmm1, %%xmm1\n\t"          \
+    "vpxor	%%xmm12, %%xmm3, %%xmm3\n\t"          \
+    "vaesenc	%%xmm0, %%xmm4, %%xmm4\n\t"           \
+    "vaesenc	%%xmm0, %%xmm5, %%xmm5\n\t"           \
+    "vaesenc	%%xmm0, %%xmm6, %%xmm6\n\t"           \
+    "vaesenc	%%xmm0, %%xmm7, %%xmm7\n\t"           \
+    "vaesenc	%%xmm0, %%xmm8, %%xmm8\n\t"           \
+    "vaesenc	%%xmm0, %%xmm9, %%xmm9\n\t"           \
+    "vaesenc	%%xmm0, %%xmm10, %%xmm10\n\t"         \
+    "vaesenc	%%xmm0, %%xmm11, %%xmm11\n\t"         \
+
+#define VAESENC_PCLMUL_AVX2_L(o)                      \
+    "vpxor	%%xmm14, %%xmm1, %%xmm1\n\t"          \
+    "vpxor	%%xmm15, %%xmm2, %%xmm2\n\t"          \
+    "vpslldq	$8, %%xmm1, %%xmm12\n\t"              \
+    "vpsrldq	$8, %%xmm1, %%xmm1\n\t"               \
+    "vmovdqa	"#o"(%[KEY]), %%xmm15\n\t"            \
+    "vmovdqa	%[MOD2_128], %%xmm0\n\t"              \
+    "vaesenc	%%xmm15, %%xmm4, %%xmm4\n\t"          \
+    "vpxor	%%xmm12, %%xmm2, %%xmm2\n\t"          \
+    "vpxor	%%xmm1, %%xmm3, %%xmm3\n\t"           \
+    "vpclmulqdq	$0x10, %%xmm0, %%xmm2, %%xmm14\n\t"   \
+    "vaesenc	%%xmm15, %%xmm5, %%xmm5\n\t"          \
+    "vaesenc	%%xmm15, %%xmm6, %%xmm6\n\t"          \
+    "vaesenc	%%xmm15, %%xmm7, %%xmm7\n\t"          \
+    "vpshufd	$0x4e, %%xmm2, %%xmm2\n\t"            \
+    "vpxor	%%xmm14, %%xmm2, %%xmm2\n\t"          \
+    "vpclmulqdq	$0x10, %%xmm0, %%xmm2, %%xmm14\n\t"   \
+    "vaesenc	%%xmm15, %%xmm8, %%xmm8\n\t"          \
+    "vaesenc	%%xmm15, %%xmm9, %%xmm9\n\t"          \
+    "vaesenc	%%xmm15, %%xmm10, %%xmm10\n\t"        \
+    "vpshufd	$0x4e, %%xmm2, %%xmm2\n\t"            \
+    "vpxor	%%xmm14, %%xmm2, %%xmm2\n\t"          \
+    "vpxor	%%xmm3, %%xmm2, %%xmm2\n\t"           \
+    "vaesenc	%%xmm15, %%xmm11, %%xmm11\n\t"
+
+#define VAESENC_BLOCK_AVX2()                                  \
+    "vmovdqu		" VAR(CTR1) ", %%xmm5\n\t"            \
+    "vpshufb		%[BSWAP_EPI64], %%xmm5, %%xmm4\n\t"   \
+    "vpaddd		%[ONE], %%xmm5, %%xmm5\n\t"           \
+    "vmovdqu		%%xmm5, " VAR(CTR1) "\n\t"            \
+    "vpxor		   (%[KEY]), %%xmm4, %%xmm4\n\t"      \
+    "vaesenc		 16(%[KEY]), %%xmm4, %%xmm4\n\t"      \
+    "vaesenc		 32(%[KEY]), %%xmm4, %%xmm4\n\t"      \
+    "vaesenc		 48(%[KEY]), %%xmm4, %%xmm4\n\t"      \
+    "vaesenc		 64(%[KEY]), %%xmm4, %%xmm4\n\t"      \
+    "vaesenc		 80(%[KEY]), %%xmm4, %%xmm4\n\t"      \
+    "vaesenc		 96(%[KEY]), %%xmm4, %%xmm4\n\t"      \
+    "vaesenc		112(%[KEY]), %%xmm4, %%xmm4\n\t"      \
+    "vaesenc		128(%[KEY]), %%xmm4, %%xmm4\n\t"      \
+    "vaesenc		144(%[KEY]), %%xmm4, %%xmm4\n\t"      \
+    "cmpl		$11, %[nr]\n\t"                       \
+    "vmovdqa		160(%[KEY]), %%xmm5\n\t"              \
+    "jl			%=f\n\t"                              \
+    "vaesenc		%%xmm5, %%xmm4, %%xmm4\n\t"           \
+    "vaesenc		176(%[KEY]), %%xmm4, %%xmm4\n\t"      \
+    "cmpl		$13, %[nr]\n\t"                       \
+    "vmovdqa		192(%[KEY]), %%xmm5\n\t"              \
+    "jl			%=f\n\t"                              \
+    "vaesenc		%%xmm5, %%xmm4, %%xmm4\n\t"           \
+    "vaesenc		208(%[KEY]), %%xmm4, %%xmm4\n\t"      \
+    "vmovdqa		224(%[KEY]), %%xmm5\n\t"              \
+    "%=:\n\t"                                                 \
+    "vaesenclast	%%xmm5, %%xmm4, %%xmm4\n\t"           \
+    "vmovdqu		(%[in]," VAR(KR64) ",1), %%xmm5\n\t"  \
+    "vpxor		%%xmm5, %%xmm4, %%xmm4\n\t"           \
+    "vmovdqu		%%xmm4, (%[out]," VAR(KR64) ",1)\n\t" \
+    "vpshufb		%[BSWAP_MASK], %%xmm4, %%xmm4\n\t"    \
+    "vpxor		%%xmm4, " VAR(XR) ", " VAR(XR) "\n\t"
+
+/* Karatsuba multiplication - slower
+ * H01 = H[1] ^ H[0] (top and bottom 64-bits XORed)
+ */
+#define _VAESENC_GFMUL_AVX2(in, H, X, ctr1, H01)            \
+    "vpxor		   (%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "vaesenc		 16(%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "vaesenc		 32(%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "vaesenc		 48(%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "vaesenc		 64(%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "vaesenc		 80(%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "vaesenc		 96(%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "vaesenc		112(%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "vaesenc		128(%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "vaesenc		144(%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "cmpl		$11, %[nr]\n\t"                     \
+    "vmovdqa		160(%[KEY]), %%xmm5\n\t"            \
+    "jl			%=f\n\t"                            \
+    "vaesenc		%%xmm5, %%xmm4, %%xmm4\n\t"         \
+    "vaesenc		176(%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "cmpl		$13, %[nr]\n\t"                     \
+    "vmovdqa		192(%[KEY]), %%xmm5\n\t"            \
+    "jl			%=f\n\t"                            \
+    "vaesenc		%%xmm5, %%xmm4, %%xmm4\n\t"         \
+    "vaesenc		208(%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "vmovdqa		224(%[KEY]), %%xmm5\n\t"            \
+    "%=:\n\t"                                               \
+    "vaesenclast	%%xmm5, %%xmm4, %%xmm4\n\t"         \
+    "vmovdqu		" #in ", %%xmm0\n\t"                \
+    "vpxor		%%xmm0, %%xmm4, %%xmm4\n\t"         \
+                                                            \
+    "vpsrldq	$8, " #X ", %%xmm2\n\t"                     \
+    "vpxor	" #X ", %%xmm2, %%xmm2\n\t"                 \
+    "vpclmulqdq	$0x00, " #H ", " #X ", %%xmm5\n\t"          \
+    "vpclmulqdq	$0x11, " #H ", " #X ", %%xmm8\n\t"          \
+    "vpclmulqdq	$0x00, "#H01", %%xmm2, %%xmm7\n\t"          \
+    "vpxor	%%xmm5, %%xmm7, %%xmm7\n\t"                 \
+    "vpxor	%%xmm8, %%xmm7, %%xmm7\n\t"                 \
+    "vpslldq	$8, %%xmm7, %%xmm6\n\t"                     \
+    "vpsrldq	$8, %%xmm7, %%xmm7\n\t"                     \
+    "vpxor	%%xmm7, %%xmm8, %%xmm8\n\t"                 \
+    "vpxor	%%xmm5, %%xmm6, %%xmm6\n\t"                 \
+                                                            \
+    "vpclmulqdq	$0x10, %[MOD2_128], %%xmm6, %%xmm5\n\t"     \
+    "vpshufd	$0x4e, %%xmm6, %%xmm6\n\t"                  \
+    "vpxor	%%xmm5, %%xmm6, %%xmm6\n\t"                 \
+    "vpclmulqdq	$0x10, %[MOD2_128], %%xmm6, %%xmm5\n\t"     \
+    "vpshufd	$0x4e, %%xmm6, %%xmm6\n\t"                  \
+    "vpxor	%%xmm8, %%xmm6, %%xmm6\n\t"                 \
+    "vpxor	%%xmm5, %%xmm6, " VAR(XR) "\n\t"
+#define VAESENC_GFMUL_AVX2(in, H, X, ctr1)                  \
+       _VAESENC_GFMUL_AVX2(in, H, X, ctr1)
+
+#define _VAESENC_GFMUL_SB_AVX2(in, H, X, ctr1)              \
+    "vpclmulqdq	$0x10, " #H ", " #X ", %%xmm7\n\t"          \
+    "vpclmulqdq	$0x01, " #H ", " #X ", %%xmm6\n\t"          \
+    "vpclmulqdq	$0x00, " #H ", " #X ", %%xmm5\n\t"          \
+    "vpclmulqdq	$0x11, " #H ", " #X ", %%xmm8\n\t"          \
+    "vpxor		   (%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "vaesenc		 16(%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "vpxor	%%xmm6, %%xmm7, %%xmm7\n\t"                 \
+    "vpslldq	$8, %%xmm7, %%xmm6\n\t"                     \
+    "vpsrldq	$8, %%xmm7, %%xmm7\n\t"                     \
+    "vaesenc		 32(%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "vpxor	%%xmm5, %%xmm6, %%xmm6\n\t"                 \
+    "vpclmulqdq	$0x10, %[MOD2_128], %%xmm6, %%xmm5\n\t"     \
+    "vaesenc		 48(%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "vaesenc		 64(%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "vaesenc		 80(%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "vpshufd	$0x4e, %%xmm6, %%xmm6\n\t"                  \
+    "vpxor	%%xmm5, %%xmm6, %%xmm6\n\t"                 \
+    "vpclmulqdq	$0x10, %[MOD2_128], %%xmm6, %%xmm5\n\t"     \
+    "vaesenc		 96(%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "vaesenc		112(%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "vaesenc		128(%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "vpshufd	$0x4e, %%xmm6, %%xmm6\n\t"                  \
+    "vaesenc		144(%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "vpxor	%%xmm7, %%xmm8, %%xmm8\n\t"                 \
+    "vpxor	%%xmm8, %%xmm6, %%xmm6\n\t"                 \
+    "cmpl		$11, %[nr]\n\t"                     \
+    "vmovdqa		160(%[KEY]), %%xmm3\n\t"            \
+    "jl			%=f\n\t"                            \
+    "vaesenc		%%xmm3, %%xmm4, %%xmm4\n\t"         \
+    "vaesenc		176(%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "cmpl		$13, %[nr]\n\t"                     \
+    "vmovdqa		192(%[KEY]), %%xmm3\n\t"            \
+    "jl			%=f\n\t"                            \
+    "vaesenc		%%xmm3, %%xmm4, %%xmm4\n\t"         \
+    "vaesenc		208(%[KEY]), %%xmm4, %%xmm4\n\t"    \
+    "vmovdqa		224(%[KEY]), %%xmm3\n\t"            \
+    "%=:\n\t"                                               \
+    "vaesenclast	%%xmm3, %%xmm4, %%xmm4\n\t"         \
+    "vpxor	%%xmm5, %%xmm6, " VAR(XR) "\n\t"            \
+    "vmovdqu		" #in ", %%xmm5\n\t"                \
+    "vpxor		%%xmm5, %%xmm4, %%xmm4\n\t"
+#define VAESENC_GFMUL_SB_AVX2(in, H, X, ctr1)               \
+       _VAESENC_GFMUL_SB_AVX2(in, H, X, ctr1)
+
+
+#define _GHASH_GFMUL_AVX2(r, r2, a, b)         \
+    "vpclmulqdq	$0x10, "#a", "#b", %%xmm2\n\t" \
+    "vpclmulqdq	$0x01, "#a", "#b", %%xmm1\n\t" \
+    "vpclmulqdq	$0x00, "#a", "#b", %%xmm0\n\t" \
+    "vpclmulqdq	$0x11, "#a", "#b", %%xmm3\n\t" \
+    "vpxor	%%xmm1, %%xmm2, %%xmm2\n\t"    \
+    "vpslldq	$8, %%xmm2, %%xmm1\n\t"        \
+    "vpsrldq	$8, %%xmm2, %%xmm2\n\t"        \
+    "vpxor	%%xmm1, %%xmm0, "#r2"\n\t"     \
+    "vpxor	%%xmm2, %%xmm3, " #r "\n\t"
+#define GHASH_GFMUL_AVX2(r, r2, a, b)          \
+       _GHASH_GFMUL_AVX2(r, r2, a, b)
+
+#define GHASH_MID_AVX2(r, r2)               \
+    "vpsrld	$31, "#r2", %%xmm0\n\t"     \
+    "vpsrld	$31, " #r ", %%xmm1\n\t"    \
+    "vpslld	$1, "#r2", "#r2"\n\t"       \
+    "vpslld	$1, " #r ", " #r "\n\t"     \
+    "vpsrldq	$12, %%xmm0, %%xmm2\n\t"    \
+    "vpslldq	$4, %%xmm0, %%xmm0\n\t"     \
+    "vpslldq	$4, %%xmm1, %%xmm1\n\t"     \
+    "vpor	%%xmm2, " #r ", " #r "\n\t" \
+    "vpor	%%xmm0, "#r2", "#r2"\n\t"   \
+    "vpor	%%xmm1, " #r ", " #r "\n\t"
+
+#define _GHASH_GFMUL_RED_AVX2(r, a, b)                  \
+    "vpclmulqdq	$0x10, "#a", "#b", %%xmm7\n\t"          \
+    "vpclmulqdq	$0x01, "#a", "#b", %%xmm6\n\t"          \
+    "vpclmulqdq	$0x00, "#a", "#b", %%xmm5\n\t"          \
+    "vpxor	%%xmm6, %%xmm7, %%xmm7\n\t"             \
+    "vpslldq	$8, %%xmm7, %%xmm6\n\t"                 \
+    "vpsrldq	$8, %%xmm7, %%xmm7\n\t"                 \
+    "vpxor	%%xmm5, %%xmm6, %%xmm6\n\t"             \
+    "vpclmulqdq	$0x11, "#a", "#b", %%xmm8\n\t"          \
+    "vpclmulqdq	$0x10, %[MOD2_128], %%xmm6, %%xmm5\n\t" \
+    "vpshufd	$0x4e, %%xmm6, %%xmm6\n\t"              \
+    "vpxor	%%xmm5, %%xmm6, %%xmm6\n\t"             \
+    "vpclmulqdq	$0x10, %[MOD2_128], %%xmm6, %%xmm5\n\t" \
+    "vpshufd	$0x4e, %%xmm6, %%xmm6\n\t"              \
+    "vpxor	%%xmm7, %%xmm8, %%xmm8\n\t"             \
+    "vpxor	%%xmm8, %%xmm6, %%xmm6\n\t"             \
+    "vpxor	%%xmm5, %%xmm6, " #r "\n\t"
+#define GHASH_GFMUL_RED_AVX2(r, a, b)                   \
+       _GHASH_GFMUL_RED_AVX2(r, a, b)
+
+#define _GHASH_GFSQR_RED2_AVX2(r, a, mod128)            \
+    "vpclmulqdq	$0x00, "#a", "#a", %%xmm6\n\t"          \
+    "vpclmulqdq	$0x11, "#a", "#a", %%xmm8\n\t"          \
+    "vpclmulqdq	$0x10, "#mod128", %%xmm6, %%xmm5\n\t"   \
+    "vpshufd	$0x4e, %%xmm6, %%xmm6\n\t"              \
+    "vpxor	%%xmm5, %%xmm6, %%xmm6\n\t"             \
+    "vpclmulqdq	$0x10, "#mod128", %%xmm6, %%xmm5\n\t"   \
+    "vpshufd	$0x4e, %%xmm6, %%xmm6\n\t"              \
+    "vpxor	%%xmm5, %%xmm6, %%xmm6\n\t"             \
+    "vpxor	%%xmm6, %%xmm8, " #r "\n\t"
+#define GHASH_GFSQR_RED2_AVX2(r, a, mod128)             \
+       _GHASH_GFSQR_RED2_AVX2(r, a, mod128)
+
+#define _GHASH_GFMUL_SQR_RED2_AVX2(rm, rs, a, b, mod128) \
+    "vpclmulqdq	$0x10, "#a", "#b", %%xmm7\n\t"           \
+    "vpclmulqdq	$0x01, "#a", "#b", %%xmm6\n\t"           \
+    "vpclmulqdq	$0x00, "#a", "#b", %%xmm5\n\t"           \
+    "vpclmulqdq	$0x11, "#a", "#b", %%xmm8\n\t"           \
+    "vpclmulqdq	$0x00, "#b", "#b", %%xmm9\n\t"           \
+    "vpclmulqdq	$0x11, "#b", "#b", %%xmm10\n\t"          \
+    "vpxor	%%xmm6, %%xmm7, %%xmm7\n\t"              \
+    "vpslldq	$8, %%xmm7, %%xmm6\n\t"                  \
+    "vpsrldq	$8, %%xmm7, %%xmm7\n\t"                  \
+    "vpxor	%%xmm5, %%xmm6, %%xmm6\n\t"              \
+    "vpclmulqdq	$0x10, "#mod128", %%xmm9, %%xmm4\n\t"    \
+    "vpclmulqdq	$0x10, "#mod128", %%xmm6, %%xmm5\n\t"    \
+    "vpshufd	$0x4e, %%xmm6, %%xmm6\n\t"               \
+    "vpshufd	$0x4e, %%xmm9, %%xmm9\n\t"               \
+    "vpxor	%%xmm5, %%xmm6, %%xmm6\n\t"              \
+    "vpxor	%%xmm4, %%xmm9, %%xmm9\n\t"              \
+    "vpclmulqdq	$0x10, "#mod128", %%xmm6, %%xmm5\n\t"    \
+    "vpclmulqdq	$0x10, "#mod128", %%xmm9, %%xmm4\n\t"    \
+    "vpshufd	$0x4e, %%xmm6, %%xmm6\n\t"               \
+    "vpshufd	$0x4e, %%xmm9, %%xmm9\n\t"               \
+    "vpxor	%%xmm7, %%xmm8, %%xmm8\n\t"              \
+    "vpxor	%%xmm4, %%xmm9, %%xmm9\n\t"              \
+    "vpxor	%%xmm8, %%xmm6, %%xmm6\n\t"              \
+    "vpxor	%%xmm10, %%xmm9, "#rs"\n\t"              \
+    "vpxor	%%xmm5, %%xmm6, "#rm"\n\t"
+#define GHASH_GFMUL_SQR_RED2_AVX2(rm, rs, a, b, mod128)  \
+       _GHASH_GFMUL_SQR_RED2_AVX2(rm, rs, a, b, mod128)
+
+#define CALC_HT_8_AVX2()                                                \
+    "vmovdqa	%[MOD2_128], %%xmm11\n\t"                               \
+    "vmovdqa	" VAR(XR) ", %%xmm2\n\t"                                \
+    "# H ^ 1 and H ^ 2\n\t"                                             \
+    GHASH_GFSQR_RED2_AVX2(%%xmm0, HR, %%xmm11)                          \
+    "vmovdqu	" VAR(HR) ", 0(" VAR(HTR) ")\n\t"                       \
+    "vmovdqu	%%xmm0 ,  16(" VAR(HTR) ")\n\t"                         \
+    "# H ^ 3 and H ^ 4\n\t"                                             \
+    GHASH_GFMUL_SQR_RED2_AVX2(%%xmm1, %%xmm3, HR, %%xmm0, %%xmm11)      \
+    "vmovdqu	%%xmm1 ,  32(" VAR(HTR) ")\n\t"                         \
+    "vmovdqu	%%xmm3 ,  48(" VAR(HTR) ")\n\t"                         \
+    "# H ^ 5 and H ^ 6\n\t"                                             \
+    GHASH_GFMUL_SQR_RED2_AVX2(%%xmm12, %%xmm0, %%xmm0, %%xmm1, %%xmm11) \
+    "vmovdqu	%%xmm12,  64(" VAR(HTR) ")\n\t"                         \
+    "vmovdqu	%%xmm0 ,  80(" VAR(HTR) ")\n\t"                         \
+    "# H ^ 7 and H ^ 8\n\t"                                             \
+    GHASH_GFMUL_SQR_RED2_AVX2(%%xmm12, %%xmm0, %%xmm1, %%xmm3, %%xmm11) \
+    "vmovdqu	%%xmm12,  96(" VAR(HTR) ")\n\t"                         \
+    "vmovdqu	%%xmm0 , 112(" VAR(HTR) ")\n\t"
+
+#define _GHASH_RED_AVX2(r, r2)                     \
+    "vmovdqa	%[MOD2_128], %%xmm2\n\t"           \
+    "vpclmulqdq	$0x10, %%xmm2, "#r2", %%xmm0\n\t"  \
+    "vpshufd	$0x4e, "#r2", %%xmm1\n\t"          \
+    "vpxor	%%xmm0, %%xmm1, %%xmm1\n\t"        \
+    "vpclmulqdq	$0x10, %%xmm2, %%xmm1, %%xmm0\n\t" \
+    "vpshufd	$0x4e, %%xmm1, %%xmm1\n\t"         \
+    "vpxor	%%xmm0, %%xmm1, %%xmm1\n\t"        \
+    "vpxor	%%xmm1, " #r ", " #r "\n\t"
+#define GHASH_RED_AVX2(r, r2)                      \
+       _GHASH_RED_AVX2(r, r2)
+
+#define GHASH_FULL_AVX2(r, r2, a, b) \
+    GHASH_GFMUL_AVX2(r, r2, a, b)    \
+    GHASH_MID_AVX2(r, r2)            \
+    GHASH_RED_AVX2(r, r2)
+
+#define _GFMUL_3V_AVX2(r, r2, r3, a, b)        \
+    "vpclmulqdq	$0x10, "#a", "#b", "#r3"\n\t"  \
+    "vpclmulqdq	$0x01, "#a", "#b", %%xmm1\n\t" \
+    "vpclmulqdq	$0x00, "#a", "#b", "#r2"\n\t"  \
+    "vpclmulqdq	$0x11, "#a", "#b", " #r "\n\t" \
+    "vpxor	%%xmm1, "#r3", "#r3"\n\t"
+#define GFMUL_3V_AVX2(r, r2, r3, a, b)         \
+       _GFMUL_3V_AVX2(r, r2, r3, a, b)
+
+#define _GFMUL_XOR_3V_AVX2(r, r2, r3, a, b)    \
+    "vpclmulqdq	$0x10, "#a", "#b", %%xmm2\n\t" \
+    "vpclmulqdq	$0x01, "#a", "#b", %%xmm1\n\t" \
+    "vpclmulqdq	$0x00, "#a", "#b", %%xmm0\n\t" \
+    "vpclmulqdq	$0x11, "#a", "#b", %%xmm3\n\t" \
+    "vpxor	%%xmm1, %%xmm2, %%xmm2\n\t"    \
+    "vpxor	%%xmm3, " #r ", " #r "\n\t"    \
+    "vpxor	%%xmm2, "#r3", "#r3"\n\t"      \
+    "vpxor	%%xmm0, "#r2", "#r2"\n\t"
+#define GFMUL_XOR_3V_AVX2(r, r2, r3, a, b)     \
+       _GFMUL_XOR_3V_AVX2(r, r2, r3, a, b)
+
+#define GHASH_GFMUL_RED_8_AVX2()                              \
+    "vmovdqu	   (" VAR(HTR) "), %%xmm12\n\t"               \
+    GFMUL_3V_AVX2(XR, %%xmm13, %%xmm14, %%xmm11, %%xmm12)     \
+    "vmovdqu	 16(" VAR(HTR) "), %%xmm12\n\t"               \
+    GFMUL_XOR_3V_AVX2(XR, %%xmm13, %%xmm14, %%xmm10, %%xmm12) \
+    "vmovdqu	 32(" VAR(HTR) "), %%xmm11\n\t"               \
+    "vmovdqu	 48(" VAR(HTR) "), %%xmm12\n\t"               \
+    GFMUL_XOR_3V_AVX2(XR, %%xmm13, %%xmm14, %%xmm9, %%xmm11)  \
+    GFMUL_XOR_3V_AVX2(XR, %%xmm13, %%xmm14, %%xmm8, %%xmm12)  \
+    "vmovdqu	 64(" VAR(HTR) "), %%xmm11\n\t"               \
+    "vmovdqu	 80(" VAR(HTR) "), %%xmm12\n\t"               \
+    GFMUL_XOR_3V_AVX2(XR, %%xmm13, %%xmm14, %%xmm7, %%xmm11)  \
+    GFMUL_XOR_3V_AVX2(XR, %%xmm13, %%xmm14, %%xmm6, %%xmm12)  \
+    "vmovdqu	 96(" VAR(HTR) "), %%xmm11\n\t"               \
+    "vmovdqu	112(" VAR(HTR) "), %%xmm12\n\t"               \
+    GFMUL_XOR_3V_AVX2(XR, %%xmm13, %%xmm14, %%xmm5, %%xmm11)  \
+    GFMUL_XOR_3V_AVX2(XR, %%xmm13, %%xmm14, %%xmm4, %%xmm12)  \
+    "vpslldq	$8, %%xmm14, %%xmm12\n\t"                     \
+    "vpsrldq	$8, %%xmm14, %%xmm14\n\t"                     \
+    "vpxor	%%xmm12, %%xmm13, %%xmm13\n\t"                \
+    "vpxor	%%xmm14, " VAR(XR) ", " VAR(XR) "\n\t"        \
+    GHASH_RED_AVX2(XR, %%xmm13)
+
+#define CALC_IV_12_AVX2()                                            \
+    "# Calculate values when IV is 12 bytes\n\t"                     \
+    "# Set counter based on IV\n\t"                                  \
+    "movl		$0x01000000, %%ecx\n\t"                      \
+    "vpinsrq		$0, 0(%%rax), %%xmm13, %%xmm13\n\t"          \
+    "vpinsrd		$2, 8(%%rax), %%xmm13, %%xmm13\n\t"          \
+    "vpinsrd		$3, %%ecx, %%xmm13, %%xmm13\n\t"             \
+    "# H = Encrypt X(=0) and T = Encrypt counter\n\t"                \
+    "vmovdqa		  0(%[KEY]), " VAR(HR) "\n\t"                \
+    "vmovdqa		 16(%[KEY]), %%xmm12\n\t"                    \
+    "vpxor		" VAR(HR) ", %%xmm13, %%xmm1\n\t"            \
+    "vaesenc		%%xmm12, " VAR(HR) ", " VAR(HR) "\n\t"       \
+    "vaesenc		%%xmm12, %%xmm1, %%xmm1\n\t"                 \
+    "vmovdqa		 32(%[KEY]), %%xmm0\n\t"                     \
+    "vmovdqa		 48(%[KEY]), %%xmm12\n\t"                    \
+    "vaesenc		%%xmm0, " VAR(HR) ", " VAR(HR) "\n\t"        \
+    "vaesenc		%%xmm0, %%xmm1, %%xmm1\n\t"                  \
+    "vaesenc		%%xmm12, " VAR(HR) ", " VAR(HR) "\n\t"       \
+    "vaesenc		%%xmm12, %%xmm1, %%xmm1\n\t"                 \
+    "vmovdqa		 64(%[KEY]), %%xmm0\n\t"                     \
+    "vmovdqa		 80(%[KEY]), %%xmm12\n\t"                    \
+    "vaesenc		%%xmm0, " VAR(HR) ", " VAR(HR) "\n\t"        \
+    "vaesenc		%%xmm0, %%xmm1, %%xmm1\n\t"                  \
+    "vaesenc		%%xmm12, " VAR(HR) ", " VAR(HR) "\n\t"       \
+    "vaesenc		%%xmm12, %%xmm1, %%xmm1\n\t"                 \
+    "vmovdqa		 96(%[KEY]), %%xmm0\n\t"                     \
+    "vmovdqa		112(%[KEY]), %%xmm12\n\t"                    \
+    "vaesenc		%%xmm0, " VAR(HR) ", " VAR(HR) "\n\t"        \
+    "vaesenc		%%xmm0, %%xmm1, %%xmm1\n\t"                  \
+    "vaesenc		%%xmm12, " VAR(HR) ", " VAR(HR) "\n\t"       \
+    "vaesenc		%%xmm12, %%xmm1, %%xmm1\n\t"                 \
+    "vmovdqa		128(%[KEY]), %%xmm0\n\t"                     \
+    "vmovdqa		144(%[KEY]), %%xmm12\n\t"                    \
+    "vaesenc		%%xmm0, " VAR(HR) ", " VAR(HR) "\n\t"        \
+    "vaesenc		%%xmm0, %%xmm1, %%xmm1\n\t"                  \
+    "vaesenc		%%xmm12, " VAR(HR) ", " VAR(HR) "\n\t"       \
+    "vaesenc		%%xmm12, %%xmm1, %%xmm1\n\t"                 \
+    "cmpl		$11, %[nr]\n\t"                              \
+    "vmovdqa		160(%[KEY]), %%xmm0\n\t"                     \
+    "jl	31f\n\t"                                                     \
+    "vmovdqa		176(%[KEY]), %%xmm12\n\t"                    \
+    "vaesenc		%%xmm0, " VAR(HR) ", " VAR(HR) "\n\t"        \
+    "vaesenc		%%xmm0, %%xmm1, %%xmm1\n\t"                  \
+    "vaesenc		%%xmm12, " VAR(HR) ", " VAR(HR) "\n\t"       \
+    "vaesenc		%%xmm12, %%xmm1, %%xmm1\n\t"                 \
+    "cmpl		$13, %[nr]\n\t"                              \
+    "vmovdqa		192(%[KEY]), %%xmm0\n\t"                     \
+    "jl	31f\n\t"                                                     \
+    "vmovdqa		208(%[KEY]), %%xmm12\n\t"                    \
+    "vaesenc		%%xmm0, " VAR(HR) ", " VAR(HR) "\n\t"        \
+    "vaesenc		%%xmm0, %%xmm1, %%xmm1\n\t"                  \
+    "vaesenc		%%xmm12, " VAR(HR) ", " VAR(HR) "\n\t"       \
+    "vaesenc		%%xmm12, %%xmm1, %%xmm1\n\t"                 \
+    "vmovdqu		224(%[KEY]), %%xmm0\n\t"                     \
+    "31:\n\t"                                                        \
+    "vaesenclast	%%xmm0, " VAR(HR) ", " VAR(HR) "\n\t"        \
+    "vaesenclast	%%xmm0, %%xmm1, %%xmm1\n\t"                  \
+    "vpshufb		%[BSWAP_MASK], " VAR(HR) ", " VAR(HR) "\n\t" \
+    "vmovdqu		%%xmm1, " VAR(TR) "\n\t"                     \
+
+#define CALC_IV_AVX2()                                       \
+    "# Calculate values when IV is not 12 bytes\n\t"         \
+    "# H = Encrypt X(=0)\n\t"                                \
+    "vmovdqa	0(%[KEY]), " VAR(HR) "\n\t"                  \
+    VAESENC_AVX(HR)                                          \
+    "vpshufb	%[BSWAP_MASK], " VAR(HR) ", " VAR(HR) "\n\t" \
+    "# Calc counter\n\t"                                     \
+    "# Initialization vector\n\t"                            \
+    "cmpl	$0, %%edx\n\t"                               \
+    "movq	$0, %%rcx\n\t"                               \
+    "je	45f\n\t"                                             \
+    "cmpl	$16, %%edx\n\t"                              \
+    "jl	44f\n\t"                                             \
+    "andl	$0xfffffff0, %%edx\n\t"                      \
+    "\n"                                                     \
+    "43:\n\t"                                                \
+    "vmovdqu	(%%rax,%%rcx,1), %%xmm4\n\t"                 \
+    "vpshufb	%[BSWAP_MASK], %%xmm4, %%xmm4\n\t"           \
+    "vpxor	%%xmm4, %%xmm13, %%xmm13\n\t"                \
+    GHASH_FULL_AVX2(%%xmm13, %%xmm12, %%xmm13, HR)           \
+    "addl	$16, %%ecx\n\t"                              \
+    "cmpl	%%edx, %%ecx\n\t"                            \
+    "jl	43b\n\t"                                             \
+    "movl	%[ibytes], %%edx\n\t"                        \
+    "cmpl	%%edx, %%ecx\n\t"                            \
+    "je	45f\n\t"                                             \
+    "\n"                                                     \
+    "44:\n\t"                                                \
+    "subq	$16, %%rsp\n\t"                              \
+    "vpxor	%%xmm4, %%xmm4, %%xmm4\n\t"                  \
+    "xorl	%%ebx, %%ebx\n\t"                            \
+    "vmovdqu	%%xmm4, (%%rsp)\n\t"                         \
+    "42:\n\t"                                                \
+    "movzbl	(%%rax,%%rcx,1), %%r13d\n\t"                 \
+    "movb	%%r13b, (%%rsp,%%rbx,1)\n\t"                 \
+    "incl	%%ecx\n\t"                                   \
+    "incl	%%ebx\n\t"                                   \
+    "cmpl	%%edx, %%ecx\n\t"                            \
+    "jl	42b\n\t"                                             \
+    "vmovdqu	(%%rsp), %%xmm4\n\t"                         \
+    "addq	$16, %%rsp\n\t"                              \
+    "vpshufb	%[BSWAP_MASK], %%xmm4, %%xmm4\n\t"           \
+    "vpxor	%%xmm4, %%xmm13, %%xmm13\n\t"                \
+    GHASH_FULL_AVX2(%%xmm13, %%xmm12, %%xmm13, HR)           \
+    "\n"                                                     \
+    "45:\n\t"                                                \
+    "# T = Encrypt counter\n\t"                              \
+    "vpxor	%%xmm0, %%xmm0, %%xmm0\n\t"                  \
+    "shll	$3, %%edx\n\t"                               \
+    "vpinsrq	$0, %%rdx, %%xmm0, %%xmm0\n\t"               \
+    "vpxor	%%xmm0, %%xmm13, %%xmm13\n\t"                \
+    GHASH_FULL_AVX2(%%xmm13, %%xmm12, %%xmm13, HR)           \
+    "vpshufb	%[BSWAP_MASK], %%xmm13, %%xmm13\n\t"         \
+    "#   Encrypt counter\n\t"                                \
+    "vmovdqa	0(%[KEY]), %%xmm4\n\t"                       \
+    "vpxor	%%xmm13, %%xmm4, %%xmm4\n\t"                 \
+    VAESENC_AVX(%%xmm4)                                      \
+    "vmovdqu	%%xmm4, " VAR(TR) "\n\t"
+
+#define CALC_AAD_AVX2()                                \
+    "# Additional authentication data\n\t"             \
+    "movl	%[abytes], %%edx\n\t"                  \
+    "cmpl	$0, %%edx\n\t"                         \
+    "je		25f\n\t"                               \
+    "movq	%[addt], %%rax\n\t"                    \
+    "xorl	%%ecx, %%ecx\n\t"                      \
+    "cmpl	$16, %%edx\n\t"                        \
+    "jl		24f\n\t"                               \
+    "andl	$0xfffffff0, %%edx\n\t"                \
+    "\n"                                               \
+    "23:\n\t"                                          \
+    "vmovdqu	(%%rax,%%rcx,1), %%xmm4\n\t"           \
+    "vpshufb	%[BSWAP_MASK], %%xmm4, %%xmm4\n\t"     \
+    "vpxor	%%xmm4, " VAR(XR) ", " VAR(XR) "\n\t"  \
+    GHASH_FULL_AVX2(XR, %%xmm12, XR, HR)               \
+    "addl	$16, %%ecx\n\t"                        \
+    "cmpl	%%edx, %%ecx\n\t"                      \
+    "jl		23b\n\t"                               \
+    "movl	%[abytes], %%edx\n\t"                  \
+    "cmpl	%%edx, %%ecx\n\t"                      \
+    "je		25f\n\t"                               \
+    "\n"                                               \
+    "24:\n\t"                                          \
+    "subq	$16, %%rsp\n\t"                        \
+    "vpxor	%%xmm4, %%xmm4, %%xmm4\n\t"            \
+    "xorl	%%ebx, %%ebx\n\t"                      \
+    "vmovdqu	%%xmm4, (%%rsp)\n\t"                   \
+    "22:\n\t"                                          \
+    "movzbl	(%%rax,%%rcx,1), %%r13d\n\t"           \
+    "movb	%%r13b, (%%rsp,%%rbx,1)\n\t"           \
+    "incl	%%ecx\n\t"                             \
+    "incl	%%ebx\n\t"                             \
+    "cmpl	%%edx, %%ecx\n\t"                      \
+    "jl		22b\n\t"                               \
+    "vmovdqu	(%%rsp), %%xmm4\n\t"                   \
+    "addq	$16, %%rsp\n\t"                        \
+    "vpshufb	%[BSWAP_MASK], %%xmm4, %%xmm4\n\t"     \
+    "vpxor	%%xmm4, " VAR(XR) ", " VAR(XR) "\n\t"  \
+    GHASH_FULL_AVX2(XR, %%xmm12, XR, HR)               \
+    "\n"                                               \
+    "25:\n\t"
+
+#define VAESENC_128_GHASH_AVX2(src, o)               \
+    "leaq	(%[in]," VAR(KR64) ",1), %%rcx\n\t"  \
+    "leaq	(%[out]," VAR(KR64) ",1), %%rdx\n\t" \
+    /* src is either %%rcx or %%rdx */             \
+    VAESENC_CTR()                                  \
+    VAESENC_XOR()                                  \
+    VAESENC_PCLMUL_AVX2_1(src,  16, (o-128), 112)  \
+    VAESENC_PCLMUL_AVX2_2(src,  32, (o-112),  96)  \
+    VAESENC_PCLMUL_AVX2_N(src,  48, (o- 96),  80)  \
+    VAESENC_PCLMUL_AVX2_N(src,  64, (o- 80),  64)  \
+    VAESENC_PCLMUL_AVX2_N(src,  80, (o- 64),  48)  \
+    VAESENC_PCLMUL_AVX2_N(src,  96, (o- 48),  32)  \
+    VAESENC_PCLMUL_AVX2_N(src, 112, (o- 32),  16)  \
+    VAESENC_PCLMUL_AVX2_N(src, 128, (o- 16),   0)  \
+    VAESENC_PCLMUL_AVX2_L(144)                     \
+    "cmpl	$11, %[nr]\n\t"                    \
+    "vmovdqa	160(%[KEY]), %%xmm12\n\t"          \
+    "jl		4f\n\t"                            \
+    VAESENC()                                      \
+    VAESENC_SET(176)                               \
+    "cmpl	$13, %[nr]\n\t"                    \
+    "vmovdqa	192(%[KEY]), %%xmm12\n\t"          \
+    "jl		4f\n\t"                            \
+    VAESENC()                                      \
+    VAESENC_SET(208)                               \
+    "vmovdqa	224(%[KEY]), %%xmm12\n\t"          \
+    "\n"                                           \
+"4:\n\t"                                           \
+    VAESENC_LAST(%%rcx, %%rdx)
+
+#define AESENC_LAST15_ENC_AVX2()                        \
+    "movl	%[nbytes], %%ecx\n\t"                   \
+    "movl	%%ecx, %%edx\n\t"                       \
+    "andl	$0x0f, %%ecx\n\t"                       \
+    "jz		55f\n\t"                                \
+    "vmovdqu	" VAR(CTR1) ", %%xmm13\n\t"             \
+    "vpshufb	%[BSWAP_EPI64], %%xmm13, %%xmm13\n\t"   \
+    "vpxor	0(%[KEY]), %%xmm13, %%xmm13\n\t"        \
+    VAESENC_AVX(%%xmm13)                                \
+    "subq	$16, %%rsp\n\t"                         \
+    "xorl	%%ecx, %%ecx\n\t"                       \
+    "vmovdqu	%%xmm13, (%%rsp)\n\t"                   \
+    "\n"                                                \
+    "51:\n\t"                                           \
+    "movzbl	(%[in]," VAR(KR64) ",1), %%r13d\n\t"    \
+    "xorb	(%%rsp,%%rcx,1), %%r13b\n\t"            \
+    "movb	%%r13b, (%[out]," VAR(KR64) ",1)\n\t"   \
+    "movb	%%r13b, (%%rsp,%%rcx,1)\n\t"            \
+    "incl	" VAR(KR) "\n\t"                        \
+    "incl	%%ecx\n\t"                              \
+    "cmpl	%%edx, " VAR(KR) "\n\t"                 \
+    "jl		51b\n\t"                                \
+    "xorq	%%r13, %%r13\n\t"                       \
+    "cmpl	$16, %%ecx\n\t"                         \
+    "je		53f\n\t"                                \
+    "\n"                                                \
+    "52:\n\t"                                           \
+    "movb	%%r13b, (%%rsp,%%rcx,1)\n\t"            \
+    "incl	%%ecx\n\t"                              \
+    "cmpl	$16, %%ecx\n\t"                         \
+    "jl		52b\n\t"                                \
+    "53:\n\t"                                           \
+    "vmovdqu	(%%rsp), %%xmm13\n\t"                   \
+    "addq	$16, %%rsp\n\t"                         \
+    "vpshufb	%[BSWAP_MASK], %%xmm13, %%xmm13\n\t"    \
+    "vpxor	%%xmm13, " VAR(XR) ", " VAR(XR) "\n\t"  \
+    GHASH_GFMUL_RED_AVX2(XR, HR, XR)                    \
+
+#define AESENC_LAST15_DEC_AVX2()                        \
+    "movl	%[nbytes], %%ecx\n\t"                   \
+    "movl	%%ecx, %%edx\n\t"                       \
+    "andl	$0x0f, %%ecx\n\t"                       \
+    "jz		55f\n\t"                                \
+    "vmovdqu	" VAR(CTR1) ", %%xmm13\n\t"             \
+    "vpshufb	%[BSWAP_EPI64], %%xmm13, %%xmm13\n\t"   \
+    "vpxor	0(%[KEY]), %%xmm13, %%xmm13\n\t"        \
+    VAESENC_AVX(%%xmm13)                                \
+    "subq	$32, %%rsp\n\t"                         \
+    "xorl	%%ecx, %%ecx\n\t"                       \
+    "vmovdqu	%%xmm13, (%%rsp)\n\t"                   \
+    "vpxor	%%xmm0, %%xmm0, %%xmm0\n\t"             \
+    "vmovdqu	%%xmm0, 16(%%rsp)\n\t"                  \
+    "\n"                                                \
+    "51:\n\t"                                           \
+    "movzbl	(%[in]," VAR(KR64) ",1), %%r13d\n\t"    \
+    "movb	%%r13b, 16(%%rsp,%%rcx,1)\n\t"          \
+    "xorb	(%%rsp,%%rcx,1), %%r13b\n\t"            \
+    "movb	%%r13b, (%[out]," VAR(KR64) ",1)\n\t"   \
+    "incl	" VAR(KR) "\n\t"                        \
+    "incl	%%ecx\n\t"                              \
+    "cmpl	%%edx, " VAR(KR) "\n\t"                 \
+    "jl		51b\n\t"                                \
+    "53:\n\t"                                           \
+    "vmovdqu	16(%%rsp), %%xmm13\n\t"                 \
+    "addq	$32, %%rsp\n\t"                         \
+    "vpshufb	%[BSWAP_MASK], %%xmm13, %%xmm13\n\t"    \
+    "vpxor	%%xmm13, " VAR(XR) ", " VAR(XR) "\n\t"  \
+    GHASH_GFMUL_RED_AVX2(XR, HR, XR)                    \
+
+#define CALC_TAG_AVX2()                                      \
+    "movl	%[nbytes], %%edx\n\t"                        \
+    "movl	%[abytes], %%ecx\n\t"                        \
+    "shlq	$3, %%rdx\n\t"                               \
+    "shlq	$3, %%rcx\n\t"                               \
+    "vpinsrq	$0, %%rdx, %%xmm0, %%xmm0\n\t"               \
+    "vpinsrq	$1, %%rcx, %%xmm0, %%xmm0\n\t"               \
+    "vpxor	%%xmm0, " VAR(XR) ", " VAR(XR) "\n\t"        \
+    GHASH_GFMUL_RED_AVX2(XR, HR, XR)                         \
+    "vpshufb	%[BSWAP_MASK], " VAR(XR) ", " VAR(XR) "\n\t" \
+    "vpxor	" VAR(TR) ", " VAR(XR) ", %%xmm0\n\t"        \
+
+
+static void AES_GCM_encrypt_avx2(const unsigned char *in, unsigned char *out,
+                                 const unsigned char* addt,
+                                 const unsigned char* ivec, unsigned char *tag,
+                                 unsigned int nbytes, unsigned int abytes,
+                                 unsigned int ibytes, unsigned int tbytes,
+                                 const unsigned char* key, int nr)
+{
+    register const unsigned char* iv asm("rax") = ivec;
+    register unsigned int ivLen asm("ebx") = ibytes;
+
+    __asm__ __volatile__ (
+        "subq		$" VAR(STACK_OFFSET) ", %%rsp\n\t"
+        /* Counter is xmm13 */
+        "vpxor		%%xmm13, %%xmm13, %%xmm13\n\t"
+        "vpxor		" VAR(XR) ", " VAR(XR) ", " VAR(XR) "\n\t"
+        "movl		%[ibytes], %%edx\n\t"
+        "cmpl		$12, %%edx\n\t"
+        "jne		35f\n\t"
+        CALC_IV_12_AVX2()
+        "jmp		39f\n\t"
+        "\n"
+        "35:\n\t"
+        CALC_IV_AVX2()
+        "\n"
+        "39:\n\t"
+
+        CALC_AAD_AVX2()
+
+        "# Calculate counter and H\n\t"
+        "vpsrlq		$63, " VAR(HR) ", %%xmm5\n\t"
+        "vpsllq		$1, " VAR(HR) ", %%xmm4\n\t"
+        "vpslldq	$8, %%xmm5, %%xmm5\n\t"
+        "vpor		%%xmm5, %%xmm4, %%xmm4\n\t"
+        "vpshufd	$0xff, " VAR(HR) ", " VAR(HR) "\n\t"
+        "vpsrad		$31, " VAR(HR) ", " VAR(HR) "\n\t"
+        "vpshufb	%[BSWAP_EPI64], %%xmm13, %%xmm13\n\t"
+        "vpand		%[MOD2_128], " VAR(HR) ", " VAR(HR) "\n\t"
+        "vpaddd		%[ONE], %%xmm13, %%xmm13\n\t"
+        "vpxor		%%xmm4, " VAR(HR) ", " VAR(HR) "\n\t"
+        "vmovdqu	%%xmm13, " VAR(CTR1) "\n\t"
+
+        "xorl		" VAR(KR) ", " VAR(KR) "\n\t"
+
+#if !defined(AES_GCM_AESNI_NO_UNROLL) && !defined(AES_GCM_AVX2_NO_UNROLL)
+        "cmpl	$128, %[nbytes]\n\t"
+        "movl	%[nbytes], %%r13d\n\t"
+        "jl	5f\n\t"
+        "andl	$0xffffff80, %%r13d\n\t"
+
+        CALC_HT_8_AVX2()
+
+        "# First 128 bytes of input\n\t"
+        VAESENC_128()
+
+        "cmpl	$128, %%r13d\n\t"
+        "movl	$128, " VAR(KR) "\n\t"
+        "jle	2f\n\t"
+
+        "# More 128 bytes of input\n\t"
+            "\n"
+    "3:\n\t"
+        VAESENC_128_GHASH_AVX2(%%rdx, 0)
+        "addl	$128, " VAR(KR) "\n\t"
+        "cmpl	%%r13d, " VAR(KR) "\n\t"
+        "jl	3b\n\t"
+        "\n"
+    "2:\n\t"
+        "vmovdqa	%[BSWAP_MASK], %%xmm13\n\t"
+        "vpshufb	%%xmm13, %%xmm4, %%xmm4\n\t"
+        "vpshufb	%%xmm13, %%xmm5, %%xmm5\n\t"
+        "vpshufb	%%xmm13, %%xmm6, %%xmm6\n\t"
+        "vpshufb	%%xmm13, %%xmm7, %%xmm7\n\t"
+        "vpshufb	%%xmm13, %%xmm8, %%xmm8\n\t"
+        "vpshufb	%%xmm13, %%xmm9, %%xmm9\n\t"
+        "vpshufb	%%xmm13, %%xmm10, %%xmm10\n\t"
+        "vpshufb	%%xmm13, %%xmm11, %%xmm11\n\t"
+        "vpxor		%%xmm2, %%xmm4, %%xmm4\n\t"
+
+        GHASH_GFMUL_RED_8_AVX2()
+
+        "vmovdqu	0(" VAR(HTR) "), " VAR(HR) "\n\t"
+        "\n"
+    "5:\n\t"
+        "movl		%[nbytes], %%edx\n\t"
+        "cmpl		%%edx, " VAR(KR) "\n\t"
+        "jge		55f\n\t"
+#endif
+
+        "movl		%[nbytes], %%r13d\n\t"
+        "andl		$0xfffffff0, %%r13d\n\t"
+        "cmpl		%%r13d, " VAR(KR) "\n\t"
+        "jge		14f\n\t"
+
+        VAESENC_BLOCK_AVX2()
+        "addl		$16, " VAR(KR) "\n\t"
+        "cmpl		%%r13d, " VAR(KR) "\n\t"
+        "jge		13f\n\t"
+                "vmovdqa	%[MOD2_128], %%xmm0\n\t"
+        "\n"
+        "12:\n\t"
+        "vmovdqu	(%[in]," VAR(KR64) ",1), %%xmm9\n\t"
+        "vmovdqu	" VAR(CTR1) ", %%xmm5\n\t"
+        "vpshufb	%[BSWAP_EPI64], %%xmm5, %%xmm4\n\t"
+        "vpaddd		%[ONE], %%xmm5, %%xmm5\n\t"
+        "vmovdqu	%%xmm5, " VAR(CTR1) "\n\t"
+        VAESENC_GFMUL_SB_AVX2(%%xmm9, HR, XR, CTR1)
+        "vmovdqu	%%xmm4, (%[out]," VAR(KR64) ",1)\n\t"
+        "vpshufb	%[BSWAP_MASK], %%xmm4, %%xmm4\n\t"
+        "addl		$16, " VAR(KR) "\n\t"
+        "vpxor		%%xmm4, " VAR(XR) ", " VAR(XR) "\n\t"
+        "cmpl		%%r13d, " VAR(KR) "\n\t"
+        "jl		12b\n\t"
+        "\n"
+        "13:\n\t"
+        GHASH_GFMUL_RED_AVX2(XR, HR, XR)
+        "\n"
+        "14:\n\t"
+
+        AESENC_LAST15_ENC_AVX2()
+        "\n"
+        "55:\n\t"
+
+        CALC_TAG_AVX2()
+        STORE_TAG_AVX()
+        "addq		$" VAR(STACK_OFFSET) ", %%rsp\n\t"
+        "vzeroupper\n\t"
+
+        :
+        : [KEY] "r" (key),
+          [in] "r" (in), [out] "r" (out), [nr] "r" (nr),
+          [nbytes] "r" (nbytes), [abytes] "r" (abytes), [addt] "r" (addt),
+          [ivec] "r" (iv), [ibytes] "r" (ivLen), [tbytes] "r" (tbytes),
+          [tag] "r" (tag),
+              [BSWAP_MASK] "m" (BSWAP_MASK),
+              [BSWAP_EPI64] "m" (BSWAP_EPI64),
+          [ONE] "m" (ONE),
+#if !defined(AES_GCM_AESNI_NO_UNROLL) && !defined(AES_GCM_AVX2_NO_UNROLL)
+          [TWO] "m" (TWO), [THREE] "m" (THREE), [FOUR] "m" (FOUR),
+          [FIVE] "m" (FIVE), [SIX] "m" (SIX), [SEVEN] "m" (SEVEN),
+          [EIGHT] "m" (EIGHT),
+#endif
+              [MOD2_128] "m" (MOD2_128)
+            : "xmm15", "xmm14", "xmm13", "xmm12",
+          "xmm0", "xmm1", "xmm2", "xmm3", "memory",
+          "xmm4", "xmm5", "xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11",
+          "rcx", "rdx", "r13"
+            );
+        }
+#endif /* HAVE_INTEL_AVX2 */
+#endif /* HAVE_INTEL_AVX1 */
+
+#ifdef HAVE_AES_DECRYPT
+/* Figure 10. AES-GCM – Decrypt With Single Block Ghash at a Time */
+
+static void AES_GCM_decrypt(const unsigned char *in, unsigned char *out,
+                            const unsigned char* addt,
+                            const unsigned char* ivec, const unsigned char *tag,
+                            int nbytes, int abytes, int ibytes, int tbytes,
+                            const unsigned char* key, int nr, int* res)
+{
+    register const unsigned char* iv asm("rax") = ivec;
+    register int ivLen asm("ebx") = ibytes;
+    register int tagLen asm("edx") = tbytes;
+
+        __asm__ __volatile__ (
+        "pushq		%%rdx\n\t"
+        "subq		$" VAR(STACK_OFFSET) ", %%rsp\n\t"
+        /* Counter is xmm13 */
+        "pxor		%%xmm13, %%xmm13\n\t"
+        "pxor		%%xmm15, %%xmm15\n\t"
+        "movl		%[ibytes], %%edx\n\t"
+        "cmpl		$12, %%edx\n\t"
+        "jne		35f\n\t"
+        CALC_IV_12()
+        "\n"
+        "35:\n\t"
+        CALC_IV()
+        "\n"
+        "39:\n\t"
+
+        CALC_AAD()
+
+        "# Calculate counter and H\n\t"
+        "pshufb		%[BSWAP_EPI64], %%xmm13\n\t"
+        "movdqa		" VAR(HR) ", %%xmm5\n\t"
+        "paddd		%[ONE], %%xmm13\n\t"
+        "movdqa		" VAR(HR) ", %%xmm4\n\t"
+        "movdqu		%%xmm13, " VAR(CTR1) "\n\t"
+        "psrlq		$63, %%xmm5\n\t"
+        "psllq		$1, %%xmm4\n\t"
+        "pslldq		$8, %%xmm5\n\t"
+        "por		%%xmm5, %%xmm4\n\t"
+        "pshufd		$0xff, " VAR(HR) ", " VAR(HR) "\n\t"
+        "psrad		$31, " VAR(HR) "\n\t"
+        "pand		%[MOD2_128], " VAR(HR) "\n\t"
+        "pxor		%%xmm4, " VAR(HR) "\n\t"
+
+        "xorl		" VAR(KR) ", " VAR(KR) "\n\t"
+
+#if !defined(AES_GCM_AESNI_NO_UNROLL) && !defined(AES_GCM_AVX1_NO_UNROLL)
+        "cmpl		$128, %[nbytes]\n\t"
+        "jl		5f\n\t"
+
+        CALC_HT_8_AVX()
+
+        "movl		%[nbytes], %%r13d\n\t"
+        "andl		$0xffffff80, %%r13d\n\t"
+        "\n"
+        "2:\n\t"
+        AESENC_128_GHASH_AVX(%%rcx, 128)
+        "addl		$128, " VAR(KR) "\n\t"
+        "cmpl		%%r13d, " VAR(KR) "\n\t"
+        "jl		2b\n\t"
+
+        "movdqa		%%xmm2, " VAR(XR) "\n\t"
+        "movdqu		(%%rsp), " VAR(HR) "\n\t"
+    "5:\n\t"
+        "movl		%[nbytes], %%edx\n\t"
+        "cmpl		%%edx, " VAR(KR) "\n\t"
+        "jge		55f\n\t"
+#endif
+        "movl		%[nbytes], %%r13d\n\t"
+        "andl		$0xfffffff0, %%r13d\n\t"
+        "cmpl		%%r13d, " VAR(KR) "\n\t"
+        "jge		13f\n\t"
+
+        "\n"
+        "12:\n\t"
+        "leaq		(%[in]," VAR(KR64) ",1), %%rcx\n\t"
+        "leaq		(%[out]," VAR(KR64) ",1), %%rdx\n\t"
+        "movdqu		(%%rcx), %%xmm1\n\t"
+        "movdqa		" VAR(HR) ", %%xmm0\n\t"
+        "pshufb		%[BSWAP_MASK], %%xmm1\n\t"
+        "pxor		" VAR(XR) ", %%xmm1\n\t"
+        AESENC_GFMUL(%%rcx, %%rdx, %%xmm0, %%xmm1)
+        "addl		$16, " VAR(KR) "\n\t"
+        "cmpl		%%r13d, " VAR(KR) "\n\t"
+        "jl		12b\n\t"
+        "\n"
+        "13:\n\t"
+
+        AESENC_LAST15_DEC_AVX()
+        "\n"
+        "55:\n\t"
+
+        CALC_TAG()
+        "addq		$" VAR(STACK_OFFSET) ", %%rsp\n\t"
+        "popq		%%rdx\n\t"
+        CMP_TAG()
+
+        :
+        : [KEY] "r" (key),
+          [in] "r" (in), [out] "r" (out), [nr] "r" (nr),
+          [nbytes] "r" (nbytes), [abytes] "r" (abytes), [addt] "r" (addt),
+          [ivec] "r" (iv), [ibytes] "r" (ivLen), [tbytes] "r" (tagLen),
+          [tag] "r" (tag), [res] "r" (res),
+          [BSWAP_MASK] "m" (BSWAP_MASK),
+          [BSWAP_EPI64] "m" (BSWAP_EPI64),
+          [ONE] "m" (ONE),
+#if !defined(AES_GCM_AESNI_NO_UNROLL) && !defined(AES_GCM_AVX1_NO_UNROLL)
+          [TWO] "m" (TWO), [THREE] "m" (THREE), [FOUR] "m" (FOUR),
+          [FIVE] "m" (FIVE), [SIX] "m" (SIX), [SEVEN] "m" (SEVEN),
+          [EIGHT] "m" (EIGHT),
+#endif
+          [MOD2_128] "m" (MOD2_128)
+        : "xmm15", "xmm14", "xmm13", "xmm12",
+          "xmm0", "xmm1", "xmm2", "xmm3", "memory",
+          "xmm4", "xmm5", "xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11",
+          "rcx", "r13"
+        );
+    }
+
+#ifdef HAVE_INTEL_AVX1
+static void AES_GCM_decrypt_avx1(const unsigned char *in, unsigned char *out,
+                                 const unsigned char* addt,
+                                 const unsigned char* ivec,
+                                 const unsigned char *tag, int nbytes,
+                                 int abytes, int ibytes, int tbytes,
+                                 const unsigned char* key, int nr, int* res)
+{
+    register const unsigned char* iv asm("rax") = ivec;
+    register int ivLen asm("ebx") = ibytes;
+    register int tagLen asm("edx") = tbytes;
+
+        __asm__ __volatile__ (
+        "pushq		%%rdx\n\t"
+        "subq		$" VAR(STACK_OFFSET) ", %%rsp\n\t"
+        /* Counter is xmm13 */
+        "vpxor		%%xmm13, %%xmm13, %%xmm13\n\t"
+        "vpxor		%%xmm15, %%xmm15, %%xmm15\n\t"
+        "movl		%[ibytes], %%edx\n\t"
+        "cmpl		$12, %%edx\n\t"
+        "jne		35f\n\t"
+        CALC_IV_12_AVX1()
+        "\n"
+        "35:\n\t"
+        CALC_IV_AVX1()
+        "\n"
+        "39:\n\t"
+
+        CALC_AAD_AVX1()
+
+        "# Calculate counter and H\n\t"
+        "vpsrlq		$63, " VAR(HR) ", %%xmm5\n\t"
+        "vpsllq		$1, " VAR(HR) ", %%xmm4\n\t"
+        "vpslldq	$8, %%xmm5, %%xmm5\n\t"
+        "vpor		%%xmm5, %%xmm4, %%xmm4\n\t"
+        "vpshufd	$0xff, " VAR(HR) ", " VAR(HR) "\n\t"
+        "vpsrad		$31, " VAR(HR) ", " VAR(HR) "\n\t"
+        "vpshufb	%[BSWAP_EPI64], %%xmm13, %%xmm13\n\t"
+        "vpand		%[MOD2_128], " VAR(HR) ", " VAR(HR) "\n\t"
+        "vpaddd		%[ONE], %%xmm13, %%xmm13\n\t"
+        "vpxor		%%xmm4, " VAR(HR) ", " VAR(HR) "\n\t"
+        "vmovdqu	%%xmm13, " VAR(CTR1) "\n\t"
+
+        "xorl		" VAR(KR) ", " VAR(KR) "\n\t"
+
+#if !defined(AES_GCM_AESNI_NO_UNROLL) && !defined(AES_GCM_AVX1_NO_UNROLL)
+        "cmpl		$128, %[nbytes]\n\t"
+        "jl		5f\n\t"
+
+        CALC_HT_8_AVX1()
+
+        "movl		%[nbytes], %%r13d\n\t"
+        "andl		$0xffffff80, %%r13d\n\t"
+        "\n"
+        "2:\n\t"
+        VAESENC_128_GHASH_AVX1(%%rcx, 128)
+        "addl		$128, " VAR(KR) "\n\t"
+        "cmpl		%%r13d, " VAR(KR) "\n\t"
+        "jl		2b\n\t"
+
+        "vmovdqa	%%xmm2, " VAR(XR) "\n\t"
+        "vmovdqu	(%%rsp), " VAR(HR) "\n\t"
+    "5:\n\t"
+        "movl		%[nbytes], %%edx\n\t"
+        "cmpl		%%edx, " VAR(KR) "\n\t"
+        "jge		55f\n\t"
+#endif
+        "movl		%[nbytes], %%r13d\n\t"
+        "andl		$0xfffffff0, %%r13d\n\t"
+        "cmpl		%%r13d, " VAR(KR) "\n\t"
+        "jge		13f\n\t"
+
+        "\n"
+        "12:\n\t"
+        "vmovdqu	(%[in]," VAR(KR64) ",1), %%xmm9\n\t"
+        "vmovdqa	" VAR(HR) ", %%xmm0\n\t"
+        "vpshufb	%[BSWAP_MASK], %%xmm9, %%xmm1\n\t"
+        "vpxor		" VAR(XR) ", %%xmm1, %%xmm1\n\t"
+        VAESENC_GFMUL(%%xmm9, %%xmm0, %%xmm1)
+        "addl		$16, " VAR(KR) "\n\t"
+        "cmpl		%%r13d, " VAR(KR) "\n\t"
+        "jl		12b\n\t"
+        "\n"
+        "13:\n\t"
+
+        AESENC_LAST15_DEC_AVX1()
+        "\n"
+        "55:\n\t"
+
+        CALC_TAG_AVX1()
+        "addq		$" VAR(STACK_OFFSET) ", %%rsp\n\t"
+        "popq		%%rdx\n\t"
+        CMP_TAG_AVX()
+        "vzeroupper\n\t"
+
+        :
+        : [KEY] "r" (key),
+          [in] "r" (in), [out] "r" (out), [nr] "r" (nr),
+          [nbytes] "r" (nbytes), [abytes] "r" (abytes), [addt] "r" (addt),
+          [ivec] "r" (iv), [ibytes] "r" (ivLen), [tbytes] "r" (tagLen),
+          [tag] "r" (tag), [res] "r" (res),
+          [BSWAP_MASK] "m" (BSWAP_MASK),
+          [BSWAP_EPI64] "m" (BSWAP_EPI64),
+          [ONE] "m" (ONE),
+#if !defined(AES_GCM_AESNI_NO_UNROLL) && !defined(AES_GCM_AVX1_NO_UNROLL)
+          [TWO] "m" (TWO), [THREE] "m" (THREE), [FOUR] "m" (FOUR),
+          [FIVE] "m" (FIVE), [SIX] "m" (SIX), [SEVEN] "m" (SEVEN),
+          [EIGHT] "m" (EIGHT),
+#endif
+          [MOD2_128] "m" (MOD2_128)
+        : "xmm15", "xmm14", "xmm13", "xmm12",
+          "xmm0", "xmm1", "xmm2", "xmm3", "memory",
+          "xmm4", "xmm5", "xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11",
+          "rcx", "r13"
+        );
+    }
+
+#ifdef HAVE_INTEL_AVX2
+static void AES_GCM_decrypt_avx2(const unsigned char *in, unsigned char *out,
+                                 const unsigned char* addt,
+                                 const unsigned char* ivec,
+                                 const unsigned char *tag, int nbytes,
+                                 int abytes, int ibytes, int tbytes,
+                                 const unsigned char* key, int nr, int* res)
+{
+    register const unsigned char* iv asm("rax") = ivec;
+    register int ivLen asm("ebx") = ibytes;
+    register int tagLen asm("edx") = tbytes;
+
+        __asm__ __volatile__ (
+        "pushq		%%rdx\n\t"
+        "subq		$" VAR(STACK_OFFSET) ", %%rsp\n\t"
+        /* Counter is xmm13 */
+        "vpxor		%%xmm13, %%xmm13, %%xmm13\n\t"
+        "vpxor		%%xmm15, %%xmm15, %%xmm15\n\t"
+        "movl		%[ibytes], %%edx\n\t"
+        "cmpl		$12, %%edx\n\t"
+        "jne		35f\n\t"
+        CALC_IV_12_AVX2()
+        "jmp		39f\n\t"
+        "\n"
+        "35:\n\t"
+        CALC_IV_AVX2()
+        "\n"
+        "39:\n\t"
+
+        CALC_AAD_AVX2()
+
+        "# Calculate counter and H\n\t"
+        "vpsrlq		$63, " VAR(HR) ", %%xmm5\n\t"
+        "vpsllq		$1, " VAR(HR) ", %%xmm4\n\t"
+        "vpslldq	$8, %%xmm5, %%xmm5\n\t"
+        "vpor		%%xmm5, %%xmm4, %%xmm4\n\t"
+        "vpshufd	$0xff, " VAR(HR) ", " VAR(HR) "\n\t"
+        "vpsrad		$31, " VAR(HR) ", " VAR(HR) "\n\t"
+        "vpshufb	%[BSWAP_EPI64], %%xmm13, %%xmm13\n\t"
+        "vpand		%[MOD2_128], " VAR(HR) ", " VAR(HR) "\n\t"
+        "vpaddd		%[ONE], %%xmm13, %%xmm13\n\t"
+        "vpxor		%%xmm4, " VAR(HR) ", " VAR(HR) "\n\t"
+        "vmovdqu	%%xmm13, " VAR(CTR1) "\n\t"
+
+        "xorl		" VAR(KR) ", " VAR(KR) "\n\t"
+
+#if !defined(AES_GCM_AESNI_NO_UNROLL) && !defined(AES_GCM_AVX2_NO_UNROLL)
+        "cmpl		$128, %[nbytes]\n\t"
+        "jl		5f\n\t"
+
+        CALC_HT_8_AVX2()
+
+        "movl		%[nbytes], %%r13d\n\t"
+        "andl		$0xffffff80, %%r13d\n\t"
+        "\n"
+        "2:\n\t"
+        VAESENC_128_GHASH_AVX2(%%rcx, 128)
+        "addl		$128, " VAR(KR) "\n\t"
+        "cmpl		%%r13d, " VAR(KR) "\n\t"
+        "jl		2b\n\t"
+
+        "vmovdqa	%%xmm2, " VAR(XR) "\n\t"
+        "vmovdqu	(%%rsp), " VAR(HR) "\n\t"
+    "5:\n\t"
+        "movl		%[nbytes], %%edx\n\t"
+        "cmpl		%%edx, " VAR(KR) "\n\t"
+        "jge		55f\n\t"
+#endif
+        "movl		%[nbytes], %%r13d\n\t"
+        "andl		$0xfffffff0, %%r13d\n\t"
+        "cmpl		%%r13d, " VAR(KR) "\n\t"
+        "jge		13f\n\t"
+
+            "vmovdqa		%[MOD2_128], %%xmm0\n\t"
+        "\n"
+        "12:\n\t"
+        "vmovdqu	(%[in]," VAR(KR64) ",1), %%xmm9\n\t"
+        "vmovdqu	" VAR(CTR1) ", %%xmm5\n\t"
+        "vpshufb	%[BSWAP_MASK], %%xmm9, %%xmm1\n\t"
+        "vpshufb	%[BSWAP_EPI64], %%xmm5, %%xmm4\n\t"
+        "vpaddd		%[ONE], %%xmm5, %%xmm5\n\t"
+        "vpxor		" VAR(XR) ", %%xmm1, %%xmm1\n\t"
+        "vmovdqu	%%xmm5, " VAR(CTR1) "\n\t"
+        VAESENC_GFMUL_SB_AVX2(%%xmm9, HR, %%xmm1, CTR1)
+        "vmovdqu	%%xmm4, (%[out]," VAR(KR64) ",1)\n\t"
+        "addl		$16, " VAR(KR) "\n\t"
+        "cmpl		%%r13d, " VAR(KR) "\n\t"
+        "jl		12b\n\t"
+        "\n"
+        "13:\n\t"
+
+        AESENC_LAST15_DEC_AVX2()
+        "\n"
+        "55:\n\t"
+
+        CALC_TAG_AVX2()
+        "addq		$" VAR(STACK_OFFSET) ", %%rsp\n\t"
+        "popq		%%rdx\n\t"
+        CMP_TAG_AVX()
+        "vzeroupper\n\t"
+
+        :
+        : [KEY] "r" (key),
+          [in] "r" (in), [out] "r" (out), [nr] "r" (nr),
+          [nbytes] "r" (nbytes), [abytes] "r" (abytes), [addt] "r" (addt),
+          [ivec] "r" (iv), [ibytes] "r" (ivLen), [tbytes] "r" (tagLen),
+          [tag] "r" (tag), [res] "r" (res),
+          [BSWAP_MASK] "m" (BSWAP_MASK),
+          [BSWAP_EPI64] "m" (BSWAP_EPI64),
+          [ONE] "m" (ONE),
+#if !defined(AES_GCM_AESNI_NO_UNROLL) && !defined(AES_GCM_AVX2_NO_UNROLL)
+          [TWO] "m" (TWO), [THREE] "m" (THREE), [FOUR] "m" (FOUR),
+          [FIVE] "m" (FIVE), [SIX] "m" (SIX), [SEVEN] "m" (SEVEN),
+          [EIGHT] "m" (EIGHT),
+#endif
+          [MOD2_128] "m" (MOD2_128)
+        : "xmm15", "xmm14", "xmm13", "xmm12",
+          "xmm0", "xmm1", "xmm2", "xmm3", "memory",
+          "xmm4", "xmm5", "xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11",
+          "rcx", "r13"
+        );
+    }
+#endif /* HAVE_INTEL_AVX2 */
+#endif /* HAVE_INTEL_AVX1 */
+#endif /* HAVE_AES_DECRYPT */
+
+#else /* _MSC_VER */
+/* The following are for MSC based builds which do not allow
+ * inline assembly. Intrinsic functions are used instead. */
+
+#define aes_gcm_calc_iv_12(KEY, ivec, nr, H, Y, T)         \
+do                                                         \
+{                                                          \
+    word32 iv12[4];                                        \
+    iv12[0] = *(word32*)&ivec[0];                          \
+    iv12[1] = *(word32*)&ivec[4];                          \
+    iv12[2] = *(word32*)&ivec[8];                          \
+    iv12[3] = 0x01000000;                                  \
+    Y = _mm_loadu_si128((__m128i*)iv12);                   \
+                                                           \
+    /* (Compute E[ZERO, KS] and E[Y0, KS] together */      \
+    tmp1 = _mm_load_si128(&KEY[0]);                        \
+    tmp2 = _mm_xor_si128(Y, KEY[0]);                       \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[1]);                 \
+    tmp2 = _mm_aesenc_si128(tmp2, KEY[1]);                 \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[2]);                 \
+    tmp2 = _mm_aesenc_si128(tmp2, KEY[2]);                 \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[3]);                 \
+    tmp2 = _mm_aesenc_si128(tmp2, KEY[3]);                 \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[4]);                 \
+    tmp2 = _mm_aesenc_si128(tmp2, KEY[4]);                 \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[5]);                 \
+    tmp2 = _mm_aesenc_si128(tmp2, KEY[5]);                 \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[6]);                 \
+    tmp2 = _mm_aesenc_si128(tmp2, KEY[6]);                 \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[7]);                 \
+    tmp2 = _mm_aesenc_si128(tmp2, KEY[7]);                 \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[8]);                 \
+    tmp2 = _mm_aesenc_si128(tmp2, KEY[8]);                 \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[9]);                 \
+    tmp2 = _mm_aesenc_si128(tmp2, KEY[9]);                 \
+    lastKey = KEY[10];                                     \
+    if (nr > 10) {                                         \
+        tmp1 = _mm_aesenc_si128(tmp1, lastKey);            \
+        tmp2 = _mm_aesenc_si128(tmp2, lastKey);            \
+        tmp1 = _mm_aesenc_si128(tmp1, KEY[11]);            \
+        tmp2 = _mm_aesenc_si128(tmp2, KEY[11]);            \
+        lastKey = KEY[12];                                 \
+        if (nr > 12) {                                     \
+            tmp1 = _mm_aesenc_si128(tmp1, lastKey);        \
+            tmp2 = _mm_aesenc_si128(tmp2, lastKey);        \
+            tmp1 = _mm_aesenc_si128(tmp1, KEY[13]);        \
+            tmp2 = _mm_aesenc_si128(tmp2, KEY[13]);        \
+            lastKey = KEY[14];                             \
+        }                                                  \
+    }                                                      \
+    H = _mm_aesenclast_si128(tmp1, lastKey);               \
+    T = _mm_aesenclast_si128(tmp2, lastKey);               \
+    H = _mm_shuffle_epi8(H, BSWAP_MASK);                   \
+}                                                          \
+while (0)
+
+#define aes_gcm_calc_iv(KEY, ivec, ibytes, nr, H, Y, T)         \
+do                                                              \
+{                                                               \
+    if (ibytes % 16) {                                          \
+        i = ibytes / 16;                                        \
+        for (j=0; j < (int)(ibytes%16); j++)                    \
+            ((unsigned char*)&last_block)[j] = ivec[i*16+j];    \
+    }                                                           \
+    tmp1 = _mm_load_si128(&KEY[0]);                             \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[1]);                      \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[2]);                      \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[3]);                      \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[4]);                      \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[5]);                      \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[6]);                      \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[7]);                      \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[8]);                      \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[9]);                      \
+    lastKey = KEY[10];                                          \
+    if (nr > 10) {                                              \
+        tmp1 = _mm_aesenc_si128(tmp1, lastKey);                 \
+        tmp1 = _mm_aesenc_si128(tmp1, KEY[11]);                 \
+        lastKey = KEY[12];                                      \
+        if (nr > 12) {                                          \
+            tmp1 = _mm_aesenc_si128(tmp1, lastKey);             \
+            tmp1 = _mm_aesenc_si128(tmp1, KEY[13]);             \
+            lastKey = KEY[14];                                  \
+        }                                                       \
+    }                                                           \
+    H = _mm_aesenclast_si128(tmp1, lastKey);                    \
+    H = _mm_shuffle_epi8(H, BSWAP_MASK);                        \
+    Y = _mm_setzero_si128();                                    \
+    for (i=0; i < (int)(ibytes/16); i++) {                      \
+        tmp1 = _mm_loadu_si128(&((__m128i*)ivec)[i]);           \
+        tmp1 = _mm_shuffle_epi8(tmp1, BSWAP_MASK);              \
+        Y = _mm_xor_si128(Y, tmp1);                             \
+        Y = gfmul_sw(Y, H);                                     \
+    }                                                           \
+    if (ibytes % 16) {                                          \
+        tmp1 = last_block;                                      \
+        tmp1 = _mm_shuffle_epi8(tmp1, BSWAP_MASK);              \
+        Y = _mm_xor_si128(Y, tmp1);                             \
+        Y = gfmul_sw(Y, H);                                     \
+    }                                                           \
+    tmp1 = _mm_insert_epi64(tmp1, ibytes*8, 0);                 \
+    tmp1 = _mm_insert_epi64(tmp1, 0, 1);                        \
+    Y = _mm_xor_si128(Y, tmp1);                                 \
+    Y = gfmul_sw(Y, H);                                         \
+    Y = _mm_shuffle_epi8(Y, BSWAP_MASK); /* Compute E(K, Y0) */ \
+    tmp1 = _mm_xor_si128(Y, KEY[0]);                            \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[1]);                      \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[2]);                      \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[3]);                      \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[4]);                      \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[5]);                      \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[6]);                      \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[7]);                      \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[8]);                      \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[9]);                      \
+    lastKey = KEY[10];                                          \
+    if (nr > 10) {                                              \
+        tmp1 = _mm_aesenc_si128(tmp1, lastKey);                 \
+        tmp1 = _mm_aesenc_si128(tmp1, KEY[11]);                 \
+        lastKey = KEY[12];                                      \
+        if (nr > 12) {                                          \
+            tmp1 = _mm_aesenc_si128(tmp1, lastKey);             \
+            tmp1 = _mm_aesenc_si128(tmp1, KEY[13]);             \
+            lastKey = KEY[14];                                  \
+        }                                                       \
+    }                                                           \
+    T = _mm_aesenclast_si128(tmp1, lastKey);                    \
+}                                                               \
+while (0)
+
+#define AES_ENC_8(j)                       \
+    tmp1 = _mm_aesenc_si128(tmp1, KEY[j]); \
+    tmp2 = _mm_aesenc_si128(tmp2, KEY[j]); \
+    tmp3 = _mm_aesenc_si128(tmp3, KEY[j]); \
+    tmp4 = _mm_aesenc_si128(tmp4, KEY[j]); \
+    tmp5 = _mm_aesenc_si128(tmp5, KEY[j]); \
+    tmp6 = _mm_aesenc_si128(tmp6, KEY[j]); \
+    tmp7 = _mm_aesenc_si128(tmp7, KEY[j]); \
+    tmp8 = _mm_aesenc_si128(tmp8, KEY[j]);
+
+#define AES_ENC_LAST_8()                                                  \
+    tmp1 =_mm_aesenclast_si128(tmp1, lastKey);                            \
+    tmp2 =_mm_aesenclast_si128(tmp2, lastKey);                            \
+    tmp1 = _mm_xor_si128(tmp1, _mm_loadu_si128(&((__m128i*)in)[i*8+0]));  \
+    tmp2 = _mm_xor_si128(tmp2, _mm_loadu_si128(&((__m128i*)in)[i*8+1]));  \
+    _mm_storeu_si128(&((__m128i*)out)[i*8+0], tmp1);                      \
+    _mm_storeu_si128(&((__m128i*)out)[i*8+1], tmp2);                      \
+    tmp3 =_mm_aesenclast_si128(tmp3, lastKey);                            \
+    tmp4 =_mm_aesenclast_si128(tmp4, lastKey);                            \
+    tmp3 = _mm_xor_si128(tmp3, _mm_loadu_si128(&((__m128i*)in)[i*8+2]));  \
+    tmp4 = _mm_xor_si128(tmp4, _mm_loadu_si128(&((__m128i*)in)[i*8+3]));  \
+    _mm_storeu_si128(&((__m128i*)out)[i*8+2], tmp3);                      \
+    _mm_storeu_si128(&((__m128i*)out)[i*8+3], tmp4);                      \
+    tmp5 =_mm_aesenclast_si128(tmp5, lastKey);                            \
+    tmp6 =_mm_aesenclast_si128(tmp6, lastKey);                            \
+    tmp5 = _mm_xor_si128(tmp5, _mm_loadu_si128(&((__m128i*)in)[i*8+4]));  \
+    tmp6 = _mm_xor_si128(tmp6, _mm_loadu_si128(&((__m128i*)in)[i*8+5]));  \
+    _mm_storeu_si128(&((__m128i*)out)[i*8+4], tmp5);                      \
+    _mm_storeu_si128(&((__m128i*)out)[i*8+5], tmp6);                      \
+    tmp7 =_mm_aesenclast_si128(tmp7, lastKey);                            \
+    tmp8 =_mm_aesenclast_si128(tmp8, lastKey);                            \
+    tmp7 = _mm_xor_si128(tmp7, _mm_loadu_si128(&((__m128i*)in)[i*8+6]));  \
+    tmp8 = _mm_xor_si128(tmp8, _mm_loadu_si128(&((__m128i*)in)[i*8+7]));  \
+    _mm_storeu_si128(&((__m128i*)out)[i*8+6], tmp7);                      \
+    _mm_storeu_si128(&((__m128i*)out)[i*8+7], tmp8);
+
 
 static __m128i gfmul_sw(__m128i a, __m128i b)
 {
     __m128i r, t1, t2, t3, t4, t5, t6, t7;
-#ifndef WOLFSSL_AES_GCM_SLOW_CLMUL
-    /* 128 x 128 Carryless Multiply */
-    t3 = _mm_clmulepi64_si128(a, b, 0x10);
-    t2 = _mm_clmulepi64_si128(a, b, 0x01);
-    t1 = _mm_clmulepi64_si128(a, b, 0x00);
-    t4 = _mm_clmulepi64_si128(a, b, 0x11);
-    t3 = _mm_xor_si128(t3, t2);
-    t2 = _mm_slli_si128(t3, 8);
-    t3 = _mm_srli_si128(t3, 8);
-    t1 = _mm_xor_si128(t1, t2);
-    t4 = _mm_xor_si128(t4, t3);
-
-    /* shift left 1 bit - bits reversed */
-    t5 = _mm_srli_epi32(t1, 31);
-    t6 = _mm_srli_epi32(t4, 31);
-    t1 = _mm_slli_epi32(t1, 1);
-    t4 = _mm_slli_epi32(t4, 1);
-    t7 = _mm_srli_si128(t5, 12);
-    t5 = _mm_slli_si128(t5, 4);
-    t6 = _mm_slli_si128(t6, 4);
-    t4 = _mm_or_si128(t4, t7);
-    t1 = _mm_or_si128(t1, t5);
-    t4 = _mm_or_si128(t4, t6);
-
-    /* Reduction */
-    t2 = _mm_clmulepi64_si128(t1, MOD2_128, 0x10);
-    t3 = _mm_shuffle_epi32(t1, 78);
-    t3 = _mm_xor_si128(t3, t2);
-    t2 = _mm_clmulepi64_si128(t3, MOD2_128, 0x10);
-    t3 = _mm_shuffle_epi32(t3, 78);
-    t3 = _mm_xor_si128(t3, t2);
-    r = _mm_xor_si128(t4, t3);
-#else
     t2 = _mm_shuffle_epi32(b, 78);
     t3 = _mm_shuffle_epi32(a, 78);
@@ -3497,8 +6768,7 @@
     t7 = _mm_xor_si128(t7, t1);
     r = _mm_xor_si128(t4, t7);
-#endif
 
     return r;
-}
+        }
 
 static void gfmul_only(__m128i a, __m128i b, __m128i* r0, __m128i* r1)
@@ -3507,15 +6777,4 @@
 
     /* 128 x 128 Carryless Multiply */
-#ifndef WOLFSSL_AES_GCM_SLOW_CLMUL
-    t3 = _mm_clmulepi64_si128(a, b, 0x10);
-    t2 = _mm_clmulepi64_si128(a, b, 0x01);
-    t1 = _mm_clmulepi64_si128(a, b, 0x00);
-    t4 = _mm_clmulepi64_si128(a, b, 0x11);
-    t3 = _mm_xor_si128(t3, t2);
-    t2 = _mm_slli_si128(t3, 8);
-    t3 = _mm_srli_si128(t3, 8);
-    t1 = _mm_xor_si128(t1, t2);
-    t4 = _mm_xor_si128(t4, t3);
-#else
     t2 = _mm_shuffle_epi32(b, 78);
     t3 = _mm_shuffle_epi32(a, 78);
@@ -3531,8 +6790,7 @@
     t1 = _mm_xor_si128(t1, t3);
     t4 = _mm_xor_si128(t4, t2);
-#endif
     *r0 = _mm_xor_si128(t1, *r0);
     *r1 = _mm_xor_si128(t4, *r1);
-}
+            }
 
 static __m128i gfmul_shl1(__m128i a)
@@ -3549,18 +6807,9 @@
     t1 = _mm_xor_si128(t1, a);
     return t1;
-}
+        }
 
 static __m128i ghash_red(__m128i r0, __m128i r1)
 {
     __m128i t2, t3;
-#ifndef WOLFSSL_AES_GCM_SLOW_CLMUL
-    t2 = _mm_clmulepi64_si128(r0, MOD2_128, 0x10);
-    t3 = _mm_shuffle_epi32(r0, 78);
-    t3 = _mm_xor_si128(t3, t2);
-    t2 = _mm_clmulepi64_si128(t3, MOD2_128, 0x10);
-    t3 = _mm_shuffle_epi32(t3, 78);
-    t3 = _mm_xor_si128(t3, t2);
-    return _mm_xor_si128(r1, t3);
-#else
     __m128i t5, t6, t7;
 
@@ -3583,6 +6832,5 @@
     t7 = _mm_xor_si128(t7, r0);
     return _mm_xor_si128(r1, t7);
-#endif
-}
+            }
 
 static __m128i gfmul_shifted(__m128i a, __m128i b)
@@ -3591,5 +6839,5 @@
     gfmul_only(a, b, &t0, &t1);
     return ghash_red(t0, t1);
-}
+        }
 
 #ifndef AES_GCM_AESNI_NO_UNROLL
@@ -3609,34 +6857,16 @@
     gfmul_only(a8, b1, &t0, &t1);
     return ghash_red(t0, t1);
-}
+    }
 #endif
 
-/* See Intel® Carry-Less Multiplication Instruction
- * and its Usage for Computing the GCM Mode White Paper
- * by Shay Gueron, Intel Mobility Group, Israel Development Center;
- * and Michael E. Kounavis, Intel Labs, Circuits and Systems Research */
-
-
-/* Figure 9. AES-GCM – Encrypt With Single Block Ghash at a Time */
-
-static const __m128i ONE   = M128_INIT(0x0, 0x1);
-#ifndef AES_GCM_AESNI_NO_UNROLL
-static const __m128i TWO   = M128_INIT(0x0, 0x2);
-static const __m128i THREE = M128_INIT(0x0, 0x3);
-static const __m128i FOUR  = M128_INIT(0x0, 0x4);
-static const __m128i FIVE  = M128_INIT(0x0, 0x5);
-static const __m128i SIX   = M128_INIT(0x0, 0x6);
-static const __m128i SEVEN = M128_INIT(0x0, 0x7);
-static const __m128i EIGHT = M128_INIT(0x0, 0x8);
-#endif
-static const __m128i BSWAP_EPI64 = M128_INIT(0x0001020304050607, 0x08090a0b0c0d0e0f);
-static const __m128i BSWAP_MASK  = M128_INIT(0x08090a0b0c0d0e0f, 0x0001020304050607);
-
-static void AES_GCM_encrypt(const unsigned char *in, unsigned char *out,
-                            const unsigned char* addt,
-                            const unsigned char* ivec,
-                            unsigned char *tag, unsigned int nbytes,
-                            unsigned int abytes, unsigned int ibytes,
-                            const unsigned char* key, int nr)
+
+static void AES_GCM_encrypt(const unsigned char *in,
+                              unsigned char *out,
+                              const unsigned char* addt,
+                              const unsigned char* ivec,
+                              unsigned char *tag, unsigned int nbytes,
+                              unsigned int abytes, unsigned int ibytes,
+                              unsigned int tbytes,
+                              const unsigned char* key, int nr)
 {
     int i, j ,k;
@@ -3654,119 +6884,8 @@
 #endif
 
-    if (ibytes == 12) {
-        Y = _mm_setzero_si128();
-        for (j=0; j < 12; j++)
-            ((unsigned char*)&Y)[j] = ivec[j];
-        Y = _mm_insert_epi32(Y, 0x1000000, 3);
-            /* (Compute E[ZERO, KS] and E[Y0, KS] together */
-        tmp1 = _mm_xor_si128(X, KEY[0]);
-        tmp2 = _mm_xor_si128(Y, KEY[0]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[1]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[1]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[2]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[2]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[3]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[3]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[4]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[4]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[5]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[5]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[6]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[6]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[7]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[7]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[8]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[8]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[9]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[9]);
-        lastKey = KEY[10];
-        if (nr > 10) {
-            tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-            tmp2 = _mm_aesenc_si128(tmp2, lastKey);
-            tmp1 = _mm_aesenc_si128(tmp1, KEY[11]);
-            tmp2 = _mm_aesenc_si128(tmp2, KEY[11]);
-            lastKey = KEY[12];
-            if (nr > 12) {
-                tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-                tmp2 = _mm_aesenc_si128(tmp2, lastKey);
-                tmp1 = _mm_aesenc_si128(tmp1, KEY[13]);
-                tmp2 = _mm_aesenc_si128(tmp2, KEY[13]);
-                lastKey = KEY[14];
-            }
-        }
-        H = _mm_aesenclast_si128(tmp1, lastKey);
-        T = _mm_aesenclast_si128(tmp2, lastKey);
-        H = _mm_shuffle_epi8(H, BSWAP_MASK);
-    }
-    else {
-        if (ibytes % 16) {
-            i = ibytes / 16;
-            for (j=0; j < (int)(ibytes%16); j++)
-                ((unsigned char*)&last_block)[j] = ivec[i*16+j];
-        }
-        tmp1 = _mm_xor_si128(X, KEY[0]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[1]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[2]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[3]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[4]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[5]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[6]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[7]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[8]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[9]);
-        lastKey = KEY[10];
-        if (nr > 10) {
-            tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-            tmp1 = _mm_aesenc_si128(tmp1, KEY[11]);
-            lastKey = KEY[12];
-            if (nr > 12) {
-                tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-                tmp1 = _mm_aesenc_si128(tmp1, KEY[13]);
-                lastKey = KEY[14];
-            }
-        }
-        H = _mm_aesenclast_si128(tmp1, lastKey);
-        H = _mm_shuffle_epi8(H, BSWAP_MASK);
-        Y = _mm_setzero_si128();
-        for (i=0; i < (int)(ibytes/16); i++) {
-            tmp1 = _mm_loadu_si128(&((__m128i*)ivec)[i]);
-            tmp1 = _mm_shuffle_epi8(tmp1, BSWAP_MASK);
-            Y = _mm_xor_si128(Y, tmp1);
-            Y = gfmul_sw(Y, H);
-        }
-        if (ibytes % 16) {
-            tmp1 = last_block;
-            tmp1 = _mm_shuffle_epi8(tmp1, BSWAP_MASK);
-            Y = _mm_xor_si128(Y, tmp1);
-            Y = gfmul_sw(Y, H);
-        }
-        tmp1 = _mm_insert_epi64(tmp1, ibytes*8, 0);
-        tmp1 = _mm_insert_epi64(tmp1, 0, 1);
-        Y = _mm_xor_si128(Y, tmp1);
-        Y = gfmul_sw(Y, H);
-        Y = _mm_shuffle_epi8(Y, BSWAP_MASK); /* Compute E(K, Y0) */
-        tmp1 = _mm_xor_si128(Y, KEY[0]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[1]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[2]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[3]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[4]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[5]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[6]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[7]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[8]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[9]);
-        lastKey = KEY[10];
-        if (nr > 10) {
-            tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-            tmp1 = _mm_aesenc_si128(tmp1, KEY[11]);
-            lastKey = KEY[12];
-            if (nr > 12) {
-                tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-                tmp1 = _mm_aesenc_si128(tmp1, KEY[13]);
-                lastKey = KEY[14];
-            }
-        }
-        T = _mm_aesenclast_si128(tmp1, lastKey);
-    }
+    if (ibytes == 12)
+        aes_gcm_calc_iv_12(KEY, ivec, nr, H, Y, T);
+    else
+        aes_gcm_calc_iv(KEY, ivec, ibytes, nr, H, Y, T);
 
     for (i=0; i < (int)(abytes/16); i++) {
@@ -3785,5 +6904,4 @@
         X = gfmul_sw(X, H);
     }
-
     tmp1 = _mm_shuffle_epi8(Y, BSWAP_EPI64);
     ctr1 = _mm_add_epi32(tmp1, ONE);
@@ -3826,139 +6944,25 @@
         tmp7 =_mm_xor_si128(tmp7, KEY[0]);
         tmp8 =_mm_xor_si128(tmp8, KEY[0]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[1]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[1]);
-        tmp3 = _mm_aesenc_si128(tmp3, KEY[1]);
-        tmp4 = _mm_aesenc_si128(tmp4, KEY[1]);
-        tmp5 = _mm_aesenc_si128(tmp5, KEY[1]);
-        tmp6 = _mm_aesenc_si128(tmp6, KEY[1]);
-        tmp7 = _mm_aesenc_si128(tmp7, KEY[1]);
-        tmp8 = _mm_aesenc_si128(tmp8, KEY[1]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[2]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[2]);
-        tmp3 = _mm_aesenc_si128(tmp3, KEY[2]);
-        tmp4 = _mm_aesenc_si128(tmp4, KEY[2]);
-        tmp5 = _mm_aesenc_si128(tmp5, KEY[2]);
-        tmp6 = _mm_aesenc_si128(tmp6, KEY[2]);
-        tmp7 = _mm_aesenc_si128(tmp7, KEY[2]);
-        tmp8 = _mm_aesenc_si128(tmp8, KEY[2]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[3]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[3]);
-        tmp3 = _mm_aesenc_si128(tmp3, KEY[3]);
-        tmp4 = _mm_aesenc_si128(tmp4, KEY[3]);
-        tmp5 = _mm_aesenc_si128(tmp5, KEY[3]);
-        tmp6 = _mm_aesenc_si128(tmp6, KEY[3]);
-        tmp7 = _mm_aesenc_si128(tmp7, KEY[3]);
-        tmp8 = _mm_aesenc_si128(tmp8, KEY[3]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[4]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[4]);
-        tmp3 = _mm_aesenc_si128(tmp3, KEY[4]);
-        tmp4 = _mm_aesenc_si128(tmp4, KEY[4]);
-        tmp5 = _mm_aesenc_si128(tmp5, KEY[4]);
-        tmp6 = _mm_aesenc_si128(tmp6, KEY[4]);
-        tmp7 = _mm_aesenc_si128(tmp7, KEY[4]);
-        tmp8 = _mm_aesenc_si128(tmp8, KEY[4]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[5]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[5]);
-        tmp3 = _mm_aesenc_si128(tmp3, KEY[5]);
-        tmp4 = _mm_aesenc_si128(tmp4, KEY[5]);
-        tmp5 = _mm_aesenc_si128(tmp5, KEY[5]);
-        tmp6 = _mm_aesenc_si128(tmp6, KEY[5]);
-        tmp7 = _mm_aesenc_si128(tmp7, KEY[5]);
-        tmp8 = _mm_aesenc_si128(tmp8, KEY[5]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[6]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[6]);
-        tmp3 = _mm_aesenc_si128(tmp3, KEY[6]);
-        tmp4 = _mm_aesenc_si128(tmp4, KEY[6]);
-        tmp5 = _mm_aesenc_si128(tmp5, KEY[6]);
-        tmp6 = _mm_aesenc_si128(tmp6, KEY[6]);
-        tmp7 = _mm_aesenc_si128(tmp7, KEY[6]);
-        tmp8 = _mm_aesenc_si128(tmp8, KEY[6]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[7]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[7]);
-        tmp3 = _mm_aesenc_si128(tmp3, KEY[7]);
-        tmp4 = _mm_aesenc_si128(tmp4, KEY[7]);
-        tmp5 = _mm_aesenc_si128(tmp5, KEY[7]);
-        tmp6 = _mm_aesenc_si128(tmp6, KEY[7]);
-        tmp7 = _mm_aesenc_si128(tmp7, KEY[7]);
-        tmp8 = _mm_aesenc_si128(tmp8, KEY[7]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[8]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[8]);
-        tmp3 = _mm_aesenc_si128(tmp3, KEY[8]);
-        tmp4 = _mm_aesenc_si128(tmp4, KEY[8]);
-        tmp5 = _mm_aesenc_si128(tmp5, KEY[8]);
-        tmp6 = _mm_aesenc_si128(tmp6, KEY[8]);
-        tmp7 = _mm_aesenc_si128(tmp7, KEY[8]);
-        tmp8 = _mm_aesenc_si128(tmp8, KEY[8]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[9]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[9]);
-        tmp3 = _mm_aesenc_si128(tmp3, KEY[9]);
-        tmp4 = _mm_aesenc_si128(tmp4, KEY[9]);
-        tmp5 = _mm_aesenc_si128(tmp5, KEY[9]);
-        tmp6 = _mm_aesenc_si128(tmp6, KEY[9]);
-        tmp7 = _mm_aesenc_si128(tmp7, KEY[9]);
-        tmp8 = _mm_aesenc_si128(tmp8, KEY[9]);
+        AES_ENC_8(1);
+        AES_ENC_8(2);
+        AES_ENC_8(3);
+        AES_ENC_8(4);
+        AES_ENC_8(5);
+        AES_ENC_8(6);
+        AES_ENC_8(7);
+        AES_ENC_8(8);
+        AES_ENC_8(9);
         lastKey = KEY[10];
         if (nr > 10) {
-            tmp1 = _mm_aesenc_si128(tmp1, KEY[10]);
-            tmp2 = _mm_aesenc_si128(tmp2, KEY[10]);
-            tmp3 = _mm_aesenc_si128(tmp3, KEY[10]);
-            tmp4 = _mm_aesenc_si128(tmp4, KEY[10]);
-            tmp5 = _mm_aesenc_si128(tmp5, KEY[10]);
-            tmp6 = _mm_aesenc_si128(tmp6, KEY[10]);
-            tmp7 = _mm_aesenc_si128(tmp7, KEY[10]);
-            tmp8 = _mm_aesenc_si128(tmp8, KEY[10]);
-            tmp1 = _mm_aesenc_si128(tmp1, KEY[11]);
-            tmp2 = _mm_aesenc_si128(tmp2, KEY[11]);
-            tmp3 = _mm_aesenc_si128(tmp3, KEY[11]);
-            tmp4 = _mm_aesenc_si128(tmp4, KEY[11]);
-            tmp5 = _mm_aesenc_si128(tmp5, KEY[11]);
-            tmp6 = _mm_aesenc_si128(tmp6, KEY[11]);
-            tmp7 = _mm_aesenc_si128(tmp7, KEY[11]);
-            tmp8 = _mm_aesenc_si128(tmp8, KEY[11]);
+            AES_ENC_8(10);
+            AES_ENC_8(11);
             lastKey = KEY[12];
             if (nr > 12) {
-                tmp1 = _mm_aesenc_si128(tmp1, KEY[12]);
-                tmp2 = _mm_aesenc_si128(tmp2, KEY[12]);
-                tmp3 = _mm_aesenc_si128(tmp3, KEY[12]);
-                tmp4 = _mm_aesenc_si128(tmp4, KEY[12]);
-                tmp5 = _mm_aesenc_si128(tmp5, KEY[12]);
-                tmp6 = _mm_aesenc_si128(tmp6, KEY[12]);
-                tmp7 = _mm_aesenc_si128(tmp7, KEY[12]);
-                tmp8 = _mm_aesenc_si128(tmp8, KEY[12]);
-                tmp1 = _mm_aesenc_si128(tmp1, KEY[13]);
-                tmp2 = _mm_aesenc_si128(tmp2, KEY[13]);
-                tmp3 = _mm_aesenc_si128(tmp3, KEY[13]);
-                tmp4 = _mm_aesenc_si128(tmp4, KEY[13]);
-                tmp5 = _mm_aesenc_si128(tmp5, KEY[13]);
-                tmp6 = _mm_aesenc_si128(tmp6, KEY[13]);
-                tmp7 = _mm_aesenc_si128(tmp7, KEY[13]);
-                tmp8 = _mm_aesenc_si128(tmp8, KEY[13]);
+                AES_ENC_8(12);
+                AES_ENC_8(13);
                 lastKey = KEY[14];
             }
         }
-        tmp1 =_mm_aesenclast_si128(tmp1, lastKey);
-        tmp2 =_mm_aesenclast_si128(tmp2, lastKey);
-        tmp3 =_mm_aesenclast_si128(tmp3, lastKey);
-        tmp4 =_mm_aesenclast_si128(tmp4, lastKey);
-        tmp5 =_mm_aesenclast_si128(tmp5, lastKey);
-        tmp6 =_mm_aesenclast_si128(tmp6, lastKey);
-        tmp7 =_mm_aesenclast_si128(tmp7, lastKey);
-        tmp8 =_mm_aesenclast_si128(tmp8, lastKey);
-        tmp1 = _mm_xor_si128(tmp1, _mm_loadu_si128(&((__m128i*)in)[0]));
-        tmp2 = _mm_xor_si128(tmp2, _mm_loadu_si128(&((__m128i*)in)[1]));
-        tmp3 = _mm_xor_si128(tmp3, _mm_loadu_si128(&((__m128i*)in)[2]));
-        tmp4 = _mm_xor_si128(tmp4, _mm_loadu_si128(&((__m128i*)in)[3]));
-        tmp5 = _mm_xor_si128(tmp5, _mm_loadu_si128(&((__m128i*)in)[4]));
-        tmp6 = _mm_xor_si128(tmp6, _mm_loadu_si128(&((__m128i*)in)[5]));
-        tmp7 = _mm_xor_si128(tmp7, _mm_loadu_si128(&((__m128i*)in)[6]));
-        tmp8 = _mm_xor_si128(tmp8, _mm_loadu_si128(&((__m128i*)in)[7]));
-        _mm_storeu_si128(&((__m128i*)out)[0], tmp1);
-        _mm_storeu_si128(&((__m128i*)out)[1], tmp2);
-        _mm_storeu_si128(&((__m128i*)out)[2], tmp3);
-        _mm_storeu_si128(&((__m128i*)out)[3], tmp4);
-        _mm_storeu_si128(&((__m128i*)out)[4], tmp5);
-        _mm_storeu_si128(&((__m128i*)out)[5], tmp6);
-        _mm_storeu_si128(&((__m128i*)out)[6], tmp7);
-        _mm_storeu_si128(&((__m128i*)out)[7], tmp8);
+        AES_ENC_LAST_8();
 
         for (i=1; i < (int)(nbytes/16/8); i++) {
@@ -4135,28 +7139,5 @@
                 }
             }
-            tmp1 =_mm_aesenclast_si128(tmp1, lastKey);
-            tmp2 =_mm_aesenclast_si128(tmp2, lastKey);
-            tmp3 =_mm_aesenclast_si128(tmp3, lastKey);
-            tmp4 =_mm_aesenclast_si128(tmp4, lastKey);
-            tmp5 =_mm_aesenclast_si128(tmp5, lastKey);
-            tmp6 =_mm_aesenclast_si128(tmp6, lastKey);
-            tmp7 =_mm_aesenclast_si128(tmp7, lastKey);
-            tmp8 =_mm_aesenclast_si128(tmp8, lastKey);
-            tmp1 = _mm_xor_si128(tmp1, _mm_loadu_si128(&((__m128i*)in)[i*8+0]));
-            tmp2 = _mm_xor_si128(tmp2, _mm_loadu_si128(&((__m128i*)in)[i*8+1]));
-            tmp3 = _mm_xor_si128(tmp3, _mm_loadu_si128(&((__m128i*)in)[i*8+2]));
-            tmp4 = _mm_xor_si128(tmp4, _mm_loadu_si128(&((__m128i*)in)[i*8+3]));
-            tmp5 = _mm_xor_si128(tmp5, _mm_loadu_si128(&((__m128i*)in)[i*8+4]));
-            tmp6 = _mm_xor_si128(tmp6, _mm_loadu_si128(&((__m128i*)in)[i*8+5]));
-            tmp7 = _mm_xor_si128(tmp7, _mm_loadu_si128(&((__m128i*)in)[i*8+6]));
-            tmp8 = _mm_xor_si128(tmp8, _mm_loadu_si128(&((__m128i*)in)[i*8+7]));
-            _mm_storeu_si128(&((__m128i*)out)[i*8+0], tmp1);
-            _mm_storeu_si128(&((__m128i*)out)[i*8+1], tmp2);
-            _mm_storeu_si128(&((__m128i*)out)[i*8+2], tmp3);
-            _mm_storeu_si128(&((__m128i*)out)[i*8+3], tmp4);
-            _mm_storeu_si128(&((__m128i*)out)[i*8+4], tmp5);
-            _mm_storeu_si128(&((__m128i*)out)[i*8+5], tmp6);
-            _mm_storeu_si128(&((__m128i*)out)[i*8+6], tmp7);
-            _mm_storeu_si128(&((__m128i*)out)[i*8+7], tmp8);
+            AES_ENC_LAST_8();
         }
 
@@ -4204,5 +7185,5 @@
         X = gfmul_shifted(X, H);
     }
-#else
+#else /* AES_GCM_AESNI_NO_UNROLL */
     for (k = 0; k < (int)(nbytes/16) && k < 1; k++) {
         tmp1 = _mm_shuffle_epi8(ctr1, BSWAP_EPI64);
@@ -4233,6 +7214,6 @@
         _mm_storeu_si128(&((__m128i*)out)[k], tmp1);
         tmp1 = _mm_shuffle_epi8(tmp1, BSWAP_MASK);
-        X =_mm_xor_si128(X, tmp1);
-    }
+    X = _mm_xor_si128(X, tmp1);
+        }
     for (; k < (int)(nbytes/16); k++) {
         tmp1 = _mm_shuffle_epi8(ctr1, BSWAP_EPI64);
@@ -4263,11 +7244,12 @@
         tmp1 = _mm_xor_si128(tmp1, _mm_loadu_si128(&((__m128i*)in)[k]));
         _mm_storeu_si128(&((__m128i*)out)[k], tmp1);
-        tmp1 = _mm_shuffle_epi8(tmp1, BSWAP_MASK);
+            tmp1 = _mm_shuffle_epi8(tmp1, BSWAP_MASK);
         X =_mm_xor_si128(X, tmp1);
-    }
+        }
     if (k > 0) {
         X = gfmul_shifted(X, H);
-    }
-#endif
+        }
+#endif /* AES_GCM_AESNI_NO_UNROLL */
+
     /* If one partial block remains */
     if (nbytes % 16) {
@@ -4313,714 +7295,17 @@
     X = _mm_shuffle_epi8(X, BSWAP_MASK);
     T = _mm_xor_si128(X, T);
-    _mm_storeu_si128((__m128i*)tag, T);
-}
-
-#ifdef HAVE_INTEL_AVX2
-/* Encrypt with key in xmm12. */
-#define VAESENC()                                       \
-            "vaesenc	%%xmm12, %[tmp1], %[tmp1]\n\t"  \
-            "vaesenc	%%xmm12, %[tmp2], %[tmp2]\n\t"  \
-            "vaesenc	%%xmm12, %[tmp3], %[tmp3]\n\t"  \
-            "vaesenc	%%xmm12, %[tmp4], %[tmp4]\n\t"  \
-            "vaesenc	%%xmm12, %[tmp5], %[tmp5]\n\t"  \
-            "vaesenc	%%xmm12, %[tmp6], %[tmp6]\n\t"  \
-            "vaesenc	%%xmm12, %[tmp7], %[tmp7]\n\t"  \
-            "vaesenc	%%xmm12, %[tmp8], %[tmp8]\n\t"
-
-
-/* Encrypt and GCM mul with the nth round key. */
-#define VAESENC_PCLMUL_N(o1, o2, o3)                                \
-                "vmovaps	"#o1"(%[KEY]), %%xmm12\n\t"         \
-                "vmovdqu	"#o2"(%[out]), %%xmm1\n\t"          \
-                "vaesenc	%%xmm12, %[tmp1], %[tmp1]\n\t"      \
-                "vmovaps	"#o3"(%[HT]), %%xmm0\n\t"           \
-                "vpshufb	%[BSWAP_MASK], %%xmm1, %%xmm1\n\t"  \
-                "vaesenc	%%xmm12, %[tmp2], %[tmp2]\n\t"      \
-                "vpclmulqdq	$16, %%xmm1, %%xmm0, %%xmm13\n\t"   \
-                "vaesenc	%%xmm12, %[tmp3], %[tmp3]\n\t"      \
-                "vpclmulqdq	$1, %%xmm1, %%xmm0, %%xmm14\n\t"    \
-                "vaesenc	%%xmm12, %[tmp4], %[tmp4]\n\t"      \
-                "vpclmulqdq	$0, %%xmm1, %%xmm0, %%xmm15\n\t"    \
-                "vaesenc	%%xmm12, %[tmp5], %[tmp5]\n\t"      \
-                "vpclmulqdq	$17, %%xmm1, %%xmm0, %%xmm1\n\t"    \
-                "vaesenc	%%xmm12, %[tmp6], %[tmp6]\n\t"      \
-                "vpxor		%%xmm14, %%xmm13, %%xmm13\n\t"      \
-                "vpslldq	$8, %%xmm13, %%xmm14\n\t"           \
-                "vpsrldq	$8, %%xmm13, %%xmm13\n\t"           \
-                "vaesenc	%%xmm12, %[tmp7], %[tmp7]\n\t"      \
-                "vpxor		%%xmm15, %%xmm2, %%xmm2\n\t"        \
-                "vpxor		%%xmm1, %%xmm3, %%xmm3\n\t"         \
-                "vpxor		%%xmm14, %%xmm2, %%xmm2\n\t"        \
-                "vpxor		%%xmm13, %%xmm3, %%xmm3\n\t"        \
-                "vaesenc	%%xmm12, %[tmp8], %[tmp8]\n\t"
-
-static void AES_GCM_encrypt_avx2(const unsigned char *in, unsigned char *out,
-                                 const unsigned char* addt,
-                                 const unsigned char* ivec,
-                                 unsigned char *tag, unsigned int nbytes,
-                                 unsigned int abytes, unsigned int ibytes,
-                                 const unsigned char* key, int nr)
-{
-    int i, j ,k;
-    __m128i ctr1;
-    __m128i H, Y, T;
-    __m128i X = _mm_setzero_si128();
-    __m128i *KEY = (__m128i*)key, lastKey;
-    __m128i last_block = _mm_setzero_si128();
-#if !defined(AES_GCM_AESNI_NO_UNROLL) && !defined(AES_GCM_AVX2_NO_UNROLL)
-    __m128i HT[8];
-    register __m128i tmp1 asm("xmm4");
-    register __m128i tmp2 asm("xmm5");
-    register __m128i tmp3 asm("xmm6");
-    register __m128i tmp4 asm("xmm7");
-    register __m128i tmp5 asm("xmm8");
-    register __m128i tmp6 asm("xmm9");
-    register __m128i tmp7 asm("xmm10");
-    register __m128i tmp8 asm("xmm11");
-    __m128i pctr1[1];
-    register __m128i XV asm("xmm2");
-#else
-    __m128i tmp1, tmp2;
-#endif
-
-    if (ibytes == 12) {
-        Y = _mm_setzero_si128();
-        for (j=0; j < 12; j++)
-            ((unsigned char*)&Y)[j] = ivec[j];
-        Y = _mm_insert_epi32(Y, 0x1000000, 3);
-            /* (Compute E[ZERO, KS] and E[Y0, KS] together */
-        tmp1 = _mm_xor_si128(X, KEY[0]);
-        tmp2 = _mm_xor_si128(Y, KEY[0]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[1]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[1]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[2]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[2]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[3]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[3]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[4]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[4]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[5]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[5]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[6]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[6]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[7]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[7]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[8]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[8]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[9]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[9]);
-        lastKey = KEY[10];
-        if (nr > 10) {
-            tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-            tmp2 = _mm_aesenc_si128(tmp2, lastKey);
-            tmp1 = _mm_aesenc_si128(tmp1, KEY[11]);
-            tmp2 = _mm_aesenc_si128(tmp2, KEY[11]);
-            lastKey = KEY[12];
-            if (nr > 12) {
-                tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-                tmp2 = _mm_aesenc_si128(tmp2, lastKey);
-                tmp1 = _mm_aesenc_si128(tmp1, KEY[13]);
-                tmp2 = _mm_aesenc_si128(tmp2, KEY[13]);
-                lastKey = KEY[14];
-            }
-        }
-        H = _mm_aesenclast_si128(tmp1, lastKey);
-        T = _mm_aesenclast_si128(tmp2, lastKey);
-        H = _mm_shuffle_epi8(H, BSWAP_MASK);
-    }
-    else {
-        if (ibytes % 16) {
-            i = ibytes / 16;
-            for (j=0; j < (int)(ibytes%16); j++)
-                ((unsigned char*)&last_block)[j] = ivec[i*16+j];
-        }
-        tmp1 = _mm_xor_si128(X, KEY[0]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[1]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[2]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[3]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[4]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[5]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[6]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[7]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[8]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[9]);
-        lastKey = KEY[10];
-        if (nr > 10) {
-            tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-            tmp1 = _mm_aesenc_si128(tmp1, KEY[11]);
-            lastKey = KEY[12];
-            if (nr > 12) {
-                tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-                tmp1 = _mm_aesenc_si128(tmp1, KEY[13]);
-                lastKey = KEY[14];
-            }
-        }
-        H = _mm_aesenclast_si128(tmp1, lastKey);
-        H = _mm_shuffle_epi8(H, BSWAP_MASK);
-        Y = _mm_setzero_si128();
-        for (i=0; i < (int)(ibytes/16); i++) {
-            tmp1 = _mm_loadu_si128(&((__m128i*)ivec)[i]);
-            tmp1 = _mm_shuffle_epi8(tmp1, BSWAP_MASK);
-            Y = _mm_xor_si128(Y, tmp1);
-            Y = gfmul_sw(Y, H);
-        }
-        if (ibytes % 16) {
-            tmp1 = last_block;
-            tmp1 = _mm_shuffle_epi8(tmp1, BSWAP_MASK);
-            Y = _mm_xor_si128(Y, tmp1);
-            Y = gfmul_sw(Y, H);
-        }
-        tmp1 = _mm_insert_epi64(tmp1, ibytes*8, 0);
-        tmp1 = _mm_insert_epi64(tmp1, 0, 1);
-        Y = _mm_xor_si128(Y, tmp1);
-        Y = gfmul_sw(Y, H);
-        Y = _mm_shuffle_epi8(Y, BSWAP_MASK); /* Compute E(K, Y0) */
-        tmp1 = _mm_xor_si128(Y, KEY[0]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[1]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[2]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[3]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[4]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[5]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[6]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[7]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[8]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[9]);
-        lastKey = KEY[10];
-        if (nr > 10) {
-            tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-            tmp1 = _mm_aesenc_si128(tmp1, KEY[11]);
-            lastKey = KEY[12];
-            if (nr > 12) {
-                tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-                tmp1 = _mm_aesenc_si128(tmp1, KEY[13]);
-                lastKey = KEY[14];
-            }
-        }
-        T = _mm_aesenclast_si128(tmp1, lastKey);
-    }
-
-    for (i=0; i < (int)(abytes/16); i++) {
-        tmp1 = _mm_loadu_si128(&((__m128i*)addt)[i]);
-        tmp1 = _mm_shuffle_epi8(tmp1, BSWAP_MASK);
-        X = _mm_xor_si128(X, tmp1);
-        X = gfmul_sw(X, H);
-    }
-    if (abytes%16) {
-        last_block = _mm_setzero_si128();
-        for (j=0; j < (int)(abytes%16); j++)
-            ((unsigned char*)&last_block)[j] = addt[i*16+j];
-        tmp1 = last_block;
-        tmp1 = _mm_shuffle_epi8(tmp1, BSWAP_MASK);
-        X = _mm_xor_si128(X, tmp1);
-        X = gfmul_sw(X, H);
-    }
-
-    tmp1 = _mm_shuffle_epi8(Y, BSWAP_EPI64);
-    ctr1 = _mm_add_epi32(tmp1, ONE);
-    H = gfmul_shl1(H);
-
-#if !defined(AES_GCM_AESNI_NO_UNROLL) && !defined(AES_GCM_AVX2_NO_UNROLL)
-    i = 0;
-    if (nbytes >= 16*8) {
-        HT[0] = H;
-        HT[1] = gfmul_shifted(H, H);
-        HT[2] = gfmul_shifted(H, HT[1]);
-        HT[3] = gfmul_shifted(HT[1], HT[1]);
-        HT[4] = gfmul_shifted(HT[1], HT[2]);
-        HT[5] = gfmul_shifted(HT[2], HT[2]);
-        HT[6] = gfmul_shifted(HT[2], HT[3]);
-        HT[7] = gfmul_shifted(HT[3], HT[3]);
-
-        pctr1[0] = ctr1;
-        __asm__ __volatile__ (
-            "vmovaps	(%[pctr1]), %%xmm0\n\t"
-            "vmovaps	%[BSWAP_EPI64], %%xmm1\n\t"
-            "vpshufb	%%xmm1, %%xmm0, %[tmp1]\n\t"
-            "vpaddd	%[ONE], %%xmm0, %[tmp2]\n\t"
-            "vpshufb	%%xmm1, %[tmp2], %[tmp2]\n\t"
-            "vpaddd	%[TWO], %%xmm0, %[tmp3]\n\t"
-            "vpshufb	%%xmm1, %[tmp3], %[tmp3]\n\t"
-            "vpaddd	%[THREE], %%xmm0, %[tmp4]\n\t"
-            "vpshufb	%%xmm1, %[tmp4], %[tmp4]\n\t"
-            "vpaddd	%[FOUR], %%xmm0, %[tmp5]\n\t"
-            "vpshufb	%%xmm1, %[tmp5], %[tmp5]\n\t"
-            "vpaddd	%[FIVE], %%xmm0, %[tmp6]\n\t"
-            "vpshufb	%%xmm1, %[tmp6], %[tmp6]\n\t"
-            "vpaddd	%[SIX], %%xmm0, %[tmp7]\n\t"
-            "vpshufb	%%xmm1, %[tmp7], %[tmp7]\n\t"
-            "vpaddd	%[SEVEN], %%xmm0, %[tmp8]\n\t"
-            "vpshufb	%%xmm1, %[tmp8], %[tmp8]\n\t"
-            "vpaddd	%[EIGHT], %%xmm0, %%xmm0\n\t"
-
-            "vmovaps	(%[KEY]), %%xmm1\n\t"
-            "vmovaps	%%xmm0, (%[pctr1])\n\t"
-            "vpxor	%%xmm1, %[tmp1], %[tmp1]\n\t"
-            "vpxor	%%xmm1, %[tmp2], %[tmp2]\n\t"
-            "vpxor	%%xmm1, %[tmp3], %[tmp3]\n\t"
-            "vpxor	%%xmm1, %[tmp4], %[tmp4]\n\t"
-            "vpxor	%%xmm1, %[tmp5], %[tmp5]\n\t"
-            "vpxor	%%xmm1, %[tmp6], %[tmp6]\n\t"
-            "vpxor	%%xmm1, %[tmp7], %[tmp7]\n\t"
-            "vpxor	%%xmm1, %[tmp8], %[tmp8]\n\t"
-
-            "vmovaps	16(%[KEY]), %%xmm12\n\t"
-            VAESENC()
-            "vmovaps	32(%[KEY]), %%xmm12\n\t"
-            VAESENC()
-            "vmovaps	48(%[KEY]), %%xmm12\n\t"
-            VAESENC()
-            "vmovaps	64(%[KEY]), %%xmm12\n\t"
-            VAESENC()
-            "vmovaps	80(%[KEY]), %%xmm12\n\t"
-            VAESENC()
-            "vmovaps	96(%[KEY]), %%xmm12\n\t"
-            VAESENC()
-            "vmovaps	112(%[KEY]), %%xmm12\n\t"
-            VAESENC()
-            "vmovaps	128(%[KEY]), %%xmm12\n\t"
-            VAESENC()
-            "vmovaps	144(%[KEY]), %%xmm12\n\t"
-            VAESENC()
-            "cmpl	$11, %[nr]\n\t"
-            "vmovaps	160(%[KEY]), %%xmm12\n\t"
-            "jl         L_enc128_enclast\n\t"
-
-            VAESENC()
-            "vmovaps	176(%[KEY]), %%xmm12\n\t"
-            VAESENC()
-            "cmpl	$13, %[nr]\n\t"
-            "vmovaps	192(%[KEY]), %%xmm12\n\t"
-            "jl         L_enc128_enclast\n\t"
-
-            VAESENC()
-            "vmovaps	208(%[KEY]), %%xmm12\n\t"
-            VAESENC()
-            "vmovaps	224(%[KEY]), %%xmm12\n\t"
-            "\n"
-        "L_enc128_enclast:\n\t"
-            "vaesenclast	%%xmm12, %[tmp1], %[tmp1]\n\t"
-            "vaesenclast	%%xmm12, %[tmp2], %[tmp2]\n\t"
-            "vpxor		(%[in]), %[tmp1], %[tmp1]\n\t"
-            "vpxor		16(%[in]), %[tmp2], %[tmp2]\n\t"
-            "vmovdqu	%[tmp1], (%[out])\n\t"
-            "vmovdqu	%[tmp2], 16(%[out])\n\t"
-            "vaesenclast	%%xmm12, %[tmp3], %[tmp3]\n\t"
-            "vaesenclast	%%xmm12, %[tmp4], %[tmp4]\n\t"
-            "vpxor		32(%[in]), %[tmp3], %[tmp3]\n\t"
-            "vpxor		48(%[in]), %[tmp4], %[tmp4]\n\t"
-            "vmovdqu	%[tmp3], 32(%[out])\n\t"
-            "vmovdqu	%[tmp4], 48(%[out])\n\t"
-            "vaesenclast	%%xmm12, %[tmp5], %[tmp5]\n\t"
-            "vaesenclast	%%xmm12, %[tmp6], %[tmp6]\n\t"
-            "vpxor		64(%[in]), %[tmp5], %[tmp5]\n\t"
-            "vpxor		80(%[in]), %[tmp6], %[tmp6]\n\t"
-            "vmovdqu	%[tmp5], 64(%[out])\n\t"
-            "vmovdqu	%[tmp6], 80(%[out])\n\t"
-            "vaesenclast	%%xmm12, %[tmp7], %[tmp7]\n\t"
-            "vaesenclast	%%xmm12, %[tmp8], %[tmp8]\n\t"
-            "vpxor		96(%[in]), %[tmp7], %[tmp7]\n\t"
-            "vpxor		112(%[in]), %[tmp8], %[tmp8]\n\t"
-            "vmovdqu	%[tmp7], 96(%[out])\n\t"
-            "vmovdqu	%[tmp8], 112(%[out])\n\t"
-
-        : [tmp1] "=xr" (tmp1), [tmp2] "=xr" (tmp2), [tmp3] "=xr" (tmp3),
-          [tmp4] "=xr" (tmp4), [tmp5] "=xr" (tmp5), [tmp6] "=xr" (tmp6),
-          [tmp7] "=xr" (tmp7), [tmp8] "=xr" (tmp8)
-        : [KEY] "r" (KEY), [pctr1] "r" (pctr1),
-          [in] "r" (&in[i*16*8]), [out] "r" (&out[i*16*8]), [nr] "r" (nr),
-          [BSWAP_EPI64] "m" (BSWAP_EPI64),
-          [ONE] "m" (ONE), [TWO] "m" (TWO),
-          [THREE] "m" (THREE), [FOUR] "m" (FOUR),
-          [FIVE] "m" (FIVE), [SIX] "m" (SIX),
-          [SEVEN] "m" (SEVEN), [EIGHT] "m" (EIGHT)
-        : "xmm15", "xmm14", "xmm13", "xmm12",
-          "xmm0", "xmm1", "xmm3", "memory"
-        );
-
-        XV = X;
-        for (i=1; i < (int)(nbytes/16/8); i++) {
-            __asm__ __volatile__ (
-                "vmovaps	(%[pctr1]), %%xmm0\n\t"
-                "vmovaps	%[BSWAP_EPI64], %%xmm1\n\t"
-                "vpshufb	%%xmm1, %%xmm0, %[tmp1]\n\t"
-                "vpaddd		%[ONE], %%xmm0, %[tmp2]\n\t"
-                "vpshufb	%%xmm1, %[tmp2], %[tmp2]\n\t"
-                "vpaddd		%[TWO], %%xmm0, %[tmp3]\n\t"
-                "vpshufb	%%xmm1, %[tmp3], %[tmp3]\n\t"
-                "vpaddd		%[THREE], %%xmm0, %[tmp4]\n\t"
-                "vpshufb	%%xmm1, %[tmp4], %[tmp4]\n\t"
-                "vpaddd		%[FOUR], %%xmm0, %[tmp5]\n\t"
-                "vpshufb	%%xmm1, %[tmp5], %[tmp5]\n\t"
-                "vpaddd		%[FIVE], %%xmm0, %[tmp6]\n\t"
-                "vpshufb	%%xmm1, %[tmp6], %[tmp6]\n\t"
-                "vpaddd		%[SIX], %%xmm0, %[tmp7]\n\t"
-                "vpshufb	%%xmm1, %[tmp7], %[tmp7]\n\t"
-                "vpaddd		%[SEVEN], %%xmm0, %[tmp8]\n\t"
-                "vpshufb	%%xmm1, %[tmp8], %[tmp8]\n\t"
-                "vpaddd		%[EIGHT], %%xmm0, %%xmm0\n\t"
-
-                "vmovaps	(%[KEY]), %%xmm1\n\t"
-                "vmovaps	%%xmm0, (%[pctr1])\n\t"
-                "vpxor		%%xmm1, %[tmp1], %[tmp1]\n\t"
-                "vpxor		%%xmm1, %[tmp2], %[tmp2]\n\t"
-                "vpxor		%%xmm1, %[tmp3], %[tmp3]\n\t"
-                "vpxor		%%xmm1, %[tmp4], %[tmp4]\n\t"
-                "vpxor		%%xmm1, %[tmp5], %[tmp5]\n\t"
-                "vpxor		%%xmm1, %[tmp6], %[tmp6]\n\t"
-                "vpxor		%%xmm1, %[tmp7], %[tmp7]\n\t"
-                "vpxor		%%xmm1, %[tmp8], %[tmp8]\n\t"
-
-                "vmovaps	16(%[KEY]), %%xmm12\n\t"
-                "vmovdqu	-128(%[out]), %%xmm1\n\t"
-                "vaesenc	%%xmm12, %[tmp1], %[tmp1]\n\t"
-                "vmovaps	112(%[HT]), %%xmm0\n\t"
-                "vpshufb	%[BSWAP_MASK], %%xmm1, %%xmm1\n\t"
-                "vpxor		%[XV], %%xmm1, %%xmm1\n\t"
-                "vaesenc	%%xmm12, %[tmp2], %[tmp2]\n\t"
-                "vpclmulqdq	$16, %%xmm1, %%xmm0, %%xmm13\n\t"
-                "vaesenc	%%xmm12, %[tmp3], %[tmp3]\n\t"
-                "vpclmulqdq	$1, %%xmm1, %%xmm0, %%xmm14\n\t"
-                "vaesenc	%%xmm12, %[tmp4], %[tmp4]\n\t"
-                "vpclmulqdq	$0, %%xmm1, %%xmm0, %%xmm15\n\t"
-                "vaesenc	%%xmm12, %[tmp5], %[tmp5]\n\t"
-                "vpclmulqdq	$17, %%xmm1, %%xmm0, %%xmm1\n\t"
-                "vaesenc	%%xmm12, %[tmp6], %[tmp6]\n\t"
-                "vpxor		%%xmm14, %%xmm13, %%xmm13\n\t"
-                "vpslldq	$8, %%xmm13, %%xmm2\n\t"
-                "vpsrldq	$8, %%xmm13, %%xmm13\n\t"
-                "vaesenc	%%xmm12, %[tmp7], %[tmp7]\n\t"
-                "vpxor		%%xmm15, %%xmm2, %%xmm2\n\t"
-                "vpxor		%%xmm13, %%xmm1, %%xmm3\n\t"
-                "vaesenc	%%xmm12, %[tmp8], %[tmp8]\n\t"
-
-                VAESENC_PCLMUL_N( 32, -112, 96)
-                VAESENC_PCLMUL_N( 48,  -96, 80)
-                VAESENC_PCLMUL_N( 64,  -80, 64)
-                VAESENC_PCLMUL_N( 80,  -64, 48)
-                VAESENC_PCLMUL_N( 96,  -48, 32)
-                VAESENC_PCLMUL_N(112,  -32, 16)
-                VAESENC_PCLMUL_N(128,  -16,  0)
-
-                "vmovaps	144(%[KEY]), %%xmm12\n\t"
-                "vaesenc	%%xmm12, %[tmp1], %[tmp1]\n\t"
-                "vmovdqa	%[MOD2_128], %%xmm0\n\t"
-                "vaesenc	%%xmm12, %[tmp2], %[tmp2]\n\t"
-                "vpclmulqdq	$16, %%xmm0, %%xmm2, %%xmm14\n\t"
-                "vaesenc	%%xmm12, %[tmp3], %[tmp3]\n\t"
-                "vpshufd	$78, %%xmm2, %%xmm13\n\t"
-                "vpxor		%%xmm14, %%xmm13, %%xmm13\n\t"
-                "vaesenc	%%xmm12, %[tmp4], %[tmp4]\n\t"
-                "vpclmulqdq	$16, %%xmm0, %%xmm13, %%xmm14\n\t"
-                "vaesenc	%%xmm12, %[tmp5], %[tmp5]\n\t"
-                "vpshufd	$78, %%xmm13, %%xmm13\n\t"
-                "vpxor		%%xmm14, %%xmm13, %%xmm13\n\t"
-                "vpxor		%%xmm3, %%xmm13, %%xmm13\n\t"
-                "vaesenc	%%xmm12, %[tmp6], %[tmp6]\n\t"
-                "vmovdqa	%%xmm13, %%xmm2\n\t"
-                "vaesenc	%%xmm12, %[tmp7], %[tmp7]\n\t"
-                "vaesenc	%%xmm12, %[tmp8], %[tmp8]\n\t"
-                "cmpl		$11, %[nr]\n\t"
-                "vmovaps	160(%[KEY]), %%xmm12\n\t"
-                "jl             %=f\n\t"
-
-                VAESENC()
-                "vmovaps	176(%[KEY]), %%xmm12\n\t"
-                VAESENC()
-                "cmpl		$13, %[nr]\n\t"
-                "vmovaps	192(%[KEY]), %%xmm12\n\t"
-                "jl             %=f\n\t"
-
-                VAESENC()
-                "vmovaps	208(%[KEY]), %%xmm12\n\t"
-                VAESENC()
-                "vmovaps	224(%[KEY]), %%xmm12\n\t"
-
-                "%=:\n\t"
-                "vaesenclast	%%xmm12, %[tmp1], %[tmp1]\n\t"
-                "vaesenclast	%%xmm12, %[tmp2], %[tmp2]\n\t"
-                "vpxor		(%[in]), %[tmp1], %[tmp1]\n\t"
-                "vpxor		16(%[in]), %[tmp2], %[tmp2]\n\t"
-                "vmovdqu	%[tmp1], (%[out])\n\t"
-                "vmovdqu	%[tmp2], 16(%[out])\n\t"
-                "vaesenclast	%%xmm12, %[tmp3], %[tmp3]\n\t"
-                "vaesenclast	%%xmm12, %[tmp4], %[tmp4]\n\t"
-                "vpxor		32(%[in]), %[tmp3], %[tmp3]\n\t"
-                "vpxor		48(%[in]), %[tmp4], %[tmp4]\n\t"
-                "vmovdqu	%[tmp3], 32(%[out])\n\t"
-                "vmovdqu	%[tmp4], 48(%[out])\n\t"
-                "vaesenclast	%%xmm12, %[tmp5], %[tmp5]\n\t"
-                "vaesenclast	%%xmm12, %[tmp6], %[tmp6]\n\t"
-                "vpxor		64(%[in]), %[tmp5], %[tmp5]\n\t"
-                "vpxor		80(%[in]), %[tmp6], %[tmp6]\n\t"
-                "vmovdqu	%[tmp5], 64(%[out])\n\t"
-                "vmovdqu	%[tmp6], 80(%[out])\n\t"
-                "vaesenclast	%%xmm12, %[tmp7], %[tmp7]\n\t"
-                "vaesenclast	%%xmm12, %[tmp8], %[tmp8]\n\t"
-                "vpxor		96(%[in]), %[tmp7], %[tmp7]\n\t"
-                "vpxor		112(%[in]), %[tmp8], %[tmp8]\n\t"
-                "vmovdqu	%[tmp7], 96(%[out])\n\t"
-                "vmovdqu	%[tmp8], 112(%[out])\n\t"
-
-            : [tmp1] "=xr" (tmp1), [tmp2] "=xr" (tmp2), [tmp3] "=xr" (tmp3),
-              [tmp4] "=xr" (tmp4), [tmp5] "=xr" (tmp5), [tmp6] "=xr" (tmp6),
-              [tmp7] "=xr" (tmp7), [tmp8] "=xr" (tmp8),
-              [XV] "+xr" (XV)
-            : [KEY] "r" (KEY), [HT] "r" (HT), [pctr1] "r" (pctr1),
-              [in] "r" (&in[i*16*8]), [out] "r" (&out[i*16*8]), [nr] "r" (nr),
-              [BSWAP_MASK] "m" (BSWAP_MASK),
-              [BSWAP_EPI64] "m" (BSWAP_EPI64),
-              [ONE] "m" (ONE), [TWO] "m" (TWO),
-              [THREE] "m" (THREE), [FOUR] "m" (FOUR),
-              [FIVE] "m" (FIVE), [SIX] "m" (SIX),
-              [SEVEN] "m" (SEVEN), [EIGHT] "m" (EIGHT),
-              [MOD2_128] "m" (MOD2_128)
-            : "xmm15", "xmm14", "xmm13", "xmm12",
-              "xmm0", "xmm1", "xmm3", "memory"
-            );
-        }
-        X = XV;
-        ctr1 = pctr1[0];
-        tmp1 = _mm_shuffle_epi8(tmp1, BSWAP_MASK);
-        tmp2 = _mm_shuffle_epi8(tmp2, BSWAP_MASK);
-        tmp3 = _mm_shuffle_epi8(tmp3, BSWAP_MASK);
-        tmp4 = _mm_shuffle_epi8(tmp4, BSWAP_MASK);
-        tmp5 = _mm_shuffle_epi8(tmp5, BSWAP_MASK);
-        tmp6 = _mm_shuffle_epi8(tmp6, BSWAP_MASK);
-        tmp7 = _mm_shuffle_epi8(tmp7, BSWAP_MASK);
-        tmp8 = _mm_shuffle_epi8(tmp8, BSWAP_MASK);
-        tmp1 = _mm_xor_si128(X, tmp1);
-        X = gfmul8(tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8,
-                   HT[0], HT[1], HT[2], HT[3], HT[4], HT[5], HT[6], HT[7]);
-    }
-    for (k = i*8; k < (int)(nbytes/16); k++) {
-        __asm__ __volatile__ (
-            "vpshufb		%[BSWAP_EPI64], %[ctr1], %[tmp1]\n\t"
-            "vpaddd		%[ONE], %[ctr1], %[ctr1]\n\t"
-            "vpxor		(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vaesenc		16(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vaesenc		32(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vaesenc		48(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vaesenc		64(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vaesenc		80(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vaesenc		96(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vaesenc		112(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vaesenc		128(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vaesenc		144(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "cmpl		$11, %[nr]\n\t"
-            "vmovaps		160(%[KEY]), %[tmp2]\n\t"
-            "jl			%=f\n\t"
-            "vaesenc		%[tmp2], %[tmp1], %[tmp1]\n\t"
-            "vaesenc		176(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "cmpl		$13, %[nr]\n\t"
-            "vmovaps		192(%[KEY]), %[tmp2]\n\t"
-            "jl			%=f\n\t"
-            "vaesenc		%[tmp2], %[tmp1], %[tmp1]\n\t"
-            "vaesenc		208(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vmovaps		224(%[KEY]), %[tmp2]\n\t"
-            "%=:\n\t"
-            "vaesenclast	%[tmp2], %[tmp1], %[tmp1]\n\t"
-            "vpxor		(%[in]), %[tmp1], %[tmp1]\n\t"
-            "vmovdqu		%[tmp1], (%[out])\n\t"
-            "vpshufb		%[BSWAP_MASK], %[tmp1], %[tmp1]\n\t"
-
-            "vpxor		%[tmp1], %[X], %[X]\n\t"
-            "# Carryless Multiply X by H (128 x 128)\n\t"
-            "vpclmulqdq		$16, %[H], %[X], %%xmm13\n\t"
-            "vpclmulqdq		$1, %[H], %[X], %%xmm14\n\t"
-            "vpclmulqdq		$0, %[H], %[X], %%xmm15\n\t"
-            "vpclmulqdq		$17, %[H], %[X], %%xmm1\n\t"
-            "vpxor		%%xmm14, %%xmm13, %%xmm13\n\t"
-            "vpslldq		$8, %%xmm13, %%xmm2\n\t"
-            "vpsrldq		$8, %%xmm13, %%xmm13\n\t"
-            "vpxor		%%xmm15, %%xmm2, %%xmm2\n\t"
-            "vpxor		%%xmm13, %%xmm1, %%xmm3\n\t"
-            "# Reduce\n\t"
-            "vmovdqa		%[MOD2_128], %%xmm0\n\t"
-            "vpclmulqdq		$16, %%xmm0, %%xmm2, %%xmm14\n\t"
-            "vpshufd		$78, %%xmm2, %%xmm13\n\t"
-            "vpxor		%%xmm14, %%xmm13, %%xmm13\n\t"
-            "vpclmulqdq		$16, %%xmm0, %%xmm13, %%xmm14\n\t"
-            "vpshufd		$78, %%xmm13, %%xmm13\n\t"
-            "vpxor		%%xmm14, %%xmm13, %%xmm13\n\t"
-            "vpxor		%%xmm3, %%xmm13, %%xmm13\n\t"
-            "vmovdqa		%%xmm13, %[X]\n\t"
-            "# End Reduce\n\t"
-
-        : [tmp1] "+xr" (tmp1), [tmp2] "=xr" (tmp2),
-          [H] "+xr" (H), [X] "+xr" (X), [ctr1] "+xr" (ctr1)
-        : [KEY] "r" (KEY),
-          [in] "r" (&in[k*16]), [out] "r" (&out[k*16]), [nr] "r" (nr),
-          [BSWAP_MASK] "m" (BSWAP_MASK),
-          [BSWAP_EPI64] "m" (BSWAP_EPI64),
-          [ONE] "m" (ONE),
-          [MOD2_128] "m" (MOD2_128)
-        : "xmm15", "xmm14", "xmm13",
-          "xmm0", "xmm1", "xmm2", "xmm3", "memory"
-        );
-    }
-#else
-    for (k = 0; k < (int)(nbytes/16) && k < 1; k++) {
-        __asm__ __volatile__ (
-            "vpshufb		%[BSWAP_EPI64], %[ctr1], %[tmp1]\n\t"
-            "vpaddd		%[ONE], %[ctr1], %[ctr1]\n\t"
-            "vpxor		(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vaesenc		16(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vaesenc		32(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vaesenc		48(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vaesenc		64(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vaesenc		80(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vaesenc		96(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vaesenc		112(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vaesenc		128(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vaesenc		144(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "cmpl		$11, %[nr]\n\t"
-            "vmovaps		160(%[KEY]), %[tmp2]\n\t"
-            "jl			%=f\n\t"
-            "vaesenc		%[tmp2], %[tmp1], %[tmp1]\n\t"
-            "vaesenc		176(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "cmpl		$13, %[nr]\n\t"
-            "vmovaps		192(%[KEY]), %[tmp2]\n\t"
-            "jl			%=f\n\t"
-            "vaesenc		%[tmp2], %[tmp1], %[tmp1]\n\t"
-            "vaesenc		208(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vmovaps		224(%[KEY]), %[tmp2]\n\t"
-            "%=:\n\t"
-            "vaesenclast	%[tmp2], %[tmp1], %[tmp1]\n\t"
-            "vpxor		(%[in]), %[tmp1], %[tmp1]\n\t"
-            "vmovdqu		%[tmp1], (%[out])\n\t"
-            "vpshufb		%[BSWAP_MASK], %[tmp1], %[tmp1]\n\t"
-            "vpxor		%[tmp1], %[X], %[X]\n\t"
-
-        : [tmp1] "+xr" (tmp1), [tmp2] "=xr" (tmp2),
-          [H] "+xr" (H), [X] "+xr" (X), [ctr1] "+xr" (ctr1)
-        : [KEY] "r" (KEY),
-          [in] "r" (&in[k*16]), [out] "r" (&out[k*16]), [nr] "r" (nr),
-          [BSWAP_MASK] "m" (BSWAP_MASK),
-          [BSWAP_EPI64] "m" (BSWAP_EPI64),
-          [ONE] "m" (ONE),
-          [MOD2_128] "m" (MOD2_128)
-        : "memory"
-        );
-    }
-    for (; k < (int)(nbytes/16); k++) {
-        __asm__ __volatile__ (
-            "vpshufb		%[BSWAP_EPI64], %[ctr1], %[tmp1]\n\t"
-            "vpaddd		%[ONE], %[ctr1], %[ctr1]\n\t"
-            "vpxor		(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vaesenc		16(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vpclmulqdq		$16, %[H], %[X], %%xmm13\n\t"
-            "vaesenc		32(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vpclmulqdq		$1, %[H], %[X], %%xmm14\n\t"
-            "vaesenc		48(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vpclmulqdq		$0, %[H], %[X], %%xmm15\n\t"
-            "vaesenc		64(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vpclmulqdq		$17, %[H], %[X], %%xmm1\n\t"
-            "vaesenc		80(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vpxor		%%xmm14, %%xmm13, %%xmm13\n\t"
-            "vpslldq		$8, %%xmm13, %%xmm2\n\t"
-            "vpsrldq		$8, %%xmm13, %%xmm13\n\t"
-            "vaesenc		96(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vpxor		%%xmm15, %%xmm2, %%xmm2\n\t"
-            "vpxor		%%xmm13, %%xmm1, %%xmm3\n\t"
-            "vmovdqa		%[MOD2_128], %%xmm0\n\t"
-            "vpclmulqdq		$16, %%xmm0, %%xmm2, %%xmm14\n\t"
-            "vaesenc		112(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vpshufd		$78, %%xmm2, %%xmm13\n\t"
-            "vpxor		%%xmm14, %%xmm13, %%xmm13\n\t"
-            "vpclmulqdq		$16, %%xmm0, %%xmm13, %%xmm14\n\t"
-            "vaesenc		128(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vpshufd		$78, %%xmm13, %%xmm13\n\t"
-            "vpxor		%%xmm14, %%xmm13, %%xmm13\n\t"
-            "vpxor		%%xmm3, %%xmm13, %%xmm13\n\t"
-            "vaesenc		144(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vmovdqa		%%xmm13, %[X]\n\t"
-            "cmpl		$11, %[nr]\n\t"
-            "vmovaps		160(%[KEY]), %[tmp2]\n\t"
-            "jl			%=f\n\t"
-            "vaesenc		%[tmp2], %[tmp1], %[tmp1]\n\t"
-            "vaesenc		176(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "cmpl		$13, %[nr]\n\t"
-            "vmovaps		192(%[KEY]), %[tmp2]\n\t"
-            "jl			%=f\n\t"
-            "vaesenc		%[tmp2], %[tmp1], %[tmp1]\n\t"
-            "vaesenc		208(%[KEY]), %[tmp1], %[tmp1]\n\t"
-            "vmovaps		224(%[KEY]), %[tmp2]\n\t"
-            "%=:\n\t"
-            "vaesenclast	%[tmp2], %[tmp1], %[tmp1]\n\t"
-            "vpxor		(%[in]), %[tmp1], %[tmp1]\n\t"
-            "vmovdqu		%[tmp1], (%[out])\n\t"
-            "vpshufb		%[BSWAP_MASK], %[tmp1], %[tmp1]\n\t"
-            "vpxor		%[tmp1], %[X], %[X]\n\t"
-
-        : [tmp1] "+xr" (tmp1), [tmp2] "=xr" (tmp2),
-          [H] "+xr" (H), [X] "+xr" (X), [ctr1] "+xr" (ctr1)
-        : [KEY] "r" (KEY),
-          [in] "r" (&in[k*16]), [out] "r" (&out[k*16]), [nr] "r" (nr),
-          [BSWAP_MASK] "m" (BSWAP_MASK),
-          [BSWAP_EPI64] "m" (BSWAP_EPI64),
-          [ONE] "m" (ONE),
-          [MOD2_128] "m" (MOD2_128)
-        : "xmm15", "xmm14", "xmm13",
-          "xmm0", "xmm1", "xmm2", "xmm3", "memory"
-        );
-    }
-    if (k > 0) {
-        X = gfmul_shifted(X, H);
-    }
-#endif
-    /* If one partial block remains */
-    if (nbytes % 16) {
-        tmp1 = _mm_shuffle_epi8(ctr1, BSWAP_EPI64);
-        tmp1 = _mm_xor_si128(tmp1, KEY[0]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[1]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[2]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[3]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[4]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[5]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[6]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[7]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[8]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[9]);
-        lastKey = KEY[10];
-        if (nr > 10) {
-            tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-            tmp1 = _mm_aesenc_si128(tmp1, KEY[11]);
-            lastKey = KEY[12];
-            if (nr > 12) {
-                tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-                tmp1 = _mm_aesenc_si128(tmp1, KEY[13]);
-                lastKey = KEY[14];
-            }
-        }
-        tmp1 = _mm_aesenclast_si128(tmp1, lastKey);
-        last_block = tmp1;
-        for (j=0; j < (int)(nbytes%16); j++)
-            ((unsigned char*)&last_block)[j] = in[k*16+j];
-        tmp1 = _mm_xor_si128(tmp1, last_block);
-        last_block = tmp1;
-        for (j=0; j < (int)(nbytes%16); j++)
-            out[k*16+j] = ((unsigned char*)&last_block)[j];
-        tmp1 = last_block;
-        tmp1 = _mm_shuffle_epi8(tmp1, BSWAP_MASK);
-        X =_mm_xor_si128(X, tmp1);
-        X = gfmul_shifted(X, H);
-    }
-    tmp1 = _mm_insert_epi64(tmp1, nbytes*8, 0);
-    tmp1 = _mm_insert_epi64(tmp1, abytes*8, 1);
-    X = _mm_xor_si128(X, tmp1);
-    X = gfmul_shifted(X, H);
-    X = _mm_shuffle_epi8(X, BSWAP_MASK);
-    T = _mm_xor_si128(X, T);
-    _mm_storeu_si128((__m128i*)tag, T);
-}
-#endif /* HAVE_INTEL_AVX2 */
+    /*_mm_storeu_si128((__m128i*)tag, T);*/
+    XMEMCPY(tag, &T, tbytes);
+    }
 
 #ifdef HAVE_AES_DECRYPT
-/* Figure 10. AES-GCM – Decrypt With Single Block Ghash at a Time */
-
-static int AES_GCM_decrypt(const unsigned char *in, unsigned char *out,
-                           const unsigned char* addt, const unsigned char* ivec,
+
+static void AES_GCM_decrypt(const unsigned char *in,
+                           unsigned char *out,
+                           const unsigned char* addt,
+                           const unsigned char* ivec,
                            const unsigned char *tag, int nbytes, int abytes,
-                           int ibytes, const unsigned char* key, int nr)
+                           int ibytes, word32 tbytes, const unsigned char* key,
+                           int nr, int* res)
 {
     int i, j ,k;
@@ -5035,122 +7320,10 @@
     __m128i r0, r1;
     __m128i tmp3, tmp4, tmp5, tmp6, tmp7, tmp8;
-#endif
-
-    if (ibytes == 12) {
-        Y = _mm_setzero_si128();
-        for (j=0; j < 12; j++)
-            ((unsigned char*)&Y)[j] = ivec[j];
-        Y = _mm_insert_epi32(Y, 0x1000000, 3);
-            /* (Compute E[ZERO, KS] and E[Y0, KS] together */
-        tmp1 = _mm_xor_si128(X, KEY[0]);
-        tmp2 = _mm_xor_si128(Y, KEY[0]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[1]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[1]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[2]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[2]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[3]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[3]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[4]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[4]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[5]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[5]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[6]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[6]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[7]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[7]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[8]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[8]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[9]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[9]);
-        lastKey = KEY[10];
-        if (nr > 10) {
-            tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-            tmp2 = _mm_aesenc_si128(tmp2, lastKey);
-            tmp1 = _mm_aesenc_si128(tmp1, KEY[11]);
-            tmp2 = _mm_aesenc_si128(tmp2, KEY[11]);
-            lastKey = KEY[12];
-            if (nr > 12) {
-                tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-                tmp2 = _mm_aesenc_si128(tmp2, lastKey);
-                tmp1 = _mm_aesenc_si128(tmp1, KEY[13]);
-                tmp2 = _mm_aesenc_si128(tmp2, KEY[13]);
-                lastKey = KEY[14];
-            }
-        }
-        H = _mm_aesenclast_si128(tmp1, lastKey);
-        T = _mm_aesenclast_si128(tmp2, lastKey);
-        H = _mm_shuffle_epi8(H, BSWAP_MASK);
-    }
-    else {
-        if (ibytes % 16) {
-            i = ibytes / 16;
-            for (j=0; j < ibytes%16; j++)
-                ((unsigned char*)&last_block)[j] = ivec[i*16+j];
-        }
-        tmp1 = _mm_xor_si128(X, KEY[0]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[1]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[2]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[3]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[4]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[5]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[6]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[7]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[8]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[9]);
-        lastKey = KEY[10];
-        if (nr > 10) {
-            tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-            tmp1 = _mm_aesenc_si128(tmp1, KEY[11]);
-            lastKey = KEY[12];
-            if (nr > 12) {
-                tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-                tmp1 = _mm_aesenc_si128(tmp1, KEY[13]);
-                lastKey = KEY[14];
-            }
-        }
-        H = _mm_aesenclast_si128(tmp1, lastKey);
-        H = _mm_shuffle_epi8(H, BSWAP_MASK);
-
-        Y = _mm_setzero_si128();
-        for (i=0; i < ibytes/16; i++) {
-            tmp1 = _mm_loadu_si128(&((__m128i*)ivec)[i]);
-            tmp1 = _mm_shuffle_epi8(tmp1, BSWAP_MASK);
-            Y = _mm_xor_si128(Y, tmp1);
-            Y = gfmul_sw(Y, H);
-        }
-        if (ibytes % 16) {
-            tmp1 = last_block;
-            tmp1 = _mm_shuffle_epi8(tmp1, BSWAP_MASK);
-            Y = _mm_xor_si128(Y, tmp1);
-            Y = gfmul_sw(Y, H);
-        }
-        tmp1 = _mm_insert_epi64(tmp1, ibytes*8, 0);
-        tmp1 = _mm_insert_epi64(tmp1, 0, 1);
-        Y = _mm_xor_si128(Y, tmp1);
-        Y = gfmul_sw(Y, H);
-        Y = _mm_shuffle_epi8(Y, BSWAP_MASK); /* Compute E(K, Y0) */
-        tmp1 = _mm_xor_si128(Y, KEY[0]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[1]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[2]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[3]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[4]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[5]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[6]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[7]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[8]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[9]);
-        lastKey = KEY[10];
-        if (nr > 10) {
-            tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-            tmp1 = _mm_aesenc_si128(tmp1, KEY[11]);
-            lastKey = KEY[12];
-            if (nr > 12) {
-                tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-                tmp1 = _mm_aesenc_si128(tmp1, KEY[13]);
-                lastKey = KEY[14];
-            }
-        }
-        T = _mm_aesenclast_si128(tmp1, lastKey);
-    }
+#endif /* AES_GCM_AESNI_NO_UNROLL */
+
+    if (ibytes == 12)
+        aes_gcm_calc_iv_12(KEY, ivec, nr, H, Y, T);
+    else
+        aes_gcm_calc_iv(KEY, ivec, ibytes, nr, H, Y, T);
 
     for (i=0; i<abytes/16; i++) {
@@ -5359,33 +7532,12 @@
                     tmp8 = _mm_aesenc_si128(tmp8, KEY[13]);
                     lastKey = KEY[14];
-                }
-            }
-            tmp1 =_mm_aesenclast_si128(tmp1, lastKey);
-            tmp2 =_mm_aesenclast_si128(tmp2, lastKey);
-            tmp3 =_mm_aesenclast_si128(tmp3, lastKey);
-            tmp4 =_mm_aesenclast_si128(tmp4, lastKey);
-            tmp5 =_mm_aesenclast_si128(tmp5, lastKey);
-            tmp6 =_mm_aesenclast_si128(tmp6, lastKey);
-            tmp7 =_mm_aesenclast_si128(tmp7, lastKey);
-            tmp8 =_mm_aesenclast_si128(tmp8, lastKey);
-            tmp1 = _mm_xor_si128(tmp1, _mm_loadu_si128(&((__m128i*)in)[i*8+0]));
-            tmp2 = _mm_xor_si128(tmp2, _mm_loadu_si128(&((__m128i*)in)[i*8+1]));
-            tmp3 = _mm_xor_si128(tmp3, _mm_loadu_si128(&((__m128i*)in)[i*8+2]));
-            tmp4 = _mm_xor_si128(tmp4, _mm_loadu_si128(&((__m128i*)in)[i*8+3]));
-            tmp5 = _mm_xor_si128(tmp5, _mm_loadu_si128(&((__m128i*)in)[i*8+4]));
-            tmp6 = _mm_xor_si128(tmp6, _mm_loadu_si128(&((__m128i*)in)[i*8+5]));
-            tmp7 = _mm_xor_si128(tmp7, _mm_loadu_si128(&((__m128i*)in)[i*8+6]));
-            tmp8 = _mm_xor_si128(tmp8, _mm_loadu_si128(&((__m128i*)in)[i*8+7]));
-            _mm_storeu_si128(&((__m128i*)out)[i*8+0], tmp1);
-            _mm_storeu_si128(&((__m128i*)out)[i*8+1], tmp2);
-            _mm_storeu_si128(&((__m128i*)out)[i*8+2], tmp3);
-            _mm_storeu_si128(&((__m128i*)out)[i*8+3], tmp4);
-            _mm_storeu_si128(&((__m128i*)out)[i*8+4], tmp5);
-            _mm_storeu_si128(&((__m128i*)out)[i*8+5], tmp6);
-            _mm_storeu_si128(&((__m128i*)out)[i*8+6], tmp7);
-            _mm_storeu_si128(&((__m128i*)out)[i*8+7], tmp8);
-        }
-    }
-#endif
+        }
+    }
+            AES_ENC_LAST_8();
+        }
+    }
+
+#endif /* AES_GCM_AESNI_NO_UNROLL */
+
     for (k = i*8; k < nbytes/16; k++) {
         tmp1 = _mm_shuffle_epi8(ctr1, BSWAP_EPI64);
@@ -5469,638 +7621,14 @@
     T = _mm_xor_si128(X, T);
 
-    if (0xffff !=
-           _mm_movemask_epi8(_mm_cmpeq_epi8(T, _mm_loadu_si128((__m128i*)tag))))
-        return 0; /* in case the authentication failed */
-
-    return 1; /* when successful returns 1 */
+/*    if (0xffff !=
+           _mm_movemask_epi8(_mm_cmpeq_epi8(T, _mm_loadu_si128((__m128i*)tag)))) */
+    if (XMEMCMP(tag, &T, tbytes) != 0)
+        *res = 0; /* in case the authentication failed */
+    else
+        *res = 1; /* when successful returns 1 */
 }
 
-#ifdef HAVE_INTEL_AVX2
-static int AES_GCM_decrypt_avx2(const unsigned char *in, unsigned char *out,
-                                const unsigned char* addt,
-                                const unsigned char* ivec,
-                                const unsigned char *tag, int nbytes,
-                                int abytes, int ibytes,
-                                const unsigned char* key, int nr)
-{
-    int i, j ,k;
-    __m128i H, Y, T;
-    __m128i *KEY = (__m128i*)key, lastKey;
-    __m128i ctr1;
-    __m128i last_block = _mm_setzero_si128();
-    __m128i X = _mm_setzero_si128();
-    __m128i tmp1, tmp2;
-#if !defined(AES_GCM_AESNI_NO_UNROLL) && !defined(AES_GCM_AVX2_NO_UNROLL)
-    __m128i HT[8];
-    __m128i pctr1[1];
-    register __m128i XV asm("xmm2");
-#else
-    __m128i XV;
-#endif
-
-    if (ibytes == 12) {
-        Y = _mm_setzero_si128();
-        for (j=0; j < 12; j++)
-            ((unsigned char*)&Y)[j] = ivec[j];
-        Y = _mm_insert_epi32(Y, 0x1000000, 3);
-            /* (Compute E[ZERO, KS] and E[Y0, KS] together */
-        tmp1 = _mm_xor_si128(X, KEY[0]);
-        tmp2 = _mm_xor_si128(Y, KEY[0]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[1]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[1]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[2]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[2]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[3]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[3]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[4]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[4]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[5]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[5]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[6]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[6]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[7]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[7]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[8]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[8]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[9]);
-        tmp2 = _mm_aesenc_si128(tmp2, KEY[9]);
-        lastKey = KEY[10];
-        if (nr > 10) {
-            tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-            tmp2 = _mm_aesenc_si128(tmp2, lastKey);
-            tmp1 = _mm_aesenc_si128(tmp1, KEY[11]);
-            tmp2 = _mm_aesenc_si128(tmp2, KEY[11]);
-            lastKey = KEY[12];
-            if (nr > 12) {
-                tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-                tmp2 = _mm_aesenc_si128(tmp2, lastKey);
-                tmp1 = _mm_aesenc_si128(tmp1, KEY[13]);
-                tmp2 = _mm_aesenc_si128(tmp2, KEY[13]);
-                lastKey = KEY[14];
-            }
-        }
-        H = _mm_aesenclast_si128(tmp1, lastKey);
-        T = _mm_aesenclast_si128(tmp2, lastKey);
-        H = _mm_shuffle_epi8(H, BSWAP_MASK);
-    }
-    else {
-        if (ibytes % 16) {
-            i = ibytes / 16;
-            for (j=0; j < ibytes%16; j++)
-                ((unsigned char*)&last_block)[j] = ivec[i*16+j];
-        }
-        tmp1 = _mm_xor_si128(X, KEY[0]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[1]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[2]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[3]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[4]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[5]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[6]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[7]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[8]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[9]);
-        lastKey = KEY[10];
-        if (nr > 10) {
-            tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-            tmp1 = _mm_aesenc_si128(tmp1, KEY[11]);
-            lastKey = KEY[12];
-            if (nr > 12) {
-                tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-                tmp1 = _mm_aesenc_si128(tmp1, KEY[13]);
-                lastKey = KEY[14];
-            }
-        }
-        H = _mm_aesenclast_si128(tmp1, lastKey);
-        H = _mm_shuffle_epi8(H, BSWAP_MASK);
-
-        Y = _mm_setzero_si128();
-        for (i=0; i < ibytes/16; i++) {
-            tmp1 = _mm_loadu_si128(&((__m128i*)ivec)[i]);
-            tmp1 = _mm_shuffle_epi8(tmp1, BSWAP_MASK);
-            Y = _mm_xor_si128(Y, tmp1);
-            Y = gfmul_sw(Y, H);
-        }
-        if (ibytes % 16) {
-            tmp1 = last_block;
-            tmp1 = _mm_shuffle_epi8(tmp1, BSWAP_MASK);
-            Y = _mm_xor_si128(Y, tmp1);
-            Y = gfmul_sw(Y, H);
-        }
-        tmp1 = _mm_insert_epi64(tmp1, ibytes*8, 0);
-        tmp1 = _mm_insert_epi64(tmp1, 0, 1);
-        Y = _mm_xor_si128(Y, tmp1);
-        Y = gfmul_sw(Y, H);
-        Y = _mm_shuffle_epi8(Y, BSWAP_MASK); /* Compute E(K, Y0) */
-        tmp1 = _mm_xor_si128(Y, KEY[0]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[1]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[2]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[3]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[4]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[5]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[6]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[7]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[8]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[9]);
-        lastKey = KEY[10];
-        if (nr > 10) {
-            tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-            tmp1 = _mm_aesenc_si128(tmp1, KEY[11]);
-            lastKey = KEY[12];
-            if (nr > 12) {
-                tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-                tmp1 = _mm_aesenc_si128(tmp1, KEY[13]);
-                lastKey = KEY[14];
-            }
-        }
-        T = _mm_aesenclast_si128(tmp1, lastKey);
-    }
-
-    for (i=0; i<abytes/16; i++) {
-        tmp1 = _mm_loadu_si128(&((__m128i*)addt)[i]);
-        tmp1 = _mm_shuffle_epi8(tmp1, BSWAP_MASK);
-        X = _mm_xor_si128(X, tmp1);
-        X = gfmul_sw(X, H);
-    }
-    if (abytes%16) {
-        last_block = _mm_setzero_si128();
-        for (j=0; j<abytes%16; j++)
-            ((unsigned char*)&last_block)[j] = addt[i*16+j];
-        tmp1 = last_block;
-        tmp1 = _mm_shuffle_epi8(tmp1, BSWAP_MASK);
-        X = _mm_xor_si128(X, tmp1);
-        X = gfmul_sw(X, H);
-    }
-
-    tmp1 = _mm_shuffle_epi8(Y, BSWAP_EPI64);
-    ctr1 = _mm_add_epi32(tmp1, ONE);
-    H = gfmul_shl1(H);
-    i = 0;
-
-#if !defined(AES_GCM_AESNI_NO_UNROLL) && !defined(AES_GCM_AVX2_NO_UNROLL)
-
-    if (0 < nbytes/16/8) {
-        HT[0] = H;
-        HT[1] = gfmul_shifted(H, H);
-        HT[2] = gfmul_shifted(H, HT[1]);
-        HT[3] = gfmul_shifted(HT[1], HT[1]);
-        HT[4] = gfmul_shifted(HT[1], HT[2]);
-        HT[5] = gfmul_shifted(HT[2], HT[2]);
-        HT[6] = gfmul_shifted(HT[2], HT[3]);
-        HT[7] = gfmul_shifted(HT[3], HT[3]);
-
-        pctr1[0] = ctr1;
-        XV = X;
-        for (; i < nbytes/16/8; i++) {
-            __asm__ __volatile__ (
-                "vmovaps	(%[pctr1]), %%xmm0\n\t"
-                "vmovaps	%[BSWAP_EPI64], %%xmm1\n\t"
-                "vpshufb	%%xmm1, %%xmm0, %%xmm4\n\t"
-                "vpaddd		%[ONE], %%xmm0, %%xmm5\n\t"
-                "vpshufb	%%xmm1, %%xmm5, %%xmm5\n\t"
-                "vpaddd		%[TWO], %%xmm0, %%xmm6\n\t"
-                "vpshufb	%%xmm1, %%xmm6, %%xmm6\n\t"
-                "vpaddd		%[THREE], %%xmm0, %%xmm7\n\t"
-                "vpshufb	%%xmm1, %%xmm7, %%xmm7\n\t"
-                "vpaddd		%[FOUR], %%xmm0, %%xmm8\n\t"
-                "vpshufb	%%xmm1, %%xmm8, %%xmm8\n\t"
-                "vpaddd		%[FIVE], %%xmm0, %%xmm9\n\t"
-                "vpshufb	%%xmm1, %%xmm9, %%xmm9\n\t"
-                "vpaddd		%[SIX], %%xmm0, %%xmm10\n\t"
-                "vpshufb	%%xmm1, %%xmm10, %%xmm10\n\t"
-                "vpaddd		%[SEVEN], %%xmm0, %%xmm11\n\t"
-                "vpshufb	%%xmm1, %%xmm11, %%xmm11\n\t"
-                "vpaddd		%[EIGHT], %%xmm0, %%xmm0\n\t"
-
-                "vmovaps	(%[KEY]), %%xmm1\n\t"
-                "vmovaps	%%xmm0, (%[pctr1])\n\t"
-                "vpxor		%%xmm1, %%xmm4, %%xmm4\n\t"
-                "vpxor		%%xmm1, %%xmm5, %%xmm5\n\t"
-                "vpxor		%%xmm1, %%xmm6, %%xmm6\n\t"
-                "vpxor		%%xmm1, %%xmm7, %%xmm7\n\t"
-                "vpxor		%%xmm1, %%xmm8, %%xmm8\n\t"
-                "vpxor		%%xmm1, %%xmm9, %%xmm9\n\t"
-                "vpxor		%%xmm1, %%xmm10, %%xmm10\n\t"
-                "vpxor		%%xmm1, %%xmm11, %%xmm11\n\t"
-
-                "vmovaps	16(%[KEY]), %%xmm12\n\t"
-                "vmovdqu	(%[in]), %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm4, %%xmm4\n\t"
-                "vmovaps	112(%[HT]), %%xmm0\n\t"
-                "vpshufb	%[BSWAP_MASK], %%xmm1, %%xmm1\n\t"
-                "vpxor		%[XV], %%xmm1, %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm5, %%xmm5\n\t"
-                "vpclmulqdq	$16, %%xmm1, %%xmm0, %%xmm13\n\t"
-                "vaesenc	%%xmm12, %%xmm6, %%xmm6\n\t"
-                "vpclmulqdq	$1, %%xmm1, %%xmm0, %%xmm14\n\t"
-                "vaesenc	%%xmm12, %%xmm7, %%xmm7\n\t"
-                "vpclmulqdq	$0, %%xmm1, %%xmm0, %%xmm15\n\t"
-                "vaesenc	%%xmm12, %%xmm8, %%xmm8\n\t"
-                "vpclmulqdq	$17, %%xmm1, %%xmm0, %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm9, %%xmm9\n\t"
-                "vpxor		%%xmm14, %%xmm13, %%xmm13\n\t"
-                "vpslldq	$8, %%xmm13, %%xmm2\n\t"
-                "vpsrldq	$8, %%xmm13, %%xmm13\n\t"
-                "vaesenc	%%xmm12, %%xmm10, %%xmm10\n\t"
-                "vpxor		%%xmm15, %%xmm2, %%xmm2\n\t"
-                "vpxor		%%xmm13, %%xmm1, %%xmm3\n\t"
-                "vaesenc	%%xmm12, %%xmm11, %%xmm11\n\t"
-
-                "vmovaps	32(%[KEY]), %%xmm12\n\t"
-                "vmovdqu	16(%[in]), %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm4, %%xmm4\n\t"
-                "vmovaps	96(%[HT]), %%xmm0\n\t"
-                "vpshufb	%[BSWAP_MASK], %%xmm1, %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm5, %%xmm5\n\t"
-                "vpclmulqdq	$16, %%xmm1, %%xmm0, %%xmm13\n\t"
-                "vaesenc	%%xmm12, %%xmm6, %%xmm6\n\t"
-                "vpclmulqdq	$1, %%xmm1, %%xmm0, %%xmm14\n\t"
-                "vaesenc	%%xmm12, %%xmm7, %%xmm7\n\t"
-                "vpclmulqdq	$0, %%xmm1, %%xmm0, %%xmm15\n\t"
-                "vaesenc	%%xmm12, %%xmm8, %%xmm8\n\t"
-                "vpclmulqdq	$17, %%xmm1, %%xmm0, %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm9, %%xmm9\n\t"
-                "vpxor		%%xmm14, %%xmm13, %%xmm13\n\t"
-                "vpslldq	$8, %%xmm13, %%xmm14\n\t"
-                "vpsrldq	$8, %%xmm13, %%xmm13\n\t"
-                "vaesenc	%%xmm12, %%xmm10, %%xmm10\n\t"
-                "vpxor		%%xmm15, %%xmm2, %%xmm2\n\t"
-                "vpxor		%%xmm1, %%xmm3, %%xmm3\n\t"
-                "vpxor		%%xmm14, %%xmm2, %%xmm2\n\t"
-                "vpxor		%%xmm13, %%xmm3, %%xmm3\n\t"
-                "vaesenc	%%xmm12, %%xmm11, %%xmm11\n\t"
-
-                "vmovaps	48(%[KEY]), %%xmm12\n\t"
-                "vmovdqu	32(%[in]), %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm4, %%xmm4\n\t"
-                "vmovaps	80(%[HT]), %%xmm0\n\t"
-                "vpshufb	%[BSWAP_MASK], %%xmm1, %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm5, %%xmm5\n\t"
-                "vpclmulqdq	$16, %%xmm1, %%xmm0, %%xmm13\n\t"
-                "vaesenc	%%xmm12, %%xmm6, %%xmm6\n\t"
-                "vpclmulqdq	$1, %%xmm1, %%xmm0, %%xmm14\n\t"
-                "vaesenc	%%xmm12, %%xmm7, %%xmm7\n\t"
-                "vpclmulqdq	$0, %%xmm1, %%xmm0, %%xmm15\n\t"
-                "vaesenc	%%xmm12, %%xmm8, %%xmm8\n\t"
-                "vpclmulqdq	$17, %%xmm1, %%xmm0, %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm9, %%xmm9\n\t"
-                "vpxor		%%xmm14, %%xmm13, %%xmm13\n\t"
-                "vpslldq	$8, %%xmm13, %%xmm14\n\t"
-                "vpsrldq	$8, %%xmm13, %%xmm13\n\t"
-                "vaesenc	%%xmm12, %%xmm10, %%xmm10\n\t"
-                "vpxor		%%xmm15, %%xmm2, %%xmm2\n\t"
-                "vpxor		%%xmm1, %%xmm3, %%xmm3\n\t"
-                "vpxor		%%xmm14, %%xmm2, %%xmm2\n\t"
-                "vpxor		%%xmm13, %%xmm3, %%xmm3\n\t"
-                "vaesenc	%%xmm12, %%xmm11, %%xmm11\n\t"
-
-                "vmovaps	64(%[KEY]), %%xmm12\n\t"
-                "vmovdqu	48(%[in]), %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm4, %%xmm4\n\t"
-                "vmovaps	64(%[HT]), %%xmm0\n\t"
-                "vpshufb	%[BSWAP_MASK], %%xmm1, %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm5, %%xmm5\n\t"
-                "vpclmulqdq	$16, %%xmm1, %%xmm0, %%xmm13\n\t"
-                "vaesenc	%%xmm12, %%xmm6, %%xmm6\n\t"
-                "vpclmulqdq	$1, %%xmm1, %%xmm0, %%xmm14\n\t"
-                "vaesenc	%%xmm12, %%xmm7, %%xmm7\n\t"
-                "vpclmulqdq	$0, %%xmm1, %%xmm0, %%xmm15\n\t"
-                "vaesenc	%%xmm12, %%xmm8, %%xmm8\n\t"
-                "vpclmulqdq	$17, %%xmm1, %%xmm0, %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm9, %%xmm9\n\t"
-                "vpxor		%%xmm14, %%xmm13, %%xmm13\n\t"
-                "vpslldq	$8, %%xmm13, %%xmm14\n\t"
-                "vpsrldq	$8, %%xmm13, %%xmm13\n\t"
-                "vaesenc	%%xmm12, %%xmm10, %%xmm10\n\t"
-                "vpxor		%%xmm15, %%xmm2, %%xmm2\n\t"
-                "vpxor		%%xmm1, %%xmm3, %%xmm3\n\t"
-                "vpxor		%%xmm14, %%xmm2, %%xmm2\n\t"
-                "vpxor		%%xmm13, %%xmm3, %%xmm3\n\t"
-                "vaesenc	%%xmm12, %%xmm11, %%xmm11\n\t"
-
-                "vmovaps	80(%[KEY]), %%xmm12\n\t"
-                "vmovdqu	64(%[in]), %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm4, %%xmm4\n\t"
-                "vmovaps	48(%[HT]), %%xmm0\n\t"
-                "vpshufb	%[BSWAP_MASK], %%xmm1, %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm5, %%xmm5\n\t"
-                "vpclmulqdq	$16, %%xmm1, %%xmm0, %%xmm13\n\t"
-                "vaesenc	%%xmm12, %%xmm6, %%xmm6\n\t"
-                "vpclmulqdq	$1, %%xmm1, %%xmm0, %%xmm14\n\t"
-                "vaesenc	%%xmm12, %%xmm7, %%xmm7\n\t"
-                "vpclmulqdq	$0, %%xmm1, %%xmm0, %%xmm15\n\t"
-                "vaesenc	%%xmm12, %%xmm8, %%xmm8\n\t"
-                "vpclmulqdq	$17, %%xmm1, %%xmm0, %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm9, %%xmm9\n\t"
-                "vpxor		%%xmm14, %%xmm13, %%xmm13\n\t"
-                "vpslldq	$8, %%xmm13, %%xmm14\n\t"
-                "vpsrldq	$8, %%xmm13, %%xmm13\n\t"
-                "vaesenc	%%xmm12, %%xmm10, %%xmm10\n\t"
-                "vpxor		%%xmm15, %%xmm2, %%xmm2\n\t"
-                "vpxor		%%xmm1, %%xmm3, %%xmm3\n\t"
-                "vpxor		%%xmm14, %%xmm2, %%xmm2\n\t"
-                "vpxor		%%xmm13, %%xmm3, %%xmm3\n\t"
-                "vaesenc	%%xmm12, %%xmm11, %%xmm11\n\t"
-
-                "vmovaps	96(%[KEY]), %%xmm12\n\t"
-                "vmovdqu	80(%[in]), %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm4, %%xmm4\n\t"
-                "vmovaps	32(%[HT]), %%xmm0\n\t"
-                "vpshufb	%[BSWAP_MASK], %%xmm1, %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm5, %%xmm5\n\t"
-                "vpclmulqdq	$16, %%xmm1, %%xmm0, %%xmm13\n\t"
-                "vaesenc	%%xmm12, %%xmm6, %%xmm6\n\t"
-                "vpclmulqdq	$1, %%xmm1, %%xmm0, %%xmm14\n\t"
-                "vaesenc	%%xmm12, %%xmm7, %%xmm7\n\t"
-                "vpclmulqdq	$0, %%xmm1, %%xmm0, %%xmm15\n\t"
-                "vaesenc	%%xmm12, %%xmm8, %%xmm8\n\t"
-                "vpclmulqdq	$17, %%xmm1, %%xmm0, %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm9, %%xmm9\n\t"
-                "vpxor		%%xmm14, %%xmm13, %%xmm13\n\t"
-                "vpslldq	$8, %%xmm13, %%xmm14\n\t"
-                "vpsrldq	$8, %%xmm13, %%xmm13\n\t"
-                "vaesenc	%%xmm12, %%xmm10, %%xmm10\n\t"
-                "vpxor		%%xmm15, %%xmm2, %%xmm2\n\t"
-                "vpxor		%%xmm1, %%xmm3, %%xmm3\n\t"
-                "vpxor		%%xmm14, %%xmm2, %%xmm2\n\t"
-                "vpxor		%%xmm13, %%xmm3, %%xmm3\n\t"
-                "vaesenc	%%xmm12, %%xmm11, %%xmm11\n\t"
-
-                "vmovaps	112(%[KEY]), %%xmm12\n\t"
-                "vmovdqu	96(%[in]), %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm4, %%xmm4\n\t"
-                "vmovaps	16(%[HT]), %%xmm0\n\t"
-                "vpshufb	%[BSWAP_MASK], %%xmm1, %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm5, %%xmm5\n\t"
-                "vpclmulqdq	$16, %%xmm1, %%xmm0, %%xmm13\n\t"
-                "vaesenc	%%xmm12, %%xmm6, %%xmm6\n\t"
-                "vpclmulqdq	$1, %%xmm1, %%xmm0, %%xmm14\n\t"
-                "vaesenc	%%xmm12, %%xmm7, %%xmm7\n\t"
-                "vpclmulqdq	$0, %%xmm1, %%xmm0, %%xmm15\n\t"
-                "vaesenc	%%xmm12, %%xmm8, %%xmm8\n\t"
-                "vpclmulqdq	$17, %%xmm1, %%xmm0, %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm9, %%xmm9\n\t"
-                "vpxor		%%xmm14, %%xmm13, %%xmm13\n\t"
-                "vpslldq	$8, %%xmm13, %%xmm14\n\t"
-                "vpsrldq	$8, %%xmm13, %%xmm13\n\t"
-                "vaesenc	%%xmm12, %%xmm10, %%xmm10\n\t"
-                "vpxor		%%xmm15, %%xmm2, %%xmm2\n\t"
-                "vpxor		%%xmm1, %%xmm3, %%xmm3\n\t"
-                "vpxor		%%xmm14, %%xmm2, %%xmm2\n\t"
-                "vpxor		%%xmm13, %%xmm3, %%xmm3\n\t"
-                "vaesenc	%%xmm12, %%xmm11, %%xmm11\n\t"
-
-                "vmovaps	128(%[KEY]), %%xmm12\n\t"
-                "vmovdqu	112(%[in]), %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm4, %%xmm4\n\t"
-                "vmovaps	(%[HT]), %%xmm0\n\t"
-                "vpshufb	%[BSWAP_MASK], %%xmm1, %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm5, %%xmm5\n\t"
-                "vpclmulqdq	$16, %%xmm1, %%xmm0, %%xmm13\n\t"
-                "vaesenc	%%xmm12, %%xmm6, %%xmm6\n\t"
-                "vpclmulqdq	$1, %%xmm1, %%xmm0, %%xmm14\n\t"
-                "vaesenc	%%xmm12, %%xmm7, %%xmm7\n\t"
-                "vpclmulqdq	$0, %%xmm1, %%xmm0, %%xmm15\n\t"
-                "vaesenc	%%xmm12, %%xmm8, %%xmm8\n\t"
-                "vpclmulqdq	$17, %%xmm1, %%xmm0, %%xmm1\n\t"
-                "vaesenc	%%xmm12, %%xmm9, %%xmm9\n\t"
-                "vpxor		%%xmm14, %%xmm13, %%xmm13\n\t"
-                "vpslldq	$8, %%xmm13, %%xmm14\n\t"
-                "vpsrldq	$8, %%xmm13, %%xmm13\n\t"
-                "vaesenc	%%xmm12, %%xmm10, %%xmm10\n\t"
-                "vpxor		%%xmm15, %%xmm2, %%xmm2\n\t"
-                "vpxor		%%xmm1, %%xmm3, %%xmm3\n\t"
-                "vpxor		%%xmm14, %%xmm2, %%xmm2\n\t"
-                "vpxor		%%xmm13, %%xmm3, %%xmm3\n\t"
-                "vaesenc	%%xmm12, %%xmm11, %%xmm11\n\t"
-
-                "vmovaps	144(%[KEY]), %%xmm12\n\t"
-                "vaesenc	%%xmm12, %%xmm4, %%xmm4\n\t"
-                "vmovdqa	%[MOD2_128], %%xmm0\n\t"
-                "vaesenc	%%xmm12, %%xmm5, %%xmm5\n\t"
-                "vpclmulqdq	$16, %%xmm0, %%xmm2, %%xmm14\n\t"
-                "vaesenc	%%xmm12, %%xmm6, %%xmm6\n\t"
-                "vpshufd	$78, %%xmm2, %%xmm13\n\t"
-                "vpxor		%%xmm14, %%xmm13, %%xmm13\n\t"
-                "vaesenc	%%xmm12, %%xmm7, %%xmm7\n\t"
-                "vpclmulqdq	$16, %%xmm0, %%xmm13, %%xmm14\n\t"
-                "vaesenc	%%xmm12, %%xmm8, %%xmm8\n\t"
-                "vpshufd	$78, %%xmm13, %%xmm13\n\t"
-                "vpxor		%%xmm14, %%xmm13, %%xmm13\n\t"
-                "vpxor		%%xmm3, %%xmm13, %%xmm13\n\t"
-                "vaesenc	%%xmm12, %%xmm9, %%xmm9\n\t"
-                "vmovdqa	%%xmm13, %%xmm2\n\t"
-                "vaesenc	%%xmm12, %%xmm10, %%xmm10\n\t"
-                "vaesenc	%%xmm12, %%xmm11, %%xmm11\n\t"
-                "cmpl		$11, %[nr]\n\t"
-                "vmovaps	160(%[KEY]), %%xmm12\n\t"
-                "jl             %=f\n\t"
-
-                "vaesenc	%%xmm12, %%xmm4, %%xmm4\n\t"
-                "vaesenc	%%xmm12, %%xmm5, %%xmm5\n\t"
-                "vaesenc	%%xmm12, %%xmm6, %%xmm6\n\t"
-                "vaesenc	%%xmm12, %%xmm7, %%xmm7\n\t"
-                "vaesenc	%%xmm12, %%xmm8, %%xmm8\n\t"
-                "vaesenc	%%xmm12, %%xmm9, %%xmm9\n\t"
-                "vaesenc	%%xmm12, %%xmm10, %%xmm10\n\t"
-                "vaesenc	%%xmm12, %%xmm11, %%xmm11\n\t"
-                "vmovaps	176(%[KEY]), %%xmm12\n\t"
-                "vaesenc	%%xmm12, %%xmm4, %%xmm4\n\t"
-                "vaesenc	%%xmm12, %%xmm5, %%xmm5\n\t"
-                "vaesenc	%%xmm12, %%xmm6, %%xmm6\n\t"
-                "vaesenc	%%xmm12, %%xmm7, %%xmm7\n\t"
-                "vaesenc	%%xmm12, %%xmm8, %%xmm8\n\t"
-                "vaesenc	%%xmm12, %%xmm9, %%xmm9\n\t"
-                "vaesenc	%%xmm12, %%xmm10, %%xmm10\n\t"
-                "vaesenc	%%xmm12, %%xmm11, %%xmm11\n\t"
-                "cmpl		$13, %[nr]\n\t"
-                "vmovaps	192(%[KEY]), %%xmm12\n\t"
-                "jl             %=f\n\t"
-
-                "vaesenc	%%xmm12, %%xmm4, %%xmm4\n\t"
-                "vaesenc	%%xmm12, %%xmm5, %%xmm5\n\t"
-                "vaesenc	%%xmm12, %%xmm6, %%xmm6\n\t"
-                "vaesenc	%%xmm12, %%xmm7, %%xmm7\n\t"
-                "vaesenc	%%xmm12, %%xmm8, %%xmm8\n\t"
-                "vaesenc	%%xmm12, %%xmm9, %%xmm9\n\t"
-                "vaesenc	%%xmm12, %%xmm10, %%xmm10\n\t"
-                "vaesenc	%%xmm12, %%xmm11, %%xmm11\n\t"
-                "vmovaps	208(%[KEY]), %%xmm12\n\t"
-                "vaesenc	%%xmm12, %%xmm4, %%xmm4\n\t"
-                "vaesenc	%%xmm12, %%xmm5, %%xmm5\n\t"
-                "vaesenc	%%xmm12, %%xmm6, %%xmm6\n\t"
-                "vaesenc	%%xmm12, %%xmm7, %%xmm7\n\t"
-                "vaesenc	%%xmm12, %%xmm8, %%xmm8\n\t"
-                "vaesenc	%%xmm12, %%xmm9, %%xmm9\n\t"
-                "vaesenc	%%xmm12, %%xmm10, %%xmm10\n\t"
-                "vaesenc	%%xmm12, %%xmm11, %%xmm11\n\t"
-                "vmovaps	224(%[KEY]), %%xmm12\n\t"
-
-                "%=:\n\t"
-                "vaesenclast	%%xmm12, %%xmm4, %%xmm4\n\t"
-                "vaesenclast	%%xmm12, %%xmm5, %%xmm5\n\t"
-                "vpxor		(%[in]), %%xmm4, %%xmm4\n\t"
-                "vpxor		16(%[in]), %%xmm5, %%xmm5\n\t"
-                "vmovdqu	%%xmm4, (%[out])\n\t"
-                "vmovdqu	%%xmm5, 16(%[out])\n\t"
-                "vaesenclast	%%xmm12, %%xmm6, %%xmm6\n\t"
-                "vaesenclast	%%xmm12, %%xmm7, %%xmm7\n\t"
-                "vpxor		32(%[in]), %%xmm6, %%xmm6\n\t"
-                "vpxor		48(%[in]), %%xmm7, %%xmm7\n\t"
-                "vmovdqu	%%xmm6, 32(%[out])\n\t"
-                "vmovdqu	%%xmm7, 48(%[out])\n\t"
-                "vaesenclast	%%xmm12, %%xmm8, %%xmm8\n\t"
-                "vaesenclast	%%xmm12, %%xmm9, %%xmm9\n\t"
-                "vpxor		64(%[in]), %%xmm8, %%xmm8\n\t"
-                "vpxor		80(%[in]), %%xmm9, %%xmm9\n\t"
-                "vmovdqu	%%xmm8, 64(%[out])\n\t"
-                "vmovdqu	%%xmm9, 80(%[out])\n\t"
-                "vaesenclast	%%xmm12, %%xmm10, %%xmm10\n\t"
-                "vaesenclast	%%xmm12, %%xmm11, %%xmm11\n\t"
-                "vpxor		96(%[in]), %%xmm10, %%xmm10\n\t"
-                "vpxor		112(%[in]), %%xmm11, %%xmm11\n\t"
-                "vmovdqu	%%xmm10, 96(%[out])\n\t"
-                "vmovdqu	%%xmm11, 112(%[out])\n\t"
-
-            : [XV] "+xr" (XV)
-            : [KEY] "r" (KEY), [HT] "r" (HT), [pctr1] "r" (pctr1),
-              [in] "r" (&in[i*16*8]), [out] "r" (&out[i*16*8]), [nr] "r" (nr),
-              [BSWAP_MASK] "m" (BSWAP_MASK),
-              [BSWAP_EPI64] "m" (BSWAP_EPI64),
-              [ONE] "m" (ONE), [TWO] "m" (TWO),
-              [THREE] "m" (THREE), [FOUR] "m" (FOUR),
-              [FIVE] "m" (FIVE), [SIX] "m" (SIX),
-              [SEVEN] "m" (SEVEN), [EIGHT] "m" (EIGHT),
-              [MOD2_128] "m" (MOD2_128)
-            : "xmm15", "xmm14", "xmm13", "xmm12",
-              "xmm11", "xmm10", "xmm9", "xmm8",
-              "xmm7", "xmm6", "xmm5", "xmm4",
-              "xmm0", "xmm1", "xmm3", "memory"
-            );
-        }
-        X = XV;
-        ctr1 = pctr1[0];
-    }
-#endif
-    for (k = i*8; k < nbytes/16; k++) {
-        __asm__ __volatile__ (
-            "vpshufb	%[BSWAP_EPI64], %[ctr1], %%xmm4\n\t"
-            "vpaddd		%[ONE], %[ctr1], %[ctr1]\n\t"
-            "vpxor		(%[KEY]), %%xmm4, %%xmm4\n\t"
-            "vaesenc	16(%[KEY]), %%xmm4, %%xmm4\n\t"
-            "vmovaps	%[H], %%xmm0\n\t"
-            "vmovdqu	(%[in]), %%xmm1\n\t"
-            "vaesenc	32(%[KEY]), %%xmm4, %%xmm4\n\t"
-            "vpshufb	%[BSWAP_MASK], %%xmm1, %%xmm1\n\t"
-            "vpxor		%[X], %%xmm1, %%xmm1\n\t"
-            "vaesenc	48(%[KEY]), %%xmm4, %%xmm4\n\t"
-            "vpclmulqdq	$16, %%xmm1, %%xmm0, %%xmm13\n\t"
-            "vaesenc	64(%[KEY]), %%xmm4, %%xmm4\n\t"
-            "vpclmulqdq	$1, %%xmm1, %%xmm0, %%xmm14\n\t"
-            "vaesenc	80(%[KEY]), %%xmm4, %%xmm4\n\t"
-            "vpclmulqdq	$0, %%xmm1, %%xmm0, %%xmm15\n\t"
-            "vaesenc	96(%[KEY]), %%xmm4, %%xmm4\n\t"
-            "vpclmulqdq	$17, %%xmm1, %%xmm0, %%xmm1\n\t"
-            "vaesenc	112(%[KEY]), %%xmm4, %%xmm4\n\t"
-            "vpxor		%%xmm14, %%xmm13, %%xmm13\n\t"
-            "vpslldq	$8, %%xmm13, %%xmm2\n\t"
-            "vpsrldq	$8, %%xmm13, %%xmm13\n\t"
-            "vaesenc	128(%[KEY]), %%xmm4, %%xmm4\n\t"
-            "vpxor		%%xmm15, %%xmm2, %%xmm2\n\t"
-            "vpxor		%%xmm13, %%xmm1, %%xmm3\n\t"
-            "vaesenc	144(%[KEY]), %%xmm4, %%xmm4\n\t"
-            "# Reduce\n\t"
-            "vmovdqa	%[MOD2_128], %%xmm0\n\t"
-            "vpclmulqdq	$16, %%xmm0, %%xmm2, %%xmm14\n\t"
-            "vpshufd	$78, %%xmm2, %%xmm13\n\t"
-            "vpxor		%%xmm14, %%xmm13, %%xmm13\n\t"
-            "vpclmulqdq	$16, %%xmm0, %%xmm13, %%xmm14\n\t"
-            "vpshufd	$78, %%xmm13, %%xmm13\n\t"
-            "vpxor		%%xmm14, %%xmm13, %%xmm13\n\t"
-            "vpxor		%%xmm3, %%xmm13, %%xmm13\n\t"
-            "vmovdqa	%%xmm13, %[X]\n\t"
-            "# End Reduce\n\t"
-            "cmpl		$11, %[nr]\n\t"
-            "vmovaps	160(%[KEY]), %%xmm5\n\t"
-            "jl             %=f\n\t"
-            "vaesenc	%%xmm5, %%xmm4, %%xmm4\n\t"
-            "vaesenc	176(%[KEY]), %%xmm4, %%xmm4\n\t"
-            "cmpl		$13, %[nr]\n\t"
-            "vmovaps	192(%[KEY]), %%xmm5\n\t"
-            "jl             %=f\n\t"
-            "vaesenc	%%xmm5, %%xmm4, %%xmm4\n\t"
-            "vaesenc	208(%[KEY]), %%xmm4, %%xmm4\n\t"
-            "vmovaps	224(%[KEY]), %%xmm5\n\t"
-            "%=:\n\t"
-            "vaesenclast	%%xmm5, %%xmm4, %%xmm4\n\t"
-            "vpxor		(%[in]), %%xmm4, %%xmm4\n\t"
-            "vmovdqu	%%xmm4, (%[out])\n\t"
-
-        : [H] "+xr" (H), [X] "+xr" (X),
-          [ctr1] "+xr" (ctr1)
-        : [KEY] "r" (KEY),
-          [in] "r" (&in[k*16]), [out] "r" (&out[k*16]), [nr] "r" (nr),
-          [BSWAP_MASK] "m" (BSWAP_MASK),
-          [BSWAP_EPI64] "m" (BSWAP_EPI64),
-          [ONE] "m" (ONE),
-          [MOD2_128] "m" (MOD2_128)
-        : "xmm15", "xmm14", "xmm13", "xmm4", "xmm5",
-          "xmm0", "xmm1", "xmm2", "xmm3", "memory"
-        );
-    }
-
-    /* If one partial block remains */
-    if (nbytes % 16) {
-        tmp1 = _mm_shuffle_epi8(ctr1, BSWAP_EPI64);
-        tmp1 = _mm_xor_si128(tmp1, KEY[0]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[1]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[2]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[3]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[4]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[5]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[6]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[7]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[8]);
-        tmp1 = _mm_aesenc_si128(tmp1, KEY[9]);
-        lastKey = KEY[10];
-        if (nr > 10) {
-            tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-            tmp1 = _mm_aesenc_si128(tmp1, KEY[11]);
-            lastKey = KEY[12];
-            if (nr > 12) {
-                tmp1 = _mm_aesenc_si128(tmp1, lastKey);
-                tmp1 = _mm_aesenc_si128(tmp1, KEY[13]);
-                lastKey = KEY[14];
-            }
-        }
-        tmp1 = _mm_aesenclast_si128(tmp1, lastKey);
-        last_block = _mm_setzero_si128();
-        for (j=0; j < nbytes%16; j++)
-            ((unsigned char*)&last_block)[j] = in[k*16+j];
-        XV = last_block;
-        tmp1 = _mm_xor_si128(tmp1, last_block);
-        last_block = tmp1;
-        for (j=0; j < nbytes%16; j++)
-            out[k*16+j] = ((unsigned char*)&last_block)[j];
-        XV = _mm_shuffle_epi8(XV, BSWAP_MASK);
-        XV = _mm_xor_si128(XV, X);
-        X = gfmul_shifted(XV, H);
-    }
-
-    tmp1 = _mm_insert_epi64(tmp1, nbytes*8, 0);
-    tmp1 = _mm_insert_epi64(tmp1, abytes*8, 1);
-    /* 128 x 128 Carryless Multiply */
-    X = _mm_xor_si128(X, tmp1);
-    X = gfmul_shifted(X, H);
-    X = _mm_shuffle_epi8(X, BSWAP_MASK);
-    T = _mm_xor_si128(X, T);
-
-    if (0xffff !=
-           _mm_movemask_epi8(_mm_cmpeq_epi8(T, _mm_loadu_si128((__m128i*)tag))))
-        return 0; /* in case the authentication failed */
-
-    return 1; /* when successful returns 1 */
-}
-#endif /* HAVE_INTEL_AVX2 */
 #endif /* HAVE_AES_DECRYPT */
+#endif /* _MSC_VER */
 #endif /* WOLFSSL_AESNI */
 
@@ -6483,5 +8011,5 @@
                 Z[2] ^= V[2];
                 Z[3] ^= V[3];
-            }
+        }
 
             if (V[3] & 0x00000001) {
@@ -6502,5 +8030,5 @@
                 V[1] |= ((V[0] & 0x00000001) ? 0x80000000 : 0);
                 V[0] >>= 1;
-            }
+    }
             y <<= 1;
         }
@@ -6613,14 +8141,201 @@
 
 #if !defined(WOLFSSL_XILINX_CRYPT)
+#ifdef FREESCALE_LTC_AES_GCM
 int wc_AesGcmEncrypt(Aes* aes, byte* out, const byte* in, word32 sz,
                    const byte* iv, word32 ivSz,
                    byte* authTag, word32 authTagSz,
                    const byte* authIn, word32 authInSz)
+    {
+    status_t status;
+    word32 keySize;
+
+    /* argument checks */
+    if (aes == NULL || authTagSz > AES_BLOCK_SIZE) {
+        return BAD_FUNC_ARG;
+    }
+
+    if (authTagSz < WOLFSSL_MIN_AUTH_TAG_SZ) {
+        WOLFSSL_MSG("GcmEncrypt authTagSz too small error");
+        return BAD_FUNC_ARG;
+    }
+
+    status = wc_AesGetKeySize(aes, &keySize);
+    if (status)
+        return status;
+
+    status = LTC_AES_EncryptTagGcm(LTC_BASE, in, out, sz, iv, ivSz,
+        authIn, authInSz, (byte*)aes->key, keySize, authTag, authTagSz);
+
+    return (status == kStatus_Success) ? 0 : AES_GCM_AUTH_E;
+}
+#else
+#if defined(STM32_CRYPTO) && (defined(WOLFSSL_STM32F4) || \
+                              defined(WOLFSSL_STM32F7) || \
+                              defined(WOLFSSL_STM32L4))
+
+static WC_INLINE int wc_AesGcmEncrypt_STM32(Aes* aes, byte* out, const byte* in,
+                                         word32 sz, const byte* iv, word32 ivSz,
+                                         byte* authTag, word32 authTagSz,
+                                         const byte* authIn, word32 authInSz)
+        {
+    int ret;
+#ifdef WOLFSSL_STM32_CUBEMX
+    CRYP_HandleTypeDef hcryp;
+#else
+    word32 keyCopy[AES_256_KEY_SIZE/sizeof(word32)];
+#endif
+    word32 keySize;
+    int status = 0;
+    int outPadSz, authPadSz;
+    word32 tag[AES_BLOCK_SIZE/sizeof(word32)];
+    word32 initialCounter[AES_BLOCK_SIZE/sizeof(word32)];
+    byte* outPadded = NULL;
+    byte* authInPadded = NULL;
+
+    ret = wc_AesGetKeySize(aes, &keySize);
+    if (ret != 0)
+        return ret;
+
+#ifdef WOLFSSL_STM32_CUBEMX
+    ret = wc_Stm32_Aes_Init(aes, &hcryp);
+    if (ret != 0)
+        return ret;
+#endif
+
+    XMEMSET(initialCounter, 0, sizeof(initialCounter));
+    XMEMCPY(initialCounter, iv, ivSz);
+    *((byte*)initialCounter + (AES_BLOCK_SIZE - 1)) = STM32_GCM_IV_START;
+
+    /* Need to pad the AAD and input cipher text to a full block size since
+     * CRYP_AES_GCM will assume these are a multiple of AES_BLOCK_SIZE.
+     * It is okay to pad with zeros because GCM does this before GHASH already.
+     * See NIST SP 800-38D */
+    if ((sz % AES_BLOCK_SIZE) != 0 || sz == 0) {
+        outPadSz = ((sz / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE;
+        outPadded = (byte*)XMALLOC(outPadSz, aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        if (outPadded == NULL) {
+            return MEMORY_E;
+        }
+        XMEMSET(outPadded, 0, outPadSz);
+    }
+    else {
+        outPadSz = sz;
+        outPadded = out;
+    }
+    XMEMCPY(outPadded, in, sz);
+
+    if (authInSz == 0 || (authInSz % AES_BLOCK_SIZE) != 0) {
+        /* Need to pad the AAD to a full block with zeros. */
+        authPadSz = ((authInSz / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE;
+        authInPadded = (byte*)XMALLOC(authPadSz, aes->heap,
+            DYNAMIC_TYPE_TMP_BUFFER);
+        if (authInPadded == NULL) {
+            if (outPadded != out) {
+                XFREE(outPadded, aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
+            }
+            return MEMORY_E;
+            }
+        XMEMSET(authInPadded, 0, authPadSz);
+        XMEMCPY(authInPadded, authIn, authInSz);
+    } else {
+        authPadSz = authInSz;
+        authInPadded = (byte*)authIn;
+    }
+
+
+#ifdef WOLFSSL_STM32_CUBEMX
+    hcryp.Init.pInitVect = (uint8_t*)initialCounter;
+    hcryp.Init.Header = authInPadded;
+    hcryp.Init.HeaderSize = authInSz;
+
+#ifdef STM32_CRYPTO_AES_ONLY
+    /* Set the CRYP parameters */
+    hcryp.Init.ChainingMode  = CRYP_CHAINMODE_AES_GCM_GMAC;
+    hcryp.Init.OperatingMode = CRYP_ALGOMODE_ENCRYPT;
+    hcryp.Init.GCMCMACPhase  = CRYP_INIT_PHASE;
+    HAL_CRYP_Init(&hcryp);
+
+    /* GCM init phase */
+    status = HAL_CRYPEx_AES_Auth(&hcryp, NULL, 0, NULL, STM32_HAL_TIMEOUT);
+    if (status == HAL_OK) {
+        /* GCM header phase */
+        hcryp.Init.GCMCMACPhase  = CRYP_HEADER_PHASE;
+        status = HAL_CRYPEx_AES_Auth(&hcryp, NULL, 0, NULL, STM32_HAL_TIMEOUT);
+        if (status == HAL_OK) {
+            /* GCM payload phase */
+            hcryp.Init.GCMCMACPhase  = CRYP_PAYLOAD_PHASE;
+            status = HAL_CRYPEx_AES_Auth(&hcryp, outPadded, sz, outPadded,
+                STM32_HAL_TIMEOUT);
+            if (status == HAL_OK) {
+                /* GCM final phase */
+                hcryp.Init.GCMCMACPhase  = CRYP_FINAL_PHASE;
+                status = HAL_CRYPEx_AES_Auth(&hcryp, NULL, sz, (byte*)tag,
+                    STM32_HAL_TIMEOUT);
+            }
+        }
+    }
+#else
+    HAL_CRYP_Init(&hcryp);
+
+    status = HAL_CRYPEx_AESGCM_Encrypt(&hcryp, outPadded, sz,
+                                       outPadded, STM32_HAL_TIMEOUT);
+    /* Compute the authTag */
+    if (status == HAL_OK) {
+        status = HAL_CRYPEx_AESGCM_Finish(&hcryp, sz, (byte*)tag,
+            STM32_HAL_TIMEOUT);
+    }
+#endif
+
+    if (status != HAL_OK)
+        ret = AES_GCM_AUTH_E;
+    HAL_CRYP_DeInit(&hcryp);
+
+#else /* STD_PERI_LIB */
+    ByteReverseWords(keyCopy, (word32*)aes->key, keySize);
+    status = CRYP_AES_GCM(MODE_ENCRYPT, (uint8_t*)initialCounter,
+                         (uint8_t*)keyCopy,     keySize * 8,
+                         (uint8_t*)outPadded,   sz,
+                         (uint8_t*)authInPadded,authInSz,
+                         (uint8_t*)outPadded,   (byte*)tag);
+    if (status != SUCCESS)
+        ret = AES_GCM_AUTH_E;
+#endif /* WOLFSSL_STM32_CUBEMX */
+
+    if (ret == 0) {
+        /* return authTag */
+    	XMEMCPY(authTag, tag, authTagSz);
+
+        /* return output if allocated padded used */
+        if (outPadded != out) {
+            XMEMCPY(out, outPadded, sz);
+            }
+        }
+
+    /* Free memory if not a multiple of AES_BLOCK_SZ */
+    if (outPadded != out) {
+        XFREE(outPadded, aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    }
+    if (authInPadded != authIn) {
+        XFREE(authInPadded, aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
+}
+
+    return ret;
+}
+#endif /* STM32_CRYPTO */
+
+#ifdef WOLFSSL_AESNI
+int AES_GCM_encrypt_C(Aes* aes, byte* out, const byte* in, word32 sz,
+                      const byte* iv, word32 ivSz,
+                      byte* authTag, word32 authTagSz,
+                      const byte* authIn, word32 authInSz);
+#else
+static
+#endif
+int AES_GCM_encrypt_C(Aes* aes, byte* out, const byte* in, word32 sz,
+                      const byte* iv, word32 ivSz,
+                      byte* authTag, word32 authTagSz,
+                      const byte* authIn, word32 authInSz)
 {
     int ret = 0;
-    word32 keySize;
-#ifdef FREESCALE_LTC_AES_GCM
-    status_t status;
-#else
     word32 blocks = sz / AES_BLOCK_SIZE;
     word32 partial = sz % AES_BLOCK_SIZE;
@@ -6631,142 +8346,125 @@
     byte *ctr;
     byte scratch[AES_BLOCK_SIZE];
-#if defined(STM32_CRYPTO) && (defined(WOLFSSL_STM32F4) || defined(WOLFSSL_STM32F7))
-    #ifdef WOLFSSL_STM32_CUBEMX
-        CRYP_HandleTypeDef hcryp;
-    #else
-        byte keyCopy[AES_BLOCK_SIZE * 2];
-    #endif /* WOLFSSL_STM32_CUBEMX */
-    int status = 0;
-    byte* authInPadded = NULL;
-    byte tag[AES_BLOCK_SIZE];
-    int authPadSz;
-#endif /* STM32_CRYPTO */
-#endif /* FREESCALE_LTC_AES_GCM */
-
+
+    ctr = counter;
+    XMEMSET(initialCounter, 0, AES_BLOCK_SIZE);
+    if (ivSz == GCM_NONCE_MID_SZ) {
+        XMEMCPY(initialCounter, iv, ivSz);
+        initialCounter[AES_BLOCK_SIZE - 1] = 1;
+    }
+    else {
+        GHASH(aes, NULL, 0, iv, ivSz, initialCounter, AES_BLOCK_SIZE);
+    }
+    XMEMCPY(ctr, initialCounter, AES_BLOCK_SIZE);
+
+#ifdef WOLFSSL_PIC32MZ_CRYPT
+    if (blocks) {
+        /* use initial IV for PIC32 HW, but don't use it below */
+        XMEMCPY(aes->reg, ctr, AES_BLOCK_SIZE);
+
+        ret = wc_Pic32AesCrypt(
+            aes->key, aes->keylen, aes->reg, AES_BLOCK_SIZE,
+            out, in, (blocks * AES_BLOCK_SIZE),
+            PIC32_ENCRYPTION, PIC32_ALGO_AES, PIC32_CRYPTOALGO_AES_GCM);
+        if (ret != 0)
+            return ret;
+        }
+    /* process remainder using partial handling */
+            #endif
+
+#if defined(HAVE_AES_ECB) && !defined(WOLFSSL_PIC32MZ_CRYPT)
+    /* some hardware acceleration can gain performance from doing AES encryption
+     * of the whole buffer at once */
+    if (c != p) { /* can not handle inline encryption */
+        while (blocks--) {
+            IncrementGcmCounter(ctr);
+            XMEMCPY(c, ctr, AES_BLOCK_SIZE);
+            c += AES_BLOCK_SIZE;
+        }
+
+        /* reset number of blocks and then do encryption */
+        blocks = sz / AES_BLOCK_SIZE;
+        wc_AesEcbEncrypt(aes, out, out, AES_BLOCK_SIZE * blocks);
+        xorbuf(out, p, AES_BLOCK_SIZE * blocks);
+        p += AES_BLOCK_SIZE * blocks;
+    }
+    else
+#endif /* HAVE_AES_ECB */
+
+        while (blocks--) {
+        IncrementGcmCounter(ctr);
+    #ifndef WOLFSSL_PIC32MZ_CRYPT
+        wc_AesEncrypt(aes, ctr, scratch);
+        xorbuf(scratch, p, AES_BLOCK_SIZE);
+        XMEMCPY(c, scratch, AES_BLOCK_SIZE);
+            #endif
+        p += AES_BLOCK_SIZE;
+            c += AES_BLOCK_SIZE;
+        }
+
+        if (partial != 0) {
+        IncrementGcmCounter(ctr);
+        wc_AesEncrypt(aes, ctr, scratch);
+        xorbuf(scratch, p, partial);
+        XMEMCPY(c, scratch, partial);
+    }
+
+    GHASH(aes, authIn, authInSz, out, sz, authTag, authTagSz);
+    wc_AesEncrypt(aes, initialCounter, scratch);
+    xorbuf(authTag, scratch, authTagSz);
+
+    return ret;
+}
+
+/* Software AES - GCM Encrypt */
+int wc_AesGcmEncrypt(Aes* aes, byte* out, const byte* in, word32 sz,
+                   const byte* iv, word32 ivSz,
+                   byte* authTag, word32 authTagSz,
+                   const byte* authIn, word32 authInSz)
+        {
     /* argument checks */
     if (aes == NULL || authTagSz > AES_BLOCK_SIZE) {
         return BAD_FUNC_ARG;
-    }
+            }
 
     if (authTagSz < WOLFSSL_MIN_AUTH_TAG_SZ) {
         WOLFSSL_MSG("GcmEncrypt authTagSz too small error");
         return BAD_FUNC_ARG;
-    }
-
-    ret = wc_AesGetKeySize(aes, &keySize);
-    if (ret != 0)
-        return ret;
-
-#ifdef FREESCALE_LTC_AES_GCM
-
-    status = LTC_AES_EncryptTagGcm(LTC_BASE, in, out, sz, iv, ivSz,
-        authIn, authInSz, (byte*)aes->key, keySize, authTag, authTagSz);
-
-    ret = (status == kStatus_Success) ? 0 : AES_GCM_AUTH_E;
-
-#else
-
-#if defined(STM32_CRYPTO) && (defined(WOLFSSL_STM32F4) || defined(WOLFSSL_STM32F7))
-
-    /* additional argument checks - STM32 HW only supports 12 byte IV */
-    if (ivSz != NONCE_SZ) {
-        return BAD_FUNC_ARG;
-    }
-
-    XMEMSET(initialCounter, 0, AES_BLOCK_SIZE);
-    XMEMCPY(initialCounter, iv, ivSz);
-    initialCounter[AES_BLOCK_SIZE - 1] = STM32_GCM_IV_START;
-
-    /* STM32 HW AES-GCM requires / assumes inputs are a multiple of block size.
-     * We can avoid this by zero padding (authIn) AAD, but zero-padded plaintext
-     * will be encrypted and output incorrectly, causing a bad authTag.
-     * We will use HW accelerated AES-GCM if plain%AES_BLOCK_SZ==0.
-     * Otherwise, we will use accelerated AES_CTR for encrypt, and then
-     * perform GHASH in software.
-     * See NIST SP 800-38D */
-
-    /* Plain text is a multiple of block size, so use HW-Accelerated AES_GCM */
-    if (!partial) {
-        /* pad authIn if it is not a block multiple */
-        if ((authInSz % AES_BLOCK_SIZE) != 0) {
-            authPadSz = ((authInSz / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE;
-            /* Need to pad the AAD to a full block with zeros. */
-            authInPadded = XMALLOC(authPadSz, aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
-            if (authInPadded == NULL) {
-                return MEMORY_E;
-            }
-            XMEMSET(authInPadded, 0, authPadSz);
-            XMEMCPY(authInPadded, authIn, authInSz);
-        } else {
-            authPadSz = authInSz;
-            authInPadded = (byte*)authIn;
-        }
-
-
-    #ifdef WOLFSSL_STM32_CUBEMX
-        XMEMSET(&hcryp, 0, sizeof(CRYP_HandleTypeDef));
-        switch (keySize) {
-            case 16: /* 128-bit key */
-                hcryp.Init.KeySize = CRYP_KEYSIZE_128B;
-                break;
-            case 24: /* 192-bit key */
-                hcryp.Init.KeySize = CRYP_KEYSIZE_192B;
-                break;
-            case 32: /* 256-bit key */
-                hcryp.Init.KeySize = CRYP_KEYSIZE_256B;
-                break;
-            default:
-                break;
-        }
-        hcryp.Instance = CRYP;
-        hcryp.Init.DataType = CRYP_DATATYPE_8B;
-        hcryp.Init.pKey = (byte*)aes->key;
-        hcryp.Init.pInitVect = initialCounter;
-        hcryp.Init.Header = authInPadded;
-        hcryp.Init.HeaderSize = authInSz;
-
-        HAL_CRYP_Init(&hcryp);
-        status = HAL_CRYPEx_AESGCM_Encrypt(&hcryp, (byte*)in, sz,
-                                        out, STM32_HAL_TIMEOUT);
-        /* Compute the authTag */
-        if (status == HAL_OK)
-            status = HAL_CRYPEx_AESGCM_Finish(&hcryp, sz, tag, STM32_HAL_TIMEOUT);
-
-        if (status != HAL_OK)
-            ret = AES_GCM_AUTH_E;
-        HAL_CRYP_DeInit(&hcryp);
-    #else
-        ByteReverseWords((word32*)keyCopy, (word32*)aes->key, keySize);
-        status = CRYP_AES_GCM(MODE_ENCRYPT, (uint8_t*)initialCounter,
-                             (uint8_t*)keyCopy,     keySize * 8,
-                             (uint8_t*)in,          sz,
-                             (uint8_t*)authInPadded,authInSz,
-                             (uint8_t*)out,         tag);
-        if (status != SUCCESS)
-            ret = AES_GCM_AUTH_E;
-    #endif /* WOLFSSL_STM32_CUBEMX */
-
-        /* authTag may be shorter than AES_BLOCK_SZ, store separately */
-        if (ret == 0)
-        	XMEMCPY(authTag, tag, authTagSz);
-
-        /* We only allocate extra memory if authInPadded is not a multiple of AES_BLOCK_SZ */
-        if (authInPadded != NULL && authInSz != authPadSz) {
-            XFREE(authInPadded, aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
-        }
-
-        return ret;
-    }
-
+}
+
+#ifdef WOLF_CRYPTO_DEV
+    if (aes->devId != INVALID_DEVID) {
+        int ret = wc_CryptoDev_AesGcmEncrypt(aes, out, in, sz, iv, ivSz,
+            authTag, authTagSz, authIn, authInSz);
+        if (ret != NOT_COMPILED_IN)
+            return ret;
+        ret = 0; /* reset error code and try using software */
+    }
 #endif
 
-    /* Software AES-GCM */
+#if defined(STM32_CRYPTO) && (defined(WOLFSSL_STM32F4) || \
+                              defined(WOLFSSL_STM32F7) || \
+                              defined(WOLFSSL_STM32L4))
+
+    /* STM32 HW only supports 12 byte IV and 16 byte auth */
+    if (ivSz == GCM_NONCE_MID_SZ && authInSz == AES_BLOCK_SIZE) {
+        return wc_AesGcmEncrypt_STM32(aes, out, in, sz, iv, ivSz,
+                                      authTag, authTagSz, authIn, authInSz);
+    }
+    #endif
 
 #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_AES)
     /* if async and byte count above threshold */
+    /* only 12-byte IV is supported in HW */
     if (aes->asyncDev.marker == WOLFSSL_ASYNC_MARKER_AES &&
-                                                sz >= WC_ASYNC_THRESH_AES_GCM) {
+                    sz >= WC_ASYNC_THRESH_AES_GCM && ivSz == GCM_NONCE_MID_SZ) {
     #if defined(HAVE_CAVIUM)
-        /* Not yet supported, contact wolfSSL if interested in using */
+        #ifdef HAVE_CAVIUM_V
+        if (authInSz == 20) { /* Nitrox V GCM is only working with 20 byte AAD */
+            return NitroxAesGcmEncrypt(aes, out, in, sz,
+                (const byte*)aes->asyncKey, aes->keylen, iv, ivSz,
+                authTag, authTagSz, authIn, authInSz);
+        }
+            #endif
     #elif defined(HAVE_INTEL_QA)
         return IntelQaSymAesGcmEncrypt(&aes->asyncDev, out, in, sz,
@@ -6788,78 +8486,44 @@
             return WC_PENDING_E;
         }
+            #endif
+    }
+#endif /* WOLFSSL_ASYNC_CRYPT */
+
+#ifdef WOLFSSL_AESNI
+    #ifdef HAVE_INTEL_AVX2
+    if (IS_INTEL_AVX2(intel_flags)) {
+        AES_GCM_encrypt_avx2(in, out, authIn, iv, authTag, sz, authInSz, ivSz,
+                                 authTagSz, (const byte*)aes->key, aes->rounds);
+        return 0;
+        }
+    else
+            #endif
+    #ifdef HAVE_INTEL_AVX1
+    if (IS_INTEL_AVX1(intel_flags)) {
+        AES_GCM_encrypt_avx1(in, out, authIn, iv, authTag, sz, authInSz, ivSz,
+                                 authTagSz, (const byte*)aes->key, aes->rounds);
+        return 0;
+        }
+    else
     #endif
-    }
-#endif /* WOLFSSL_ASYNC_CRYPT */
-
-#ifdef WOLFSSL_AESNI
     if (haveAESNI) {
-    #ifdef HAVE_INTEL_AVX2
-        if (IS_INTEL_AVX2(intel_flags)) {
-            AES_GCM_encrypt_avx2(in, out, authIn, iv, authTag,
-                        sz, authInSz, ivSz, (const byte*)aes->key, aes->rounds);
-        }
-        else
-    #endif
-            AES_GCM_encrypt(in, out, authIn, iv, authTag,
-                        sz, authInSz, ivSz, (const byte*)aes->key, aes->rounds);
+        AES_GCM_encrypt(in, out, authIn, iv, authTag, sz, authInSz, ivSz,
+                                 authTagSz, (const byte*)aes->key, aes->rounds);
         return 0;
     }
+    else
 #endif
-
-    ctr = counter;
-    XMEMSET(initialCounter, 0, AES_BLOCK_SIZE);
-    if (ivSz == NONCE_SZ) {
-        XMEMCPY(initialCounter, iv, ivSz);
-        initialCounter[AES_BLOCK_SIZE - 1] = 1;
-    }
-    else {
-        GHASH(aes, NULL, 0, iv, ivSz, initialCounter, AES_BLOCK_SIZE);
-    }
-    XMEMCPY(ctr, initialCounter, AES_BLOCK_SIZE);
-
-#ifdef WOLFSSL_PIC32MZ_CRYPT
-    if (blocks) {
-        /* use intitial IV for PIC32 HW, but don't use it below */
-        XMEMCPY(aes->reg, ctr, AES_BLOCK_SIZE);
-
-        ret = wc_Pic32AesCrypt(
-            aes->key, aes->keylen, aes->reg, AES_BLOCK_SIZE,
-            out, in, (blocks * AES_BLOCK_SIZE),
-            PIC32_ENCRYPTION, PIC32_ALGO_AES, PIC32_CRYPTOALGO_AES_GCM);
-        if (ret != 0)
-            return ret;
-    }
-    /* process remainder using partial handling */
+    {
+        return AES_GCM_encrypt_C(aes, out, in, sz, iv, ivSz, authTag, authTagSz,
+                                                              authIn, authInSz);
+    }
+}
 #endif
-    while (blocks--) {
-        IncrementGcmCounter(ctr);
-    #ifndef WOLFSSL_PIC32MZ_CRYPT
-        wc_AesEncrypt(aes, ctr, scratch);
-        xorbuf(scratch, p, AES_BLOCK_SIZE);
-        XMEMCPY(c, scratch, AES_BLOCK_SIZE);
-    #endif
-        p += AES_BLOCK_SIZE;
-        c += AES_BLOCK_SIZE;
-    }
-
-    if (partial != 0) {
-        IncrementGcmCounter(ctr);
-        wc_AesEncrypt(aes, ctr, scratch);
-        xorbuf(scratch, p, partial);
-        XMEMCPY(c, scratch, partial);
-
-    }
-
-    GHASH(aes, authIn, authInSz, out, sz, authTag, authTagSz);
-    wc_AesEncrypt(aes, initialCounter, scratch);
-    xorbuf(authTag, scratch, authTagSz);
-
-#endif /* FREESCALE_LTC_AES_GCM */
-
-    return ret;
-}
-
-
+
+
+
+/* AES GCM Decrypt */
 #if defined(HAVE_AES_DECRYPT) || defined(HAVE_AESGCM_DECRYPT)
+#ifdef FREESCALE_LTC_AES_GCM
 int  wc_AesGcmDecrypt(Aes* aes, byte* out, const byte* in, word32 sz,
                    const byte* iv, word32 ivSz,
@@ -6867,21 +8531,205 @@
                    const byte* authIn, word32 authInSz)
 {
+    int ret;
+    word32 keySize;
+    status_t status;
+
+    /* argument checks */
+    /* If the sz is non-zero, both in and out must be set. If sz is 0,
+     * in and out are don't cares, as this is is the GMAC case. */
+    if (aes == NULL || iv == NULL || (sz != 0 && (in == NULL || out == NULL)) ||
+        authTag == NULL || authTagSz > AES_BLOCK_SIZE || authTagSz == 0) {
+
+        return BAD_FUNC_ARG;
+    }
+
+    ret = wc_AesGetKeySize(aes, &keySize);
+    if (ret != 0) {
+        return ret;
+    }
+
+    status = LTC_AES_DecryptTagGcm(LTC_BASE, in, out, sz, iv, ivSz,
+        authIn, authInSz, (byte*)aes->key, keySize, authTag, authTagSz);
+
+    return (status == kStatus_Success) ? 0 : AES_GCM_AUTH_E;
+}
+
+#else
+
+#if defined(STM32_CRYPTO) && (defined(WOLFSSL_STM32F4) || \
+                              defined(WOLFSSL_STM32F7) || \
+                              defined(WOLFSSL_STM32L4))
+static WC_INLINE int wc_AesGcmDecrypt_STM32(Aes* aes, byte* out,
+                    const byte* in, word32 sz,
+                    const byte* iv, word32 ivSz,
+                    const byte* authTag, word32 authTagSz,
+                    const byte* authIn, word32 authInSz)
+{
+    int ret;
+#ifdef WOLFSSL_STM32_CUBEMX
+    CRYP_HandleTypeDef hcryp;
+#else
+    word32 keyCopy[AES_256_KEY_SIZE/sizeof(word32)];
+#endif
+    word32 keySize;
+    int status;
+    int outPadSz, authPadSz;
+    word32 tag[AES_BLOCK_SIZE/sizeof(word32)];
+    word32 initialCounter[AES_BLOCK_SIZE/sizeof(word32)];
+    byte* outPadded = NULL;
+    byte* authInPadded = NULL;
+
+    ret = wc_AesGetKeySize(aes, &keySize);
+    if (ret != 0)
+        return ret;
+
+#ifdef WOLFSSL_STM32_CUBEMX
+    ret = wc_Stm32_Aes_Init(aes, &hcryp);
+    if (ret != 0)
+        return ret;
+#endif
+
+    XMEMSET(initialCounter, 0, sizeof(initialCounter));
+    XMEMCPY(initialCounter, iv, ivSz);
+    *((byte*)initialCounter + (AES_BLOCK_SIZE - 1)) = STM32_GCM_IV_START;
+
+    /* Need to pad the AAD and input cipher text to a full block size since
+     * CRYP_AES_GCM will assume these are a multiple of AES_BLOCK_SIZE.
+     * It is okay to pad with zeros because GCM does this before GHASH already.
+     * See NIST SP 800-38D */
+    if ((sz % AES_BLOCK_SIZE) != 0 || sz == 0) {
+        outPadSz = ((sz / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE;
+        outPadded = (byte*)XMALLOC(outPadSz, aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        if (outPadded == NULL) {
+            return MEMORY_E;
+        }
+        XMEMSET(outPadded, 0, outPadSz);
+    }
+    else {
+        outPadSz = sz;
+        outPadded = out;
+    }
+    XMEMCPY(outPadded, in, sz);
+
+    if (authInSz == 0 || (authInSz % AES_BLOCK_SIZE) != 0) {
+            /* Need to pad the AAD to a full block with zeros. */
+        authPadSz = ((authInSz / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE;
+        authInPadded = (byte*)XMALLOC(authPadSz, aes->heap,
+            DYNAMIC_TYPE_TMP_BUFFER);
+            if (authInPadded == NULL) {
+            if (outPadded != out) {
+                XFREE(outPadded, aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
+            }
+                return MEMORY_E;
+            }
+            XMEMSET(authInPadded, 0, authPadSz);
+            XMEMCPY(authInPadded, authIn, authInSz);
+        } else {
+            authPadSz = authInSz;
+            authInPadded = (byte*)authIn;
+        }
+
+    #ifdef WOLFSSL_STM32_CUBEMX
+    hcryp.Init.pInitVect = (uint8_t*)initialCounter;
+        hcryp.Init.Header = authInPadded;
+        hcryp.Init.HeaderSize = authInSz;
+
+#ifdef STM32_CRYPTO_AES_ONLY
+    /* Set the CRYP parameters */
+    hcryp.Init.ChainingMode  = CRYP_CHAINMODE_AES_GCM_GMAC;
+    hcryp.Init.OperatingMode = CRYP_ALGOMODE_DECRYPT;
+    hcryp.Init.GCMCMACPhase  = CRYP_INIT_PHASE;
+        HAL_CRYP_Init(&hcryp);
+
+    /* GCM init phase */
+    status = HAL_CRYPEx_AES_Auth(&hcryp, NULL, 0, NULL, STM32_HAL_TIMEOUT);
+    if (status == HAL_OK) {
+        /* GCM header phase */
+        hcryp.Init.GCMCMACPhase = CRYP_HEADER_PHASE;
+        status = HAL_CRYPEx_AES_Auth(&hcryp, NULL, 0, NULL, STM32_HAL_TIMEOUT);
+        if (status == HAL_OK) {
+            /* GCM payload phase */
+            hcryp.Init.GCMCMACPhase = CRYP_PAYLOAD_PHASE;
+            status = HAL_CRYPEx_AES_Auth(&hcryp, outPadded, sz, outPadded,
+                STM32_HAL_TIMEOUT);
+            if (status == HAL_OK) {
+                /* GCM final phase */
+                hcryp.Init.GCMCMACPhase = CRYP_FINAL_PHASE;
+                status = HAL_CRYPEx_AES_Auth(&hcryp, NULL, sz, (byte*)tag,
+                    STM32_HAL_TIMEOUT);
+            }
+        }
+    }
+#else
+    HAL_CRYP_Init(&hcryp);
+    /* Use outPadded for output buffer instead of out so that we don't overflow
+     * our size. */
+    status = HAL_CRYPEx_AESGCM_Decrypt(&hcryp, outPadded, sz, outPadded,
+        STM32_HAL_TIMEOUT);
+        /* Compute the authTag */
+    if (status == HAL_OK) {
+        status = HAL_CRYPEx_AESGCM_Finish(&hcryp, sz, (byte*)tag,
+            STM32_HAL_TIMEOUT);
+    }
+#endif
+
+        if (status != HAL_OK)
+            ret = AES_GCM_AUTH_E;
+
+        HAL_CRYP_DeInit(&hcryp);
+
+#else /* STD_PERI_LIB */
+    ByteReverseWords(keyCopy, (word32*)aes->key, aes->keylen);
+
+    /* Input size and auth size need to be the actual sizes, even though
+     * they are not block aligned, because this length (in bits) is used
+     * in the final GHASH. Use outPadded for output buffer instead of
+     * out so that we don't overflow our size.                         */
+    status = CRYP_AES_GCM(MODE_DECRYPT, (uint8_t*)initialCounter,
+                             (uint8_t*)keyCopy,     keySize * 8,
+                         (uint8_t*)outPadded,   sz,
+                             (uint8_t*)authInPadded,authInSz,
+                         (uint8_t*)outPadded,   (byte*)tag);
+        if (status != SUCCESS)
+            ret = AES_GCM_AUTH_E;
+    #endif /* WOLFSSL_STM32_CUBEMX */
+
+    if (ConstantCompare(authTag, (byte*)tag, authTagSz) != 0) {
+        ret = AES_GCM_AUTH_E;
+        }
+
+    if (ret == 0) {
+        /* return output if allocated padded used */
+        if (outPadded != out) {
+            XMEMCPY(out, outPadded, sz);
+        }
+    }
+
+    /* Free memory if not a multiple of AES_BLOCK_SZ */
+    if (outPadded != out) {
+        XFREE(outPadded, aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        }
+    if (authInPadded != authIn) {
+        XFREE(authInPadded, aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    }
+
+    return ret;
+    }
+#endif /* STM32 */
+
+#ifdef WOLFSSL_AESNI
+int AES_GCM_decrypt_C(Aes* aes, byte* out, const byte* in, word32 sz,
+                      const byte* iv, word32 ivSz,
+                      const byte* authTag, word32 authTagSz,
+                      const byte* authIn, word32 authInSz);
+#else
+static
+#endif
+int AES_GCM_decrypt_C(Aes* aes, byte* out, const byte* in, word32 sz,
+                      const byte* iv, word32 ivSz,
+                      const byte* authTag, word32 authTagSz,
+                      const byte* authIn, word32 authInSz)
+{
     int ret = 0;
-    word32 keySize;
-#ifdef FREESCALE_LTC_AES_GCM
-    status_t status;
-#elif defined(STM32_CRYPTO) && (defined(WOLFSSL_STM32F4) || defined(WOLFSSL_STM32F7))
-    #ifdef WOLFSSL_STM32_CUBEMX
-        CRYP_HandleTypeDef hcryp;
-    #else
-        byte keyCopy[AES_BLOCK_SIZE * 2];
-    #endif /* WOLFSSL_STM32_CUBEMX */
-    int  status;
-    int  inPadSz, authPadSz;
-    byte tag[AES_BLOCK_SIZE];
-    byte *inPadded = NULL;
-    byte *authInPadded = NULL;
-    byte initialCounter[AES_BLOCK_SIZE];
-#else /* software AES-GCM */
     word32 blocks = sz / AES_BLOCK_SIZE;
     word32 partial = sz % AES_BLOCK_SIZE;
@@ -6894,141 +8742,131 @@
     byte Tprime[AES_BLOCK_SIZE];
     byte EKY0[AES_BLOCK_SIZE];
+    ctr = counter;
+
+    XMEMSET(initialCounter, 0, AES_BLOCK_SIZE);
+    if (ivSz == GCM_NONCE_MID_SZ) {
+        XMEMCPY(initialCounter, iv, ivSz);
+        initialCounter[AES_BLOCK_SIZE - 1] = 1;
+    }
+    else {
+        GHASH(aes, NULL, 0, iv, ivSz, initialCounter, AES_BLOCK_SIZE);
+    }
+    XMEMCPY(ctr, initialCounter, AES_BLOCK_SIZE);
+
+    /* Calc the authTag again using the received auth data and the cipher text */
+    GHASH(aes, authIn, authInSz, in, sz, Tprime, sizeof(Tprime));
+    wc_AesEncrypt(aes, ctr, EKY0);
+    xorbuf(Tprime, EKY0, sizeof(Tprime));
+
+    if (ConstantCompare(authTag, Tprime, authTagSz) != 0) {
+        return AES_GCM_AUTH_E;
+    }
+
+#ifdef WOLFSSL_PIC32MZ_CRYPT
+    if (blocks) {
+        /* use initial IV for PIC32 HW, but don't use it below */
+        XMEMCPY(aes->reg, ctr, AES_BLOCK_SIZE);
+
+        ret = wc_Pic32AesCrypt(
+            aes->key, aes->keylen, aes->reg, AES_BLOCK_SIZE,
+            out, in, (blocks * AES_BLOCK_SIZE),
+            PIC32_DECRYPTION, PIC32_ALGO_AES, PIC32_CRYPTOALGO_AES_GCM);
+        if (ret != 0)
+            return ret;
+    }
+    /* process remainder using partial handling */
 #endif
 
+#if defined(HAVE_AES_ECB) && !defined(WOLFSSL_PIC32MZ_CRYPT)
+    /* some hardware acceleration can gain performance from doing AES encryption
+     * of the whole buffer at once */
+    if (c != p) { /* can not handle inline decryption */
+        while (blocks--) {
+            IncrementGcmCounter(ctr);
+            XMEMCPY(p, ctr, AES_BLOCK_SIZE);
+            p += AES_BLOCK_SIZE;
+        }
+
+        /* reset number of blocks and then do encryption */
+        blocks = sz / AES_BLOCK_SIZE;
+        wc_AesEcbEncrypt(aes, out, out, AES_BLOCK_SIZE * blocks);
+        xorbuf(out, c, AES_BLOCK_SIZE * blocks);
+        c += AES_BLOCK_SIZE * blocks;
+    }
+    else
+#endif /* HAVE_AES_ECB */
+    while (blocks--) {
+        IncrementGcmCounter(ctr);
+    #ifndef WOLFSSL_PIC32MZ_CRYPT
+        wc_AesEncrypt(aes, ctr, scratch);
+        xorbuf(scratch, c, AES_BLOCK_SIZE);
+        XMEMCPY(p, scratch, AES_BLOCK_SIZE);
+    #endif
+        p += AES_BLOCK_SIZE;
+        c += AES_BLOCK_SIZE;
+    }
+
+    if (partial != 0) {
+        IncrementGcmCounter(ctr);
+        wc_AesEncrypt(aes, ctr, scratch);
+        xorbuf(scratch, c, partial);
+        XMEMCPY(p, scratch, partial);
+    }
+
+    return ret;
+}
+
+/* Software AES - GCM Decrypt */
+int  wc_AesGcmDecrypt(Aes* aes, byte* out, const byte* in, word32 sz,
+                   const byte* iv, word32 ivSz,
+                   const byte* authTag, word32 authTagSz,
+                   const byte* authIn, word32 authInSz)
+{
+#ifdef WOLFSSL_AESNI
+    int res = AES_GCM_AUTH_E;
+#endif
+
     /* argument checks */
-    if (aes == NULL || out == NULL || in == NULL || iv == NULL ||
-        authTag == NULL || authTagSz > AES_BLOCK_SIZE) {
+    /* If the sz is non-zero, both in and out must be set. If sz is 0,
+     * in and out are don't cares, as this is is the GMAC case. */
+    if (aes == NULL || iv == NULL || (sz != 0 && (in == NULL || out == NULL)) ||
+        authTag == NULL || authTagSz > AES_BLOCK_SIZE || authTagSz == 0) {
+
         return BAD_FUNC_ARG;
     }
 
-    ret = wc_AesGetKeySize(aes, &keySize);
-    if (ret != 0) {
-        return ret;
-    }
-
-#ifdef FREESCALE_LTC_AES_GCM
-
-    status = LTC_AES_DecryptTagGcm(LTC_BASE, in, out, sz, iv, ivSz,
-        authIn, authInSz, (byte*)aes->key, keySize, authTag, authTagSz);
-
-    ret = (status == kStatus_Success) ? 0 : AES_GCM_AUTH_E;
-
-#elif defined(STM32_CRYPTO) && (defined(WOLFSSL_STM32F4) || defined(WOLFSSL_STM32F7))
-
-    /* additional argument checks - STM32 HW only supports 12 byte IV */
-    if (ivSz != NONCE_SZ) {
-        return BAD_FUNC_ARG;
-    }
-
-    XMEMSET(initialCounter, 0, AES_BLOCK_SIZE);
-    XMEMCPY(initialCounter, iv, ivSz);
-    initialCounter[AES_BLOCK_SIZE - 1] = STM32_GCM_IV_START;
-
-    /* Need to pad the AAD and input cipher text to a full block size since
-     * CRYP_AES_GCM will assume these are a multiple of AES_BLOCK_SIZE.
-     * It is okay to pad with zeros because GCM does this before GHASH already.
-     * See NIST SP 800-38D */
-
-    if ((sz % AES_BLOCK_SIZE) > 0) {
-        inPadSz = ((sz / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE;
-        inPadded = XMALLOC(inPadSz, aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
-        if (inPadded == NULL) {
-            return MEMORY_E;
-        }
-        XMEMSET(inPadded, 0, inPadSz);
-        XMEMCPY(inPadded, in, sz);
-    } else {
-        inPadSz = sz;
-        inPadded = (byte*)in;
-    }
-
-    if ((authInSz % AES_BLOCK_SIZE) > 0) {
-        authPadSz = ((authInSz / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE;
-        authInPadded = XMALLOC(authPadSz, aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
-        if (authInPadded == NULL) {
-            if (inPadded != NULL && inPadSz != sz)
-                XFREE(inPadded , aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
-            return MEMORY_E;
-        }
-        XMEMSET(authInPadded, 0, authPadSz);
-        XMEMCPY(authInPadded, authIn, authInSz);
-    } else {
-        authPadSz = authInSz;
-        authInPadded = (byte*)authIn;
-    }
-
-#ifdef WOLFSSL_STM32_CUBEMX
-    XMEMSET(&hcryp, 0, sizeof(CRYP_HandleTypeDef));
-    switch(keySize) {
-        case 16: /* 128-bit key */
-            hcryp.Init.KeySize = CRYP_KEYSIZE_128B;
-            break;
-        case 24: /* 192-bit key */
-            hcryp.Init.KeySize = CRYP_KEYSIZE_192B;
-            break;
-        case 32: /* 256-bit key */
-            hcryp.Init.KeySize = CRYP_KEYSIZE_256B;
-            break;
-        default:
-            break;
-    }
-    hcryp.Instance = CRYP;
-    hcryp.Init.DataType = CRYP_DATATYPE_8B;
-    hcryp.Init.pKey = (byte*)aes->key;
-    hcryp.Init.pInitVect = initialCounter;
-    hcryp.Init.Header = authInPadded;
-    hcryp.Init.HeaderSize = authInSz;
-
-    HAL_CRYP_Init(&hcryp);
-    /* Use inPadded for output buffer instead of
-    * out so that we don't overflow our size. */
-    status = HAL_CRYPEx_AESGCM_Decrypt(&hcryp, (byte*)inPadded,
-                                    sz, inPadded, STM32_HAL_TIMEOUT);
-    /* Compute the authTag */
-    if (status == HAL_OK)
-        status = HAL_CRYPEx_AESGCM_Finish(&hcryp, sz, tag, STM32_HAL_TIMEOUT);
-
-    if (status != HAL_OK)
-        ret = AES_GCM_AUTH_E;
-
-    HAL_CRYP_DeInit(&hcryp);
-#else
-    ByteReverseWords((word32*)keyCopy, (word32*)aes->key, keySize);
-
-    /* Input size and auth size need to be the actual sizes, even though
-     * they are not block aligned, because this length (in bits) is used
-     * in the final GHASH. Use inPadded for output buffer instead of
-     * out so that we don't overflow our size.                         */
-    status = CRYP_AES_GCM(MODE_DECRYPT, (uint8_t*)initialCounter,
-                         (uint8_t*)keyCopy,     keySize * 8,
-                         (uint8_t*)inPadded,    sz,
-                         (uint8_t*)authInPadded,authInSz,
-                         (uint8_t*)inPadded,    tag);
-    if (status != SUCCESS)
-        ret = AES_GCM_AUTH_E;
-#endif /* WOLFSSL_STM32_CUBEMX */
-
-    if (ret == 0 && ConstantCompare(authTag, tag, authTagSz) == 0) {
-        /* Only keep the decrypted data if authTag success. */
-        XMEMCPY(out, inPadded, sz);
-        ret = 0; /* success */
-    }
-
-    /* only allocate padding buffers if the inputs are not a multiple of block sz */
-    if (inPadded != NULL && inPadSz != sz)
-        XFREE(inPadded , aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
-    if (authInPadded != NULL && authPadSz != authInSz)
-        XFREE(authInPadded, aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
-
-#else
-
-    /* software AES GCM */
+#ifdef WOLF_CRYPTO_DEV
+    if (aes->devId != INVALID_DEVID) {
+        int ret = wc_CryptoDev_AesGcmDecrypt(aes, out, in, sz, iv, ivSz,
+            authTag, authTagSz, authIn, authInSz);
+        if (ret != NOT_COMPILED_IN)
+            return ret;
+    }
+#endif
+
+#if defined(STM32_CRYPTO) && (defined(WOLFSSL_STM32F4) || \
+                              defined(WOLFSSL_STM32F7) || \
+                              defined(WOLFSSL_STM32L4))
+
+    /* STM32 HW only supports 12 byte IV and 16 byte auth */
+    if (ivSz == GCM_NONCE_MID_SZ && authInSz == AES_BLOCK_SIZE) {
+        return wc_AesGcmDecrypt_STM32(aes, out, in, sz, iv, ivSz,
+                                      authTag, authTagSz, authIn, authInSz);
+    }
+#endif
 
 #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_AES)
     /* if async and byte count above threshold */
+    /* only 12-byte IV is supported in HW */
     if (aes->asyncDev.marker == WOLFSSL_ASYNC_MARKER_AES &&
-                                                sz >= WC_ASYNC_THRESH_AES_GCM) {
+                    sz >= WC_ASYNC_THRESH_AES_GCM && ivSz == GCM_NONCE_MID_SZ) {
     #if defined(HAVE_CAVIUM)
-        /* Not yet supported, contact wolfSSL if interested in using */
+        #ifdef HAVE_CAVIUM_V
+        if (authInSz == 20) { /* Nitrox V GCM is only working with 20 byte AAD */
+            return NitroxAesGcmDecrypt(aes, out, in, sz,
+                (const byte*)aes->asyncKey, aes->keylen, iv, ivSz,
+                authTag, authTagSz, authIn, authInSz);
+        }
+        #endif
     #elif defined(HAVE_INTEL_QA)
         return IntelQaSymAesGcmDecrypt(&aes->asyncDev, out, in, sz,
@@ -7055,79 +8893,214 @@
 
 #ifdef WOLFSSL_AESNI
-    if (haveAESNI) {
     #ifdef HAVE_INTEL_AVX2
         if (IS_INTEL_AVX2(intel_flags)) {
-            if (AES_GCM_decrypt_avx2(in, out, authIn, iv, authTag, sz, authInSz,
-                                       ivSz, (byte*)aes->key, aes->rounds) == 0)
+        AES_GCM_decrypt_avx2(in, out, authIn, iv, authTag, sz, authInSz, ivSz,
+                                 authTagSz, (byte*)aes->key, aes->rounds, &res);
+        if (res == 0)
             return AES_GCM_AUTH_E;
+        return 0;
+    }
+    else
+    #endif
+    #ifdef HAVE_INTEL_AVX1
+    if (IS_INTEL_AVX1(intel_flags)) {
+        AES_GCM_decrypt_avx1(in, out, authIn, iv, authTag, sz, authInSz, ivSz,
+                                 authTagSz, (byte*)aes->key, aes->rounds, &res);
+        if (res == 0)
+            return AES_GCM_AUTH_E;
+        return 0;
         }
         else
     #endif
-        if (AES_GCM_decrypt(in, out, authIn, iv, authTag, sz, authInSz, ivSz,
-                                             (byte*)aes->key, aes->rounds) == 0)
+    if (haveAESNI) {
+        AES_GCM_decrypt(in, out, authIn, iv, authTag, sz, authInSz, ivSz,
+                                 authTagSz, (byte*)aes->key, aes->rounds, &res);
+        if (res == 0)
             return AES_GCM_AUTH_E;
         return 0;
     }
+    else
 #endif
-
-    ctr = counter;
-    XMEMSET(initialCounter, 0, AES_BLOCK_SIZE);
-    if (ivSz == NONCE_SZ) {
-        XMEMCPY(initialCounter, iv, ivSz);
-        initialCounter[AES_BLOCK_SIZE - 1] = 1;
-    }
-    else {
-        GHASH(aes, NULL, 0, iv, ivSz, initialCounter, AES_BLOCK_SIZE);
-    }
-    XMEMCPY(ctr, initialCounter, AES_BLOCK_SIZE);
-
-    /* Calc the authTag again using the received auth data and the cipher text */
-    GHASH(aes, authIn, authInSz, in, sz, Tprime, sizeof(Tprime));
-    wc_AesEncrypt(aes, ctr, EKY0);
-    xorbuf(Tprime, EKY0, sizeof(Tprime));
-
-    if (ConstantCompare(authTag, Tprime, authTagSz) != 0) {
-        return AES_GCM_AUTH_E;
-    }
-
-#ifdef WOLFSSL_PIC32MZ_CRYPT
-    if (blocks) {
-        /* use intitial IV for PIC32 HW, but don't use it below */
-        XMEMCPY(aes->reg, ctr, AES_BLOCK_SIZE);
-
-        ret = wc_Pic32AesCrypt(
-            aes->key, aes->keylen, aes->reg, AES_BLOCK_SIZE,
-            out, in, (blocks * AES_BLOCK_SIZE),
-            PIC32_DECRYPTION, PIC32_ALGO_AES, PIC32_CRYPTOALGO_AES_GCM);
-        if (ret != 0)
-            return ret;
-    }
-    /* process remainder using partial handling */
+    {
+        return AES_GCM_decrypt_C(aes, out, in, sz, iv, ivSz, authTag, authTagSz,
+                                                              authIn, authInSz);
+    }
+}
 #endif
-
-    while (blocks--) {
-        IncrementGcmCounter(ctr);
-    #ifndef WOLFSSL_PIC32MZ_CRYPT
-        wc_AesEncrypt(aes, ctr, scratch);
-        xorbuf(scratch, c, AES_BLOCK_SIZE);
-        XMEMCPY(p, scratch, AES_BLOCK_SIZE);
-    #endif
-        p += AES_BLOCK_SIZE;
-        c += AES_BLOCK_SIZE;
-    }
-    if (partial != 0) {
-        IncrementGcmCounter(ctr);
-        wc_AesEncrypt(aes, ctr, scratch);
-        xorbuf(scratch, c, partial);
-        XMEMCPY(p, scratch, partial);
-    }
-
-#endif
+#endif /* HAVE_AES_DECRYPT || HAVE_AESGCM_DECRYPT */
+#endif /* WOLFSSL_XILINX_CRYPT */
+#endif /* end of block for AESGCM implementation selection */
+
+
+/* Common to all, abstract functions that build off of lower level AESGCM
+ * functions */
+#ifndef WC_NO_RNG
+
+int wc_AesGcmSetExtIV(Aes* aes, const byte* iv, word32 ivSz)
+{
+    int ret = 0;
+
+    if (aes == NULL || iv == NULL ||
+        (ivSz != GCM_NONCE_MIN_SZ && ivSz != GCM_NONCE_MID_SZ &&
+         ivSz != GCM_NONCE_MAX_SZ)) {
+
+        ret = BAD_FUNC_ARG;
+    }
+
+    if (ret == 0) {
+        XMEMCPY((byte*)aes->reg, iv, ivSz);
+
+        /* If the IV is 96, allow for a 2^64 invocation counter.
+         * For any other size for the nonce, limit the invocation
+         * counter to 32-bits. (SP 800-38D 8.3) */
+        aes->invokeCtr[0] = 0;
+        aes->invokeCtr[1] = (ivSz == GCM_NONCE_MID_SZ) ? 0 : 0xFFFFFFFF;
+        aes->nonceSz = ivSz;
+    }
 
     return ret;
 }
 
-#endif /* HAVE_AES_DECRYPT || HAVE_AESGCM_DECRYPT */
-#endif /* (WOLFSSL_XILINX_CRYPT) */
+
+int wc_AesGcmSetIV(Aes* aes, word32 ivSz,
+                   const byte* ivFixed, word32 ivFixedSz,
+                   WC_RNG* rng)
+{
+    int ret = 0;
+
+    if (aes == NULL || rng == NULL ||
+        (ivSz != GCM_NONCE_MIN_SZ && ivSz != GCM_NONCE_MID_SZ &&
+         ivSz != GCM_NONCE_MAX_SZ) ||
+        (ivFixed == NULL && ivFixedSz != 0) ||
+        (ivFixed != NULL && ivFixedSz != AES_IV_FIXED_SZ)) {
+
+        ret = BAD_FUNC_ARG;
+    }
+
+    if (ret == 0) {
+        byte* iv = (byte*)aes->reg;
+
+        if (ivFixedSz)
+            XMEMCPY(iv, ivFixed, ivFixedSz);
+
+        ret = wc_RNG_GenerateBlock(rng, iv + ivFixedSz, ivSz - ivFixedSz);
+    }
+
+    if (ret == 0) {
+        /* If the IV is 96, allow for a 2^64 invocation counter.
+         * For any other size for the nonce, limit the invocation
+         * counter to 32-bits. (SP 800-38D 8.3) */
+        aes->invokeCtr[0] = 0;
+        aes->invokeCtr[1] = (ivSz == GCM_NONCE_MID_SZ) ? 0 : 0xFFFFFFFF;
+        aes->nonceSz = ivSz;
+    }
+
+            return ret;
+    }
+
+
+int wc_AesGcmEncrypt_ex(Aes* aes, byte* out, const byte* in, word32 sz,
+                        byte* ivOut, word32 ivOutSz,
+                        byte* authTag, word32 authTagSz,
+                        const byte* authIn, word32 authInSz)
+{
+    int ret = 0;
+
+    if (aes == NULL || (sz != 0 && (in == NULL || out == NULL)) ||
+        ivOut == NULL || ivOutSz != aes->nonceSz ||
+        (authIn == NULL && authInSz != 0)) {
+
+        ret = BAD_FUNC_ARG;
+    }
+
+    if (ret == 0) {
+        aes->invokeCtr[0]++;
+        if (aes->invokeCtr[0] == 0) {
+            aes->invokeCtr[1]++;
+            if (aes->invokeCtr[1] == 0)
+                ret = AES_GCM_OVERFLOW_E;
+        }
+    }
+
+    if (ret == 0) {
+        XMEMCPY(ivOut, aes->reg, ivOutSz);
+        ret = wc_AesGcmEncrypt(aes, out, in, sz,
+                               (byte*)aes->reg, ivOutSz,
+                               authTag, authTagSz,
+                               authIn, authInSz);
+        IncCtr((byte*)aes->reg, ivOutSz);
+    }
+
+    return ret;
+}
+
+int wc_Gmac(const byte* key, word32 keySz, byte* iv, word32 ivSz,
+            const byte* authIn, word32 authInSz,
+            byte* authTag, word32 authTagSz, WC_RNG* rng)
+{
+    Aes aes;
+    int ret;
+
+    if (key == NULL || iv == NULL || (authIn == NULL && authInSz != 0) ||
+        authTag == NULL || authTagSz == 0 || rng == NULL) {
+
+        return BAD_FUNC_ARG;
+    }
+
+    ret = wc_AesInit(&aes, NULL, INVALID_DEVID);
+    if (ret == 0) {
+        ret = wc_AesGcmSetKey(&aes, key, keySz);
+        if (ret == 0)
+            ret = wc_AesGcmSetIV(&aes, ivSz, NULL, 0, rng);
+        if (ret == 0)
+            ret = wc_AesGcmEncrypt_ex(&aes, NULL, NULL, 0, iv, ivSz,
+                                  authTag, authTagSz, authIn, authInSz);
+        wc_AesFree(&aes);
+    }
+    ForceZero(&aes, sizeof(aes));
+
+    return ret;
+}
+
+int wc_GmacVerify(const byte* key, word32 keySz,
+                  const byte* iv, word32 ivSz,
+                  const byte* authIn, word32 authInSz,
+                  const byte* authTag, word32 authTagSz)
+{
+    int ret;
+#ifndef NO_AES_DECRYPT
+    Aes aes;
+
+    if (key == NULL || iv == NULL || (authIn == NULL && authInSz != 0) ||
+        authTag == NULL || authTagSz == 0 || authTagSz > AES_BLOCK_SIZE) {
+
+        return BAD_FUNC_ARG;
+    }
+
+    ret = wc_AesInit(&aes, NULL, INVALID_DEVID);
+    if (ret == 0) {
+        ret = wc_AesGcmSetKey(&aes, key, keySz);
+        if (ret == 0)
+            ret = wc_AesGcmDecrypt(&aes, NULL, NULL, 0, iv, ivSz,
+                                  authTag, authTagSz, authIn, authInSz);
+        wc_AesFree(&aes);
+    }
+    ForceZero(&aes, sizeof(aes));
+#else
+    (void)key;
+    (void)keySz;
+    (void)iv;
+    (void)ivSz;
+    (void)authIn;
+    (void)authInSz;
+    (void)authTag;
+    (void)authTagSz;
+    ret = NOT_COMPILED_IN;
+#endif
+    return ret;
+}
+
+#endif /* WC_NO_RNG */
+
 
 WOLFSSL_API int wc_GmacSetKey(Gmac* gmac, const byte* key, word32 len)
@@ -7155,9 +9128,18 @@
 int wc_AesCcmSetKey(Aes* aes, const byte* key, word32 keySz)
 {
+    if (!((keySz == 16) || (keySz == 24) || (keySz == 32)))
+        return BAD_FUNC_ARG;
+
     return wc_AesSetKey(aes, key, keySz, NULL, AES_ENCRYPTION);
 }
 
-#if defined(HAVE_COLDFIRE_SEC)
+#ifdef WOLFSSL_ARMASM
+    /* implementation located in wolfcrypt/src/port/arm/armv8-aes.c */
+
+#elif defined(HAVE_COLDFIRE_SEC)
     #error "Coldfire SEC doesn't currently support AES-CCM mode"
+
+#elif defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_AES)
+    /* implemented in wolfcrypt/src/port/caam_aes.c */
 
 #elif defined(FREESCALE_LTC)
@@ -7226,8 +9208,7 @@
 #endif /* HAVE_AES_DECRYPT */
 
-
-/* software AES CCM */
 #else
 
+/* Software CCM */
 static void roll_x(Aes* aes, const byte* in, word32 inSz, byte* out)
 {
@@ -7293,5 +9274,5 @@
 
 
-static INLINE void AesCcmCtrInc(byte* B, word32 lenSz)
+static WC_INLINE void AesCcmCtrInc(byte* B, word32 lenSz)
 {
     word32 i;
@@ -7302,4 +9283,5 @@
 }
 
+/* Software AES - CCM Encrypt */
 /* return 0 on success */
 int wc_AesCcmEncrypt(Aes* aes, byte* out, const byte* in, word32 inSz,
@@ -7317,5 +9299,6 @@
     /* sanity check on arguments */
     if (aes == NULL || out == NULL || in == NULL || nonce == NULL
-            || authTag == NULL || nonceSz < 7 || nonceSz > 13)
+            || authTag == NULL || nonceSz < 7 || nonceSz > 13 ||
+            authTagSz > AES_BLOCK_SIZE)
         return BAD_FUNC_ARG;
 
@@ -7369,4 +9352,5 @@
 
 #ifdef HAVE_AES_DECRYPT
+/* Software AES - CCM Decrypt */
 int  wc_AesCcmDecrypt(Aes* aes, byte* out, const byte* in, word32 inSz,
                    const byte* nonce, word32 nonceSz,
@@ -7385,5 +9369,6 @@
     /* sanity check on arguments */
     if (aes == NULL || out == NULL || in == NULL || nonce == NULL
-            || authTag == NULL || nonceSz < 7 || nonceSz > 13)
+            || authTag == NULL || nonceSz < 7 || nonceSz > 13 ||
+            authTagSz > AES_BLOCK_SIZE)
         return BAD_FUNC_ARG;
 
@@ -7457,6 +9442,72 @@
     return result;
 }
+
 #endif /* HAVE_AES_DECRYPT */
-#endif /* software AES CCM */
+#endif /* software CCM */
+
+/* abstract functions that call lower level AESCCM functions */
+#ifndef WC_NO_RNG
+
+int wc_AesCcmSetNonce(Aes* aes, const byte* nonce, word32 nonceSz)
+{
+    int ret = 0;
+
+    if (aes == NULL || nonce == NULL ||
+        nonceSz < CCM_NONCE_MIN_SZ || nonceSz > CCM_NONCE_MAX_SZ) {
+
+        ret = BAD_FUNC_ARG;
+    }
+
+    if (ret == 0) {
+        XMEMCPY(aes->reg, nonce, nonceSz);
+        aes->nonceSz = nonceSz;
+
+        /* Invocation counter should be 2^61 */
+        aes->invokeCtr[0] = 0;
+        aes->invokeCtr[1] = 0xE0000000;
+    }
+
+    return ret;
+}
+
+
+int wc_AesCcmEncrypt_ex(Aes* aes, byte* out, const byte* in, word32 sz,
+                        byte* ivOut, word32 ivOutSz,
+                        byte* authTag, word32 authTagSz,
+                        const byte* authIn, word32 authInSz)
+{
+    int ret = 0;
+
+    if (aes == NULL || out == NULL ||
+        (in == NULL && sz != 0) ||
+        ivOut == NULL ||
+        (authIn == NULL && authInSz != 0) ||
+        (ivOutSz != aes->nonceSz)) {
+
+        ret = BAD_FUNC_ARG;
+    }
+
+    if (ret == 0) {
+        aes->invokeCtr[0]++;
+        if (aes->invokeCtr[0] == 0) {
+            aes->invokeCtr[1]++;
+            if (aes->invokeCtr[1] == 0)
+                ret = AES_CCM_OVERFLOW_E;
+        }
+    }
+
+    if (ret == 0) {
+        ret = wc_AesCcmEncrypt(aes, out, in, sz,
+                               (byte*)aes->reg, aes->nonceSz,
+                               authTag, authTagSz,
+                               authIn, authInSz);
+        XMEMCPY(ivOut, aes->reg, aes->nonceSz);
+        IncCtr((byte*)aes->reg, aes->nonceSz);
+    }
+
+    return ret;
+}
+
+#endif /* WC_NO_RNG */
 
 #endif /* HAVE_AESCCM */
@@ -7473,13 +9524,46 @@
     aes->heap = heap;
 
+#ifdef WOLF_CRYPTO_DEV
+    aes->devId = devId;
+#else
+    (void)devId;
+#endif
 #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_AES)
     ret = wolfAsync_DevCtxInit(&aes->asyncDev, WOLFSSL_ASYNC_MARKER_AES,
                                                         aes->heap, devId);
-#else
-    (void)devId;
 #endif /* WOLFSSL_ASYNC_CRYPT */
+
+#ifdef WOLFSSL_AFALG
+    aes->alFd = -1;
+    aes->rdFd = -1;
+#endif
+#if defined(WOLFSSL_DEVCRYPTO) && \
+   (defined(WOLFSSL_DEVCRYPTO_AES) || defined(WOLFSSL_DEVCRYPTO_CBC))
+    aes->ctx.cfd = -1;
+#endif
 
     return ret;
 }
+
+#ifdef HAVE_PKCS11
+int  wc_AesInit_Id(Aes* aes, unsigned char* id, int len, void* heap, int devId)
+{
+    int ret = 0;
+
+    if (aes == NULL)
+        ret = BAD_FUNC_ARG;
+    if (ret == 0 && (len < 0 || len > AES_MAX_ID_LEN))
+        ret = BUFFER_E;
+
+    if (ret == 0)
+        ret  = wc_AesInit(aes, heap, devId);
+    if (ret == 0) {
+        XMEMCPY(aes->id, id, len);
+        aes->idLen = len;
+    }
+
+    return ret;
+}
+#endif
 
 /* Free Aes from use with async hardware */
@@ -7492,4 +9576,17 @@
     wolfAsync_DevCtxFree(&aes->asyncDev, WOLFSSL_ASYNC_MARKER_AES);
 #endif /* WOLFSSL_ASYNC_CRYPT */
+#ifdef WOLFSSL_AFALG
+    if (aes->rdFd > 0) { /* negative is error case */
+        close(aes->rdFd);
+    }
+    if (aes->alFd > 0) {
+        close(aes->alFd);
+    }
+#endif /* WOLFSSL_AFALG */
+#if defined(WOLFSSL_DEVCRYPTO) && \
+    (defined(WOLFSSL_DEVCRYPTO_AES) || defined(WOLFSSL_DEVCRYPTO_CBC))
+    wc_DevCryptoFree(&aes->ctx);
+    ForceZero((byte*)aes->devKey, AES_MAX_KEY_SIZE/WOLFSSL_BIT_SIZE);
+#endif
 }
 
@@ -7504,13 +9601,19 @@
 
     switch (aes->rounds) {
+#ifdef WOLFSSL_AES_128
     case 10:
         *keySize = 16;
         break;
+#endif
+#ifdef WOLFSSL_AES_192
     case 12:
         *keySize = 24;
         break;
+#endif
+#ifdef WOLFSSL_AES_256
     case 14:
         *keySize = 32;
         break;
+#endif
     default:
         *keySize = 0;
@@ -7521,12 +9624,185 @@
 }
 
-#endif /* !WOLFSSL_ARMASM */
 #endif /* !WOLFSSL_TI_CRYPT */
 
+#ifdef HAVE_AES_ECB
+#if defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_AES)
+    /* implemented in wolfcrypt/src/port/caam/caam_aes.c */
+
+#elif defined(WOLFSSL_AFALG)
+    /* implemented in wolfcrypt/src/port/af_alg/afalg_aes.c */
+
+#elif defined(WOLFSSL_DEVCRYPTO_AES)
+    /* implemented in wolfcrypt/src/port/devcrypt/devcrypto_aes.c */
+
+#else
+
+/* Software AES - ECB */
+int wc_AesEcbEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+{
+    word32 blocks = sz / AES_BLOCK_SIZE;
+
+    if ((in == NULL) || (out == NULL) || (aes == NULL))
+      return BAD_FUNC_ARG;
+    while (blocks>0) {
+      wc_AesEncryptDirect(aes, out, in);
+      out += AES_BLOCK_SIZE;
+      in  += AES_BLOCK_SIZE;
+      sz  -= AES_BLOCK_SIZE;
+      blocks--;
+    }
+    return 0;
+}
+
+
+int wc_AesEcbDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+{
+    word32 blocks = sz / AES_BLOCK_SIZE;
+
+    if ((in == NULL) || (out == NULL) || (aes == NULL))
+      return BAD_FUNC_ARG;
+    while (blocks>0) {
+      wc_AesDecryptDirect(aes, out, in);
+      out += AES_BLOCK_SIZE;
+      in  += AES_BLOCK_SIZE;
+      sz  -= AES_BLOCK_SIZE;
+      blocks--;
+    }
+    return 0;
+}
+#endif
+#endif /* HAVE_AES_ECB */
+
+#ifdef WOLFSSL_AES_CFB
+/* CFB 128
+ *
+ * aes structure holding key to use for encryption
+ * out buffer to hold result of encryption (must be at least as large as input
+ *     buffer)
+ * in  buffer to encrypt
+ * sz  size of input buffer
+ *
+ * returns 0 on success and negative error values on failure
+ */
+/* Software AES - CFB Encrypt */
+int wc_AesCfbEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+{
+    byte*  tmp = NULL;
+    byte*  reg = NULL;
+
+    WOLFSSL_ENTER("wc_AesCfbEncrypt");
+
+    if (aes == NULL || out == NULL || in == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    if (aes->left && sz) {
+        reg = (byte*)aes->reg + AES_BLOCK_SIZE - aes->left;
+    }
+
+    /* consume any unused bytes left in aes->tmp */
+    tmp = (byte*)aes->tmp + AES_BLOCK_SIZE - aes->left;
+    while (aes->left && sz) {
+        *(out++) = *(reg++) = *(in++) ^ *(tmp++);
+        aes->left--;
+        sz--;
+    }
+
+    while (sz >= AES_BLOCK_SIZE) {
+        wc_AesEncryptDirect(aes, out, (byte*)aes->reg);
+        xorbuf(out, in, AES_BLOCK_SIZE);
+        XMEMCPY(aes->reg, out, AES_BLOCK_SIZE);
+        out += AES_BLOCK_SIZE;
+        in  += AES_BLOCK_SIZE;
+        sz  -= AES_BLOCK_SIZE;
+        aes->left = 0;
+    }
+
+    /* encrypt left over data */
+    if (sz) {
+        wc_AesEncryptDirect(aes, (byte*)aes->tmp, (byte*)aes->reg);
+        aes->left = AES_BLOCK_SIZE;
+        tmp = (byte*)aes->tmp;
+        reg = (byte*)aes->reg;
+
+        while (sz--) {
+            *(out++) = *(reg++) = *(in++) ^ *(tmp++);
+            aes->left--;
+        }
+    }
+
+    return 0;
+}
+
+
+#ifdef HAVE_AES_DECRYPT
+/* CFB 128
+ *
+ * aes structure holding key to use for decryption
+ * out buffer to hold result of decryption (must be at least as large as input
+ *     buffer)
+ * in  buffer to decrypt
+ * sz  size of input buffer
+ *
+ * returns 0 on success and negative error values on failure
+ */
+/* Software AES - CFB Decrypt */
+int wc_AesCfbDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+{
+    byte*  tmp;
+
+    WOLFSSL_ENTER("wc_AesCfbDecrypt");
+
+    if (aes == NULL || out == NULL || in == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    /* check if more input needs copied over to aes->reg */
+    if (aes->left && sz) {
+        int size = min(aes->left, sz);
+        XMEMCPY((byte*)aes->reg + AES_BLOCK_SIZE - aes->left, in, size);
+    }
+
+    /* consume any unused bytes left in aes->tmp */
+    tmp = (byte*)aes->tmp + AES_BLOCK_SIZE - aes->left;
+    while (aes->left && sz) {
+        *(out++) = *(in++) ^ *(tmp++);
+        aes->left--;
+        sz--;
+    }
+
+    while (sz > AES_BLOCK_SIZE) {
+        wc_AesEncryptDirect(aes, out, (byte*)aes->reg);
+        xorbuf(out, in, AES_BLOCK_SIZE);
+        XMEMCPY(aes->reg, in, AES_BLOCK_SIZE);
+        out += AES_BLOCK_SIZE;
+        in  += AES_BLOCK_SIZE;
+        sz  -= AES_BLOCK_SIZE;
+        aes->left = 0;
+    }
+
+    /* decrypt left over data */
+    if (sz) {
+        wc_AesEncryptDirect(aes, (byte*)aes->tmp, (byte*)aes->reg);
+        XMEMCPY(aes->reg, in, sz);
+        aes->left = AES_BLOCK_SIZE;
+        tmp = (byte*)aes->tmp;
+
+        while (sz--) {
+            *(out++) = *(in++) ^ *(tmp++);
+            aes->left--;
+        }
+    }
+
+    return 0;
+}
+#endif /* HAVE_AES_DECRYPT */
+#endif /* WOLFSSL_AES_CFB */
+
 
 #ifdef HAVE_AES_KEYWRAP
 
 /* Initialize key wrap counter with value */
-static INLINE void InitKeyWrapCounter(byte* inOutCtr, word32 value)
+static WC_INLINE void InitKeyWrapCounter(byte* inOutCtr, word32 value)
 {
     int i;
@@ -7541,5 +9817,5 @@
 
 /* Increment key wrap counter */
-static INLINE void IncrementKeyWrapCounter(byte* inOutCtr)
+static WC_INLINE void IncrementKeyWrapCounter(byte* inOutCtr)
 {
     int i;
@@ -7553,5 +9829,5 @@
 
 /* Decrement key wrap counter */
-static INLINE void DecrementKeyWrapCounter(byte* inOutCtr)
+static WC_INLINE void DecrementKeyWrapCounter(byte* inOutCtr)
 {
     int i;
@@ -7836,4 +10112,43 @@
 }
 
+#ifdef HAVE_AES_ECB
+/* helper function for encrypting / decrypting full buffer at once */
+static int _AesXtsHelper(Aes* aes, byte* out, const byte* in, word32 sz, int dir)
+{
+    word32 outSz   = sz;
+    word32 totalSz = (sz / AES_BLOCK_SIZE) * AES_BLOCK_SIZE; /* total bytes */
+    byte*  pt      = out;
+
+    outSz -= AES_BLOCK_SIZE;
+
+    while (outSz > 0) {
+        word32 j;
+        byte carry = 0;
+
+        /* multiply by shift left and propagate carry */
+        for (j = 0; j < AES_BLOCK_SIZE && outSz > 0; j++, outSz--) {
+            byte tmpC;
+
+            tmpC   = (pt[j] >> 7) & 0x01;
+            pt[j+AES_BLOCK_SIZE] = ((pt[j] << 1) + carry) & 0xFF;
+            carry  = tmpC;
+        }
+        if (carry) {
+            pt[AES_BLOCK_SIZE] ^= GF_XTS;
+        }
+
+        pt += AES_BLOCK_SIZE;
+    }
+
+    xorbuf(out, in, totalSz);
+    if (dir == AES_ENCRYPTION) {
+        return wc_AesEcbEncrypt(aes, out, out, totalSz);
+    }
+    else {
+        return wc_AesEcbDecrypt(aes, out, out, totalSz);
+    }
+}
+#endif /* HAVE_AES_ECB */
+
 
 /* AES with XTS mode. (XTS) XEX encryption with Tweak and cipher text Stealing.
@@ -7849,4 +10164,5 @@
  * returns 0 on success
  */
+/* Software AES - XTS Encrypt  */
 int wc_AesXtsEncrypt(XtsAes* xaes, byte* out, const byte* in, word32 sz,
         const byte* i, word32 iSz)
@@ -7856,5 +10172,5 @@
     Aes *aes, *tweak;
 
-    if (xaes == NULL || out == NULL) {
+    if (xaes == NULL || out == NULL || in == NULL) {
         return BAD_FUNC_ARG;
     }
@@ -7867,12 +10183,21 @@
     }
 
-    if (in == NULL && sz > 0) {
-        return BAD_FUNC_ARG;
-    }
-
     if (blocks > 0) {
         byte tmp[AES_BLOCK_SIZE];
 
+        XMEMSET(tmp, 0, AES_BLOCK_SIZE); /* set to 0's in case of improper AES
+                                          * key setup passed to encrypt direct*/
+
         wc_AesEncryptDirect(tweak, tmp, i);
+
+    #ifdef HAVE_AES_ECB
+        /* encrypt all of buffer at once when possible */
+        if (in != out) { /* can not handle inline */
+            XMEMCPY(out, tmp, AES_BLOCK_SIZE);
+            if ((ret = _AesXtsHelper(aes, out, in, sz, AES_ENCRYPTION)) != 0) {
+                return ret;
+            }
+        }
+    #endif
 
         while (blocks > 0) {
@@ -7881,10 +10206,16 @@
             byte buf[AES_BLOCK_SIZE];
 
+    #ifdef HAVE_AES_ECB
+            if (in == out) { /* check for if inline */
+    #endif
             XMEMCPY(buf, in, AES_BLOCK_SIZE);
             xorbuf(buf, tmp, AES_BLOCK_SIZE);
             wc_AesEncryptDirect(aes, out, buf);
+    #ifdef HAVE_AES_ECB
+            }
+    #endif
             xorbuf(out, tmp, AES_BLOCK_SIZE);
 
-            /* multiply by shift left and propogate carry */
+            /* multiply by shift left and propagate carry */
             for (j = 0; j < AES_BLOCK_SIZE; j++) {
                 byte tmpC;
@@ -7897,5 +10228,4 @@
                 tmp[0] ^= GF_XTS;
             }
-            carry = 0;
 
             in  += AES_BLOCK_SIZE;
@@ -7942,4 +10272,5 @@
  * returns 0 on success
  */
+/* Software AES - XTS Decrypt */
 int wc_AesXtsDecrypt(XtsAes* xaes, byte* out, const byte* in, word32 sz,
         const byte* i, word32 iSz)
@@ -7949,5 +10280,5 @@
     Aes *aes, *tweak;
 
-    if (xaes == NULL || out == NULL) {
+    if (xaes == NULL || out == NULL || in == NULL) {
         return BAD_FUNC_ARG;
     }
@@ -7957,8 +10288,4 @@
 
     if (iSz < AES_BLOCK_SIZE) {
-        return BAD_FUNC_ARG;
-    }
-
-    if (in == NULL && sz > 0) {
         return BAD_FUNC_ARG;
     }
@@ -7970,4 +10297,7 @@
         byte stl = (sz % AES_BLOCK_SIZE);
 
+        XMEMSET(tmp, 0, AES_BLOCK_SIZE); /* set to 0's in case of improper AES
+                                          * key setup passed to decrypt direct*/
+
         wc_AesEncryptDirect(tweak, tmp, i);
 
@@ -7978,13 +10308,29 @@
         }
 
+    #ifdef HAVE_AES_ECB
+        /* decrypt all of buffer at once when possible */
+        if (in != out) { /* can not handle inline */
+            XMEMCPY(out, tmp, AES_BLOCK_SIZE);
+            if ((ret = _AesXtsHelper(aes, out, in, sz, AES_DECRYPTION)) != 0) {
+                return ret;
+            }
+        }
+    #endif
+
         while (blocks > 0) {
             byte buf[AES_BLOCK_SIZE];
 
+    #ifdef HAVE_AES_ECB
+            if (in == out) { /* check for if inline */
+    #endif
             XMEMCPY(buf, in, AES_BLOCK_SIZE);
             xorbuf(buf, tmp, AES_BLOCK_SIZE);
             wc_AesDecryptDirect(aes, out, buf);
+    #ifdef HAVE_AES_ECB
+            }
+    #endif
             xorbuf(out, tmp, AES_BLOCK_SIZE);
 
-            /* multiply by shift left and propogate carry */
+            /* multiply by shift left and propagate carry */
             for (j = 0; j < AES_BLOCK_SIZE; j++) {
                 byte tmpC;
@@ -8010,5 +10356,5 @@
             byte tmp2[AES_BLOCK_SIZE];
 
-            /* multiply by shift left and propogate carry */
+            /* multiply by shift left and propagate carry */
             for (j = 0; j < AES_BLOCK_SIZE; j++) {
                 byte tmpC;
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/arc4.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/arc4.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/arc4.c	(revision 372)
@@ -71,5 +71,5 @@
 
 
-static INLINE byte MakeByte(word32* x, word32* y, byte* s)
+static WC_INLINE byte MakeByte(word32* x, word32* y, byte* s)
 {
     word32 a = s[*x], b;
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/asn.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/asn.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/asn.c	(revision 372)
@@ -35,4 +35,6 @@
  * RSA_DECODE_EXTRA: Decodes extra information in RSA public key.
  * WOLFSSL_CERT_GEN: Cert generation. Saves extra certificate info in GetName.
+ * WOLFSSL_NO_ASN_STRICT: Disable strict RFC compliance checks to
+    restore 3.13.0 behavior.
  * WOLFSSL_NO_OCSP_OPTIONAL_CERTS: Skip optional OCSP certs (responder issuer
     must still be trusted)
@@ -45,12 +47,10 @@
  * WOLFSSL_ALT_CERT_CHAINS: Allows matching multiple CA's to validate
     chain based on issuer and public key (includes signature confirmation)
+ * WOLFSSL_SMALL_CERT_VERIFY: Verify the certificate signature without using
+    DecodedCert. Doubles up on some code but allows smaller dynamic memory
+    usage.
 */
 
 #ifndef NO_ASN
-
-#ifdef HAVE_RTP_SYS
-    #include "os.h"           /* dc_rtc_api needs    */
-    #include "dc_rtc_api.h"   /* to get current time */
-#endif
 
 #include <wolfssl/wolfcrypt/asn.h>
@@ -61,4 +61,6 @@
 #include <wolfssl/wolfcrypt/pwdbased.h>
 #include <wolfssl/wolfcrypt/des3.h>
+#include <wolfssl/wolfcrypt/aes.h>
+#include <wolfssl/wolfcrypt/wc_encrypt.h>
 #include <wolfssl/wolfcrypt/logging.h>
 
@@ -72,4 +74,7 @@
 #endif
 
+#ifndef NO_PWDBASED
+    #include <wolfssl/wolfcrypt/aes.h>
+#endif
 #ifndef NO_RC4
     #include <wolfssl/wolfcrypt/arc4.h>
@@ -112,4 +117,5 @@
 #endif
 
+
 #ifdef _MSC_VER
     /* 4996 warning to use MS extensions e.g., strcpy_s instead of XSTRNCPY */
@@ -119,381 +125,25 @@
 #define ERROR_OUT(err, eLabel) { ret = (err); goto eLabel; }
 
-#ifndef NO_ASN_TIME
-#if defined(USER_TIME)
-    /* Use our gmtime and time_t/struct tm types.
-       Only needs seconds since EPOCH using XTIME function.
-       time_t XTIME(time_t * timer) {}
-    */
-    #define WOLFSSL_GMTIME
-    #define USE_WOLF_TM
-    #define USE_WOLF_TIME_T
-
-#elif defined(TIME_OVERRIDES)
-    /* Override XTIME() and XGMTIME() functionality.
-       Requires user to provide these functions:
-        time_t XTIME(time_t * timer) {}
-        struct tm* XGMTIME(const time_t* timer, struct tm* tmp) {}
-    */
-    #ifndef HAVE_TIME_T_TYPE
-        #define USE_WOLF_TIME_T
-    #endif
-    #ifndef HAVE_TM_TYPE
-        #define USE_WOLF_TM
-    #endif
-    #define NEED_TMP_TIME
-
-#elif defined(HAVE_RTP_SYS)
-    /* uses parital <time.h> structures */
-    #define XTIME(tl)       (0)
-    #define XGMTIME(c, t)   rtpsys_gmtime((c))
-
-#elif defined(MICRIUM)
-    #include <clk.h>
-    #include <time.h>
-    #define XTIME(t1)       micrium_time((t1))
-    #define WOLFSSL_GMTIME
-
-#elif defined(MICROCHIP_TCPIP_V5) || defined(MICROCHIP_TCPIP)
-    #include <time.h>
-    #define XTIME(t1)       pic32_time((t1))
-    #define XGMTIME(c, t)   gmtime((c))
-
-#elif defined(FREESCALE_MQX) || defined(FREESCALE_KSDK_MQX)
-    #define XTIME(t1)       mqx_time((t1))
-    #define HAVE_GMTIME_R
-
-#elif defined(FREESCALE_KSDK_BM) || defined(FREESCALE_FREE_RTOS) || \
-        defined(FREESCALE_KSDK_FREERTOS)
-    #include <time.h>
-    #ifndef XTIME
-        /*extern time_t ksdk_time(time_t* timer);*/
-        #define XTIME(t1)   ksdk_time((t1))
-    #endif
-    #define XGMTIME(c, t)   gmtime((c))
-
-#elif defined(WOLFSSL_ATMEL)
-    #define XTIME(t1)       atmel_get_curr_time_and_date((t1))
-    #define WOLFSSL_GMTIME
-    #define USE_WOLF_TM
-    #define USE_WOLF_TIME_T
-
-#elif defined(IDIRECT_DEV_TIME)
-    /*Gets the timestamp from cloak software owned by VT iDirect
-    in place of time() from <time.h> */
-    #include <time.h>
-    #define XTIME(t1)       idirect_time((t1))
-    #define XGMTIME(c, t)   gmtime((c))
-
-#elif defined(_WIN32_WCE)
-    #include <windows.h>
-    #define XTIME(t1)       windows_time((t1))
-    #define WOLFSSL_GMTIME
-#else
-
-    /* default */
-    /* uses complete <time.h> facility */
-    #include <time.h>
-#endif
-
-
-/* Map default time functions */
-#if !defined(XTIME) && !defined(TIME_OVERRIDES) && !defined(USER_TIME)
-    #define XTIME(tl)       time((tl))
-#endif
-#if !defined(XGMTIME) && !defined(TIME_OVERRIDES)
-    #if defined(WOLFSSL_GMTIME) || !defined(HAVE_GMTIME_R)
-        #define XGMTIME(c, t)   gmtime((c))
-    #else
-        #define XGMTIME(c, t)   gmtime_r((c), (t))
-        #define NEED_TMP_TIME
-    #endif
-#endif
-#if !defined(XVALIDATE_DATE) && !defined(HAVE_VALIDATE_DATE)
-    #define USE_WOLF_VALIDDATE
-    #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t))
-#endif
-
-/* wolf struct tm and time_t */
-#if defined(USE_WOLF_TM)
-    struct tm {
-        int  tm_sec;     /* seconds after the minute [0-60] */
-        int  tm_min;     /* minutes after the hour [0-59] */
-        int  tm_hour;    /* hours since midnight [0-23] */
-        int  tm_mday;    /* day of the month [1-31] */
-        int  tm_mon;     /* months since January [0-11] */
-        int  tm_year;    /* years since 1900 */
-        int  tm_wday;    /* days since Sunday [0-6] */
-        int  tm_yday;    /* days since January 1 [0-365] */
-        int  tm_isdst;   /* Daylight Savings Time flag */
-        long tm_gmtoff;  /* offset from CUT in seconds */
-        char *tm_zone;   /* timezone abbreviation */
+#ifdef HAVE_SELFTEST
+    #ifndef WOLFSSL_AES_KEY_SIZE_ENUM
+    enum Asn_Misc {
+        AES_IV_SIZE         = 16,
+        AES_128_KEY_SIZE    = 16,
+        AES_192_KEY_SIZE    = 24,
+        AES_256_KEY_SIZE    = 32
     };
-#endif /* USE_WOLF_TM */
-#if defined(USE_WOLF_TIME_T)
-    typedef long time_t;
-#endif
-
-/* forward declarations */
-#if defined(USER_TIME)
-    struct tm* gmtime(const time_t* timer);
-    extern time_t XTIME(time_t * timer);
-
-    #ifdef STACK_TRAP
-        /* for stack trap tracking, don't call os gmtime on OS X/linux,
-           uses a lot of stack spce */
-        extern time_t time(time_t * timer);
-        #define XTIME(tl)  time((tl))
-    #endif /* STACK_TRAP */
-
-#elif defined(TIME_OVERRIDES)
-    extern time_t XTIME(time_t * timer);
-    extern struct tm* XGMTIME(const time_t* timer, struct tm* tmp);
-#elif defined(WOLFSSL_GMTIME)
-    struct tm* gmtime(const time_t* timer);
-#endif
-
-
-#if defined(_WIN32_WCE)
-time_t windows_time(time_t* timer)
-{
-    SYSTEMTIME     sysTime;
-    FILETIME       fTime;
-    ULARGE_INTEGER intTime;
-    time_t         localTime;
-
-    if (timer == NULL)
-        timer = &localTime;
-
-    GetSystemTime(&sysTime);
-    SystemTimeToFileTime(&sysTime, &fTime);
-
-    XMEMCPY(&intTime, &fTime, sizeof(FILETIME));
-    /* subtract EPOCH */
-    intTime.QuadPart -= 0x19db1ded53e8000;
-    /* to secs */
-    intTime.QuadPart /= 10000000;
-    *timer = (time_t)intTime.QuadPart;
-
-    return *timer;
-}
-#endif /*  _WIN32_WCE */
-
-#if defined(WOLFSSL_GMTIME)
-struct tm* gmtime(const time_t* timer)
-{
-    #define YEAR0          1900
-    #define EPOCH_YEAR     1970
-    #define SECS_DAY       (24L * 60L * 60L)
-    #define LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) %400)))
-    #define YEARSIZE(year) (LEAPYEAR(year) ? 366 : 365)
-
-    static const int _ytab[2][12] =
-    {
-        {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
-        {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
-    };
-
-    static struct tm st_time;
-    struct tm* ret = &st_time;
-    time_t secs = *timer;
-    unsigned long dayclock, dayno;
-    int year = EPOCH_YEAR;
-
-    dayclock = (unsigned long)secs % SECS_DAY;
-    dayno    = (unsigned long)secs / SECS_DAY;
-
-    ret->tm_sec  = (int) dayclock % 60;
-    ret->tm_min  = (int)(dayclock % 3600) / 60;
-    ret->tm_hour = (int) dayclock / 3600;
-    ret->tm_wday = (int) (dayno + 4) % 7;        /* day 0 a Thursday */
-
-    while(dayno >= (unsigned long)YEARSIZE(year)) {
-        dayno -= YEARSIZE(year);
-        year++;
-    }
-
-    ret->tm_year = year - YEAR0;
-    ret->tm_yday = (int)dayno;
-    ret->tm_mon  = 0;
-
-    while(dayno >= (unsigned long)_ytab[LEAPYEAR(year)][ret->tm_mon]) {
-        dayno -= _ytab[LEAPYEAR(year)][ret->tm_mon];
-        ret->tm_mon++;
-    }
-
-    ret->tm_mday  = (int)++dayno;
-    ret->tm_isdst = 0;
-
-    return ret;
-}
-#endif /* WOLFSSL_GMTIME */
-
-
-#if defined(HAVE_RTP_SYS)
-#define YEAR0          1900
-
-struct tm* rtpsys_gmtime(const time_t* timer)       /* has a gmtime() but hangs */
-{
-    static struct tm st_time;
-    struct tm* ret = &st_time;
-
-    DC_RTC_CALENDAR cal;
-    dc_rtc_time_get(&cal, TRUE);
-
-    ret->tm_year  = cal.year - YEAR0;       /* gm starts at 1900 */
-    ret->tm_mon   = cal.month - 1;          /* gm starts at 0 */
-    ret->tm_mday  = cal.day;
-    ret->tm_hour  = cal.hour;
-    ret->tm_min   = cal.minute;
-    ret->tm_sec   = cal.second;
-
-    return ret;
-}
-
-#endif /* HAVE_RTP_SYS */
-
-
-#if defined(MICROCHIP_TCPIP_V5) || defined(MICROCHIP_TCPIP)
-
-/*
- * time() is just a stub in Microchip libraries. We need our own
- * implementation. Use SNTP client to get seconds since epoch.
- */
-time_t pic32_time(time_t* timer)
-{
-#ifdef MICROCHIP_TCPIP_V5
-    DWORD sec = 0;
-#else
-    uint32_t sec = 0;
-#endif
-    time_t localTime;
-
-    if (timer == NULL)
-        timer = &localTime;
-
-#ifdef MICROCHIP_MPLAB_HARMONY
-    sec = TCPIP_SNTP_UTCSecondsGet();
-#else
-    sec = SNTPGetUTCSeconds();
-#endif
-    *timer = (time_t) sec;
-
-    return *timer;
-}
-
-#endif /* MICROCHIP_TCPIP || MICROCHIP_TCPIP_V5 */
-
-
-#if defined(MICRIUM)
-
-time_t micrium_time(time_t* timer)
-{
-    CLK_TS_SEC sec;
-
-    Clk_GetTS_Unix(&sec);
-
-    return (time_t) sec;
-}
-
-#endif /* MICRIUM */
-
-
-#if defined(FREESCALE_MQX) || defined(FREESCALE_KSDK_MQX)
-
-time_t mqx_time(time_t* timer)
-{
-    time_t localTime;
-    TIME_STRUCT time_s;
-
-    if (timer == NULL)
-        timer = &localTime;
-
-    _time_get(&time_s);
-    *timer = (time_t) time_s.SECONDS;
-
-    return *timer;
-}
-
-#endif /* FREESCALE_MQX || FREESCALE_KSDK_MQX */
-
-
-#if defined(WOLFSSL_TIRTOS)
-
-time_t XTIME(time_t * timer)
-{
-    time_t sec = 0;
-
-    sec = (time_t) Seconds_get();
-
-    if (timer != NULL)
-        *timer = sec;
-
-    return sec;
-}
-
-#endif /* WOLFSSL_TIRTOS */
-
-
-#if defined(WOLFSSL_XILINX)
-#include "xrtcpsu.h"
-
-time_t XTIME(time_t * timer)
-{
-    time_t sec = 0;
-    XRtcPsu_Config* con;
-    XRtcPsu         rtc;
-
-    con = XRtcPsu_LookupConfig(XPAR_XRTCPSU_0_DEVICE_ID);
-    if (con != NULL) {
-        if (XRtcPsu_CfgInitialize(&rtc, con, con->BaseAddr) == XST_SUCCESS) {
-            sec = (time_t)XRtcPsu_GetCurrentTime(&rtc);
-        }
-        else {
-            WOLFSSL_MSG("Unable to initialize RTC");
-        }
-    }
-
-    if (timer != NULL)
-        *timer = sec;
-
-    return sec;
-}
-
-#endif /* WOLFSSL_TIRTOS */
-
-
-/* two byte date/time, add to value */
-static INLINE void GetTime(int* value, const byte* date, int* idx)
-{
-    int i = *idx;
-
-    *value += btoi(date[i++]) * 10;
-    *value += btoi(date[i++]);
-
-    *idx = i;
-}
-
-
-#if defined(IDIRECT_DEV_TIME)
-
-extern time_t getTimestamp();
-
-time_t idirect_time(time_t * timer)
-{
-    time_t sec = getTimestamp();
-
-    if (timer != NULL)
-        *timer = sec;
-
-    return sec;
-}
-
-#endif /* IDIRECT_DEV_TIME */
-
-#endif /* !NO_ASN_TIME */
-
+#endif
+#endif
 
 WOLFSSL_LOCAL int GetLength(const byte* input, word32* inOutIdx, int* len,
                            word32 maxIdx)
+{
+    return GetLength_ex(input, inOutIdx, len, maxIdx, 1);
+}
+
+
+/* give option to check length value found against index. 1 to check 0 to not */
+WOLFSSL_LOCAL int GetLength_ex(const byte* input, word32* inOutIdx, int* len,
+                           word32 maxIdx, int check)
 {
     int     length = 0;
@@ -525,5 +175,5 @@
         length = b;
 
-    if ((idx + length) > maxIdx) {   /* for user of length */
+    if (check && (idx + length) > maxIdx) {   /* for user of length */
         WOLFSSL_MSG("GetLength value exceeds buffer length");
         return BUFFER_E;
@@ -534,4 +184,27 @@
         *len = length;
 
+    return length;
+}
+
+
+static int GetASNHeader_ex(const byte* input, byte tag, word32* inOutIdx, int* len,
+                        word32 maxIdx, int check)
+{
+    word32 idx = *inOutIdx;
+    byte   b;
+    int    length;
+
+    if ((idx + 1) > maxIdx)
+        return BUFFER_E;
+
+    b = input[idx++];
+    if (b != tag)
+        return ASN_PARSE_E;
+
+    if (GetLength_ex(input, &idx, &length, maxIdx, check) < 0)
+        return ASN_PARSE_E;
+
+    *len      = length;
+    *inOutIdx = idx;
     return length;
 }
@@ -552,22 +225,7 @@
                         word32 maxIdx)
 {
-    word32 idx = *inOutIdx;
-    byte   b;
-    int    length;
-
-    if ((idx + 1) > maxIdx)
-        return BUFFER_E;
-
-    b = input[idx++];
-    if (b != tag)
-        return ASN_PARSE_E;
-
-    if (GetLength(input, &idx, &length, maxIdx) < 0)
-        return ASN_PARSE_E;
-
-    *len      = length;
-    *inOutIdx = idx;
-    return length;
-}
+    return GetASNHeader_ex(input, tag, inOutIdx, len, maxIdx, 1);
+}
+
 
 WOLFSSL_LOCAL int GetSequence(const byte* input, word32* inOutIdx, int* len,
@@ -576,4 +234,12 @@
     return GetASNHeader(input, ASN_SEQUENCE | ASN_CONSTRUCTED, inOutIdx, len,
                         maxIdx);
+}
+
+
+WOLFSSL_LOCAL int GetSequence_ex(const byte* input, word32* inOutIdx, int* len,
+                           word32 maxIdx, int check)
+{
+    return GetASNHeader_ex(input, ASN_SEQUENCE | ASN_CONSTRUCTED, inOutIdx, len,
+                        maxIdx, check);
 }
 
@@ -724,6 +390,4 @@
                 return ASN_PARSE_E;
         }
-        else if ((input[*inOutIdx] & 0x80) == 0x80)
-            return ASN_PARSE_E;
     }
 
@@ -759,8 +423,123 @@
 }
 
+
+#if !defined(NO_DSA) && !defined(NO_SHA)
+static char sigSha1wDsaName[] = "SHAwDSA";
+#endif /* NO_DSA */
+#ifndef NO_RSA
+#ifdef WOLFSSL_MD2
+    static char sigMd2wRsaName[] = "MD2wRSA";
+#endif
+#ifndef NO_MD5
+    static char sigMd5wRsaName[] = "MD5wRSA";
+#endif
+#ifndef NO_SHA
+    static char sigSha1wRsaName[] = "SHAwRSA";
+#endif
+#ifdef WOLFSSL_SHA224
+    static char sigSha224wRsaName[] = "SHA224wRSA";
+#endif
+#ifndef NO_SHA256
+    static char sigSha256wRsaName[] = "SHA256wRSA";
+#endif
+#ifdef WOLFSSL_SHA384
+    static char sigSha384wRsaName[] = "SHA384wRSA";
+#endif
+#ifdef WOLFSSL_SHA512
+    static char sigSha512wRsaName[] = "SHA512wRSA";
+#endif
+#endif /* NO_RSA */
+#ifdef HAVE_ECC
+#ifndef NO_SHA
+    static char sigSha1wEcdsaName[] = "SHAwECDSA";
+#endif
+#ifdef WOLFSSL_SHA224
+    static char sigSha224wEcdsaName[] = "SHA224wECDSA";
+#endif
+#ifndef NO_SHA256
+    static char sigSha256wEcdsaName[] = "SHA256wECDSA";
+#endif
+#ifdef WOLFSSL_SHA384
+    static char sigSha384wEcdsaName[] = "SHA384wECDSA";
+#endif
+#ifdef WOLFSSL_SHA512
+    static char sigSha512wEcdsaName[] = "SHA512wECDSA";
+#endif
+#endif /* HAVE_ECC */
+static char sigUnknownName[] = "Unknown";
+
+
+/* Get the human readable string for a signature type
+ *
+ * oid  Oid value for signature
+ */
+char* GetSigName(int oid) {
+    switch (oid) {
+    #if !defined(NO_DSA) && !defined(NO_SHA)
+        case CTC_SHAwDSA:
+            return sigSha1wDsaName;
+    #endif /* NO_DSA && NO_SHA */
+    #ifndef NO_RSA
+        #ifdef WOLFSSL_MD2
+        case CTC_MD2wRSA:
+            return sigMd2wRsaName;
+        #endif
+        #ifndef NO_MD5
+        case CTC_MD5wRSA:
+            return sigMd5wRsaName;
+        #endif
+        #ifndef NO_SHA
+        case CTC_SHAwRSA:
+            return sigSha1wRsaName;
+        #endif
+        #ifdef WOLFSSL_SHA224
+        case CTC_SHA224wRSA:
+            return sigSha224wRsaName;
+        #endif
+        #ifndef NO_SHA256
+        case CTC_SHA256wRSA:
+            return sigSha256wRsaName;
+        #endif
+        #ifdef WOLFSSL_SHA384
+        case CTC_SHA384wRSA:
+            return sigSha384wRsaName;
+        #endif
+        #ifdef WOLFSSL_SHA512
+        case CTC_SHA512wRSA:
+            return sigSha512wRsaName;
+        #endif
+    #endif /* NO_RSA */
+    #ifdef HAVE_ECC
+        #ifndef NO_SHA
+        case CTC_SHAwECDSA:
+            return sigSha1wEcdsaName;
+        #endif
+        #ifdef WOLFSSL_SHA224
+        case CTC_SHA224wECDSA:
+            return sigSha224wEcdsaName;
+        #endif
+        #ifndef NO_SHA256
+        case CTC_SHA256wECDSA:
+            return sigSha256wEcdsaName;
+        #endif
+        #ifdef WOLFSSL_SHA384
+        case CTC_SHA384wECDSA:
+            return sigSha384wEcdsaName;
+        #endif
+        #ifdef WOLFSSL_SHA512
+        case CTC_SHA512wECDSA:
+            return sigSha512wEcdsaName;
+        #endif
+    #endif /* HAVE_ECC */
+        default:
+            return sigUnknownName;
+    }
+}
+
+
 #if !defined(NO_DSA) || defined(HAVE_ECC) || \
    (!defined(NO_RSA) && \
         (defined(WOLFSSL_CERT_GEN) || \
-        (defined(WOLFSSL_KEY_GEN) && !defined(HAVE_USER_RSA))))
+        ((defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA)) && !defined(HAVE_USER_RSA))))
 /* Set the DER/BER encoding of the ASN.1 INTEGER header.
  *
@@ -786,5 +565,5 @@
 
 #if !defined(NO_DSA) || defined(HAVE_ECC) || defined(WOLFSSL_CERT_GEN) || \
-    (defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA) && !defined(HAVE_USER_RSA))
+    ((defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA)) && !defined(NO_RSA) && !defined(HAVE_USER_RSA))
 /* Set the DER/BER encoding of the ASN.1 INTEGER element with an mp_int.
  * The number is assumed to be positive.
@@ -906,4 +685,50 @@
     return *number;
 }
+
+
+/* Set small integer, 32 bits or less. DER encoding with no leading 0s
+ * returns total amount written including ASN tag and length byte on success */
+static int SetShortInt(byte* input, word32* inOutIdx, word32 number,
+                              word32 maxIdx)
+{
+    word32 idx = *inOutIdx;
+    word32 len = 0;
+    int    i;
+    byte ar[MAX_LENGTH_SZ];
+
+    /* check for room for type and length bytes */
+    if ((idx + 2) > maxIdx)
+        return BUFFER_E;
+
+    input[idx++] = ASN_INTEGER;
+    idx++; /* place holder for length byte */
+    if (MAX_LENGTH_SZ + idx > maxIdx)
+        return ASN_PARSE_E;
+
+    /* find first non zero byte */
+    XMEMSET(ar, 0, MAX_LENGTH_SZ);
+    c32toa(number, ar);
+    for (i = 0; i < MAX_LENGTH_SZ; i++) {
+        if (ar[i] != 0) {
+            break;
+        }
+    }
+
+    /* handle case of 0 */
+    if (i == MAX_LENGTH_SZ) {
+        input[idx++] = 0; len++;
+    }
+
+    for (; i < MAX_LENGTH_SZ && idx < maxIdx; i++) {
+        input[idx++] = ar[i]; len++;
+    }
+
+    /* jump back to beginning of input buffer using unaltered inOutIdx value
+     * and set number of bytes for integer, then update the index value */
+    input[*inOutIdx + 1] = (byte)len;
+    *inOutIdx = idx;
+
+    return len + 2; /* size of integer bytes plus ASN TAG and length byte */
+}
 #endif /* !NO_PWDBASED */
 
@@ -959,4 +784,24 @@
     return 0;
 }
+
+#if (!defined(WOLFSSL_KEY_GEN) && !defined(OPENSSL_EXTRA) && defined(RSA_LOW_MEM)) \
+    || defined(WOLFSSL_RSA_PUBLIC_ONLY)
+#if !defined(NO_RSA) && !defined(HAVE_USER_RSA)
+static int SkipInt(const byte* input, word32* inOutIdx, word32 maxIdx)
+{
+    word32 idx = *inOutIdx;
+    int    ret;
+    int    length;
+
+    ret = GetASNInt(input, &idx, &length, maxIdx);
+    if (ret != 0)
+        return ret;
+
+    *inOutIdx = idx + length;
+
+    return 0;
+}
+#endif
+#endif
 
 static int CheckBitString(const byte* input, word32* inOutIdx, int* len,
@@ -1008,9 +853,11 @@
 }
 
-#if (!defined(NO_RSA) && (defined(WOLFSSL_CERT_GEN) || \
-                          (defined(WOLFSSL_KEY_GEN) && \
-                           !defined(HAVE_USER_RSA)))) || \
-    (defined(HAVE_ECC) && (defined(WOLFSSL_CERT_GEN) || \
-                           defined(WOLFSSL_KEY_GEN)))
+/* RSA (with CertGen or KeyGen) OR ECC OR ED25519 (with CertGen or KeyGen) */
+#if (!defined(NO_RSA) && !defined(HAVE_USER_RSA) && \
+        (defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA))) || \
+    (defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT)) || \
+    (defined(HAVE_ED25519) && \
+        (defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA)))
+
 /* Set the DER/BER encoding of the ASN.1 BIT_STRING header.
  *
@@ -1032,4 +879,216 @@
     return idx;
 }
+#endif /* !NO_RSA || HAVE_ECC || HAVE_ED25519 */
+
+#ifdef ASN_BER_TO_DER
+/* Convert a BER encoding with indefinite length items to DER.
+ *
+ * ber    BER encoded data.
+ * berSz  Length of BER encoded data.
+ * der    Buffer to hold DER encoded version of data.
+ *        NULL indicates only the length is required.
+ * derSz  The size of the buffer to hold the DER encoded data.
+ *        Will be set if der is NULL, otherwise the value is checked as der is
+ *        filled.
+ * returns ASN_PARSE_E if the BER data is invalid and BAD_FUNC_ARG if ber or
+ * derSz are NULL.
+ */
+int wc_BerToDer(const byte* ber, word32 berSz, byte* der, word32* derSz)
+{
+    int ret;
+    word32 i, j, k;
+    int len, l;
+    int indef;
+    int depth = 0;
+    byte type;
+    word32 cnt, sz;
+    word32 outSz = 0;
+    byte lenBytes[4];
+
+    if (ber == NULL || derSz == NULL)
+        return BAD_FUNC_ARG;
+
+    sz = 0;
+    outSz = *derSz;
+
+    for (i = 0, j = 0; i < berSz; ) {
+        /* Check that there is data for an ASN item to parse. */
+        if (i + 2 > berSz)
+            return ASN_PARSE_E;
+
+        /* End Of Content (EOC) mark end of indefinite length items.
+         * EOCs are not encoded in DER.
+         * Keep track of no. indefinite length items that have not been
+         * terminated in depth.
+         */
+        if (ber[i] == 0 && ber[i+1] == 0) {
+            if (depth == 0)
+                break;
+            if (--depth == 0)
+                break;
+
+            i += 2;
+            continue;
+        }
+
+        /* Indefinite length is encoded as: 0x80 */
+        type = ber[i];
+        indef = ber[i+1] == ASN_INDEF_LENGTH;
+        if (indef && (type & 0xC0) == 0 &&
+                                   ber[i] != (ASN_SEQUENCE | ASN_CONSTRUCTED) &&
+                                   ber[i] != (ASN_SET      | ASN_CONSTRUCTED)) {
+            /* Indefinite length OCTET STRING or other simple type.
+             * Put all the data into one entry.
+             */
+
+            /* Type no longer constructed. */
+            type &= ~ASN_CONSTRUCTED;
+            if (der != NULL) {
+                /* Ensure space for type. */
+                if (j + 1 >= outSz)
+                    return BUFFER_E;
+                der[j] = type;
+            }
+            i++; j++;
+            /* Skip indefinite length. */
+            i++;
+
+            /* There must be further ASN1 items to combine. */
+            if (i + 2 > berSz)
+                return ASN_PARSE_E;
+
+            /* Calculate length of combined data. */
+            len = 0;
+            k = i;
+            while (ber[k] != 0x00) {
+                /* Each ASN item must be the same type as the constructed. */
+                if (ber[k] != type)
+                    return ASN_PARSE_E;
+                k++;
+
+                ret = GetLength(ber, &k, &l, berSz);
+                if (ret < 0)
+                    return ASN_PARSE_E;
+                k += l;
+                len += l;
+
+                /* Must at least have terminating EOC. */
+                if (k + 2 > berSz)
+                    return ASN_PARSE_E;
+            }
+            /* Ensure a valid EOC ASN item. */
+            if (ber[k+1] != 0x00)
+                return ASN_PARSE_E;
+
+            if (der == NULL) {
+                /* Add length of ASN item length encoding and data. */
+                j += SetLength(len, lenBytes);
+                j += len;
+            }
+            else {
+                /* Check space for encoded length. */
+                if (SetLength(len, lenBytes) > outSz - j)
+                    return BUFFER_E;
+                /* Encode new length. */
+                j += SetLength(len, der + j);
+
+                /* Encode data in single item. */
+                k = i;
+                while (ber[k] != 0x00) {
+                    /* Skip ASN type. */
+                    k++;
+
+                    /* Find length of data in ASN item. */
+                    ret = GetLength(ber, &k, &l, berSz);
+                    if (ret < 0)
+                        return ASN_PARSE_E;
+
+                    /* Ensure space for data and copy in. */
+                    if (j + l > outSz)
+                        return BUFFER_E;
+                    XMEMCPY(der + j, ber + k, l);
+                    k += l; j += l;
+                }
+            }
+            /* Continue conversion after EOC. */
+            i = k + 2;
+
+            continue;
+        }
+
+        if (der != NULL) {
+            /* Ensure space for type and at least one byte of length. */
+            if (j + 1 >= outSz)
+                return BUFFER_E;
+            /* Put in type. */
+            der[j] = ber[i];
+        }
+        i++; j++;
+
+        if (indef) {
+            /* Skip indefinite length. */
+            i++;
+            /* Calculate the size of the data inside constructed. */
+            ret = wc_BerToDer(ber + i, berSz - i, NULL, &sz);
+            if (ret != LENGTH_ONLY_E)
+                return ret;
+
+            if (der != NULL) {
+                /* Ensure space for encoded length. */
+                if (SetLength(sz, lenBytes) > outSz - j)
+                    return BUFFER_E;
+                /* Encode real length. */
+                j += SetLength(sz, der + j);
+            }
+            else {
+                /* Add size of encoded length. */
+                j += SetLength(sz, lenBytes);
+            }
+
+            /* Another EOC to find. */
+            depth++;
+        }
+        else {
+            /* Get the size of the encode length and length value. */
+            cnt = i;
+            ret = GetLength(ber, &cnt, &len, berSz);
+            if (ret < 0)
+                return ASN_PARSE_E;
+            cnt -= i;
+
+            /* Check there is enough data to copy out. */
+            if (i + cnt + len > berSz)
+                return ASN_PARSE_E;
+
+            if (der != NULL) {
+                /* Ensure space in DER buffer. */
+                if (j + cnt + len > outSz)
+                    return BUFFER_E;
+                /* Copy length and data into DER buffer. */
+                XMEMCPY(der + j, ber + i, cnt + len);
+            }
+            /* Continue conversion after this ASN item. */
+            i += cnt + len;
+            j += cnt + len;
+        }
+    }
+
+    if (depth >= 1)
+        return ASN_PARSE_E;
+
+    /* Return length if no buffer to write to. */
+    if (der == NULL) {
+        *derSz = j;
+        return LENGTH_ONLY_E;
+    }
+
+    return 0;
+}
+#endif
+
+#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_GEN)
+
+#if (!defined(NO_RSA) && !defined(HAVE_USER_RSA)) || \
+    defined(HAVE_ECC) || defined(HAVE_ED25519)
 
 #ifdef WOLFSSL_CERT_EXT
@@ -1067,37 +1126,91 @@
 }
 #endif /* WOLFSSL_CERT_EXT */
-#endif /* !NO_RSA && (WOLFSSL_CERT_GEN || (WOLFSSL_KEY_GEN &&
-                                           !HAVE_USER_RSA)) */
+#endif /* !NO_RSA || HAVE_ECC || HAVE_ED25519 */
+#endif /* WOLFSSL_CERT_GEN || WOLFSSL_KEY_GEN */
 
 
 
 /* hashType */
+#ifdef WOLFSSL_MD2
 static const byte hashMd2hOid[] = {42, 134, 72, 134, 247, 13, 2, 2};
+#endif
+#ifndef NO_MD5
 static const byte hashMd5hOid[] = {42, 134, 72, 134, 247, 13, 2, 5};
+#endif
+#ifndef NO_SHA
 static const byte hashSha1hOid[] = {43, 14, 3, 2, 26};
+#endif
+#ifdef WOLFSSL_SHA224
 static const byte hashSha224hOid[] = {96, 134, 72, 1, 101, 3, 4, 2, 4};
+#endif
+#ifndef NO_SHA256
 static const byte hashSha256hOid[] = {96, 134, 72, 1, 101, 3, 4, 2, 1};
+#endif
+#ifdef WOLFSSL_SHA384
 static const byte hashSha384hOid[] = {96, 134, 72, 1, 101, 3, 4, 2, 2};
+#endif
+#ifdef WOLFSSL_SHA512
 static const byte hashSha512hOid[] = {96, 134, 72, 1, 101, 3, 4, 2, 3};
+#endif
+
+/* hmacType */
+#ifndef NO_HMAC
+    #ifdef WOLFSSL_SHA224
+    static const byte hmacSha224Oid[] = {42, 134, 72, 134, 247, 13, 2, 8};
+    #endif
+    #ifndef NO_SHA256
+    static const byte hmacSha256Oid[] = {42, 134, 72, 134, 247, 13, 2, 9};
+    #endif
+    #ifdef WOLFSSL_SHA384
+    static const byte hmacSha384Oid[] = {42, 134, 72, 134, 247, 13, 2, 10};
+    #endif
+    #ifdef WOLFSSL_SHA512
+    static const byte hmacSha512Oid[] = {42, 134, 72, 134, 247, 13, 2, 11};
+    #endif
+#endif
 
 /* sigType */
-#ifndef NO_DSA
+#if !defined(NO_DSA) && !defined(NO_SHA)
     static const byte sigSha1wDsaOid[] = {42, 134, 72, 206, 56, 4, 3};
 #endif /* NO_DSA */
 #ifndef NO_RSA
+    #ifdef WOLFSSL_MD2
     static const byte sigMd2wRsaOid[] = {42, 134, 72, 134, 247, 13, 1, 1, 2};
+    #endif
+    #ifndef NO_MD5
     static const byte sigMd5wRsaOid[] = {42, 134, 72, 134, 247, 13, 1, 1, 4};
+    #endif
+    #ifndef NO_SHA
     static const byte sigSha1wRsaOid[] = {42, 134, 72, 134, 247, 13, 1, 1, 5};
+    #endif
+    #ifdef WOLFSSL_SHA224
     static const byte sigSha224wRsaOid[] = {42, 134, 72, 134, 247, 13, 1, 1,14};
+    #endif
+    #ifndef NO_SHA256
     static const byte sigSha256wRsaOid[] = {42, 134, 72, 134, 247, 13, 1, 1,11};
+    #endif
+    #ifdef WOLFSSL_SHA384
     static const byte sigSha384wRsaOid[] = {42, 134, 72, 134, 247, 13, 1, 1,12};
+    #endif
+    #ifdef WOLFSSL_SHA512
     static const byte sigSha512wRsaOid[] = {42, 134, 72, 134, 247, 13, 1, 1,13};
+    #endif
 #endif /* NO_RSA */
 #ifdef HAVE_ECC
+    #ifndef NO_SHA
     static const byte sigSha1wEcdsaOid[] = {42, 134, 72, 206, 61, 4, 1};
+    #endif
+    #ifdef WOLFSSL_SHA224
     static const byte sigSha224wEcdsaOid[] = {42, 134, 72, 206, 61, 4, 3, 1};
+    #endif
+    #ifndef NO_SHA256
     static const byte sigSha256wEcdsaOid[] = {42, 134, 72, 206, 61, 4, 3, 2};
+    #endif
+    #ifdef WOLFSSL_SHA384
     static const byte sigSha384wEcdsaOid[] = {42, 134, 72, 206, 61, 4, 3, 3};
+    #endif
+    #ifdef WOLFSSL_SHA512
     static const byte sigSha512wEcdsaOid[] = {42, 134, 72, 206, 61, 4, 3, 4};
+    #endif
 #endif /* HAVE_ECC */
 #ifdef HAVE_ED25519
@@ -1127,23 +1240,76 @@
 #endif /* HAVE_ECC */
 
+#ifdef HAVE_AES_CBC
 /* blkType */
+    #ifdef WOLFSSL_AES_128
 static const byte blkAes128CbcOid[] = {96, 134, 72, 1, 101, 3, 4, 1, 2};
+    #endif
+    #ifdef WOLFSSL_AES_192
 static const byte blkAes192CbcOid[] = {96, 134, 72, 1, 101, 3, 4, 1, 22};
+    #endif
+    #ifdef WOLFSSL_AES_256
 static const byte blkAes256CbcOid[] = {96, 134, 72, 1, 101, 3, 4, 1, 42};
+    #endif
+#endif /* HAVE_AES_CBC */
+#ifdef HAVE_AESGCM
+    #ifdef WOLFSSL_AES_128
+    static const byte blkAes128GcmOid[] = {96, 134, 72, 1, 101, 3, 4, 1, 6};
+    #endif
+    #ifdef WOLFSSL_AES_192
+    static const byte blkAes192GcmOid[] = {96, 134, 72, 1, 101, 3, 4, 1, 26};
+    #endif
+    #ifdef WOLFSSL_AES_256
+    static const byte blkAes256GcmOid[] = {96, 134, 72, 1, 101, 3, 4, 1, 46};
+    #endif
+#endif /* HAVE_AESGCM */
+#ifdef HAVE_AESCCM
+    #ifdef WOLFSSL_AES_128
+    static const byte blkAes128CcmOid[] = {96, 134, 72, 1, 101, 3, 4, 1, 7};
+    #endif
+    #ifdef WOLFSSL_AES_192
+    static const byte blkAes192CcmOid[] = {96, 134, 72, 1, 101, 3, 4, 1, 27};
+    #endif
+    #ifdef WOLFSSL_AES_256
+    static const byte blkAes256CcmOid[] = {96, 134, 72, 1, 101, 3, 4, 1, 47};
+    #endif
+#endif /* HAVE_AESCCM */
+
+#ifndef NO_DES3
 static const byte blkDesCbcOid[]  = {43, 14, 3, 2, 7};
 static const byte blkDes3CbcOid[] = {42, 134, 72, 134, 247, 13, 3, 7};
+#endif
 
 /* keyWrapType */
+#ifdef WOLFSSL_AES_128
 static const byte wrapAes128Oid[] = {96, 134, 72, 1, 101, 3, 4, 1, 5};
+#endif
+#ifdef WOLFSSL_AES_192
 static const byte wrapAes192Oid[] = {96, 134, 72, 1, 101, 3, 4, 1, 25};
+#endif
+#ifdef WOLFSSL_AES_256
 static const byte wrapAes256Oid[] = {96, 134, 72, 1, 101, 3, 4, 1, 45};
+#endif
+#ifdef HAVE_PKCS7
+/* From RFC 3211 */
+static const byte wrapPwriKekOid[] = {42, 134, 72, 134, 247, 13, 1, 9, 16, 3,9};
+#endif
 
 /* cmsKeyAgreeType */
+#ifndef NO_SHA
 static const byte dhSinglePass_stdDH_sha1kdf_Oid[]   =
                                           {43, 129, 5, 16, 134, 72, 63, 0, 2};
+#endif
+#ifdef WOLFSSL_SHA224
 static const byte dhSinglePass_stdDH_sha224kdf_Oid[] = {43, 129, 4, 1, 11, 0};
+#endif
+#ifndef NO_SHA256
 static const byte dhSinglePass_stdDH_sha256kdf_Oid[] = {43, 129, 4, 1, 11, 1};
+#endif
+#ifdef WOLFSSL_SHA384
 static const byte dhSinglePass_stdDH_sha384kdf_Oid[] = {43, 129, 4, 1, 11, 2};
+#endif
+#ifdef WOLFSSL_SHA512
 static const byte dhSinglePass_stdDH_sha512kdf_Oid[] = {43, 129, 4, 1, 11, 3};
+#endif
 
 /* ocspType */
@@ -1164,8 +1330,12 @@
 static const byte extInhibitAnyOid[] = {85, 29, 54};
 static const byte extExtKeyUsageOid[] = {85, 29, 37};
+#ifndef IGNORE_NAME_CONSTRAINTS
 static const byte extNameConsOid[] = {85, 29, 30};
+#endif
 
 /* certAuthInfoType */
+#ifdef HAVE_OCSP
 static const byte extAuthInfoOcspOid[] = {43, 6, 1, 5, 5, 7, 48, 1};
+#endif
 static const byte extAuthInfoCaIssuerOid[] = {43, 6, 1, 5, 5, 7, 48, 2};
 
@@ -1188,5 +1358,26 @@
 static const byte pbkdf2Oid[] = {42, 134, 72, 134, 247, 13, 1, 5, 12};
 
-static const byte* OidFromId(word32 id, word32 type, word32* oidSz)
+/* PKCS5 */
+#if !defined(NO_DES3) && !defined(NO_SHA)
+static const byte pbeSha1Des[] = {42, 134, 72, 134, 247, 13, 1, 5, 10};
+#endif
+static const byte pbes2[] = {42, 134, 72, 134, 247, 13, 1, 5, 13};
+
+/* PKCS12 */
+#if !defined(NO_RC4) && !defined(NO_SHA)
+static const byte pbeSha1RC4128[] = {42, 134, 72, 134, 247, 13, 1, 12, 1, 1};
+#endif
+#if !defined(NO_DES3) && !defined(NO_SHA)
+static const byte pbeSha1Des3[] = {42, 134, 72, 134, 247, 13, 1, 12, 1, 3};
+#endif
+
+#ifdef HAVE_LIBZ
+/* zlib compression */
+static const byte zlibCompress[] = {42, 134, 72, 134, 247, 13, 1, 9, 16, 3, 8};
+#endif
+
+
+/* returns a pointer to the OID string on success and NULL on fail */
+const byte* OidFromId(word32 id, word32 type, word32* oidSz)
 {
     const byte* oid = NULL;
@@ -1198,32 +1389,46 @@
         case oidHashType:
             switch (id) {
+            #ifdef WOLFSSL_MD2
                 case MD2h:
                     oid = hashMd2hOid;
                     *oidSz = sizeof(hashMd2hOid);
                     break;
+            #endif
+            #ifndef NO_MD5
                 case MD5h:
                     oid = hashMd5hOid;
                     *oidSz = sizeof(hashMd5hOid);
                     break;
+            #endif
+            #ifndef NO_SHA
                 case SHAh:
                     oid = hashSha1hOid;
                     *oidSz = sizeof(hashSha1hOid);
                     break;
+            #endif
+            #ifdef WOLFSSL_SHA224
                 case SHA224h:
                     oid = hashSha224hOid;
                     *oidSz = sizeof(hashSha224hOid);
                     break;
+            #endif
+            #ifndef NO_SHA256
                 case SHA256h:
                     oid = hashSha256hOid;
                     *oidSz = sizeof(hashSha256hOid);
                     break;
+            #endif
+            #ifdef WOLFSSL_SHA384
                 case SHA384h:
                     oid = hashSha384hOid;
                     *oidSz = sizeof(hashSha384hOid);
                     break;
+            #endif
+            #ifdef WOLFSSL_SHA512
                 case SHA512h:
                     oid = hashSha512hOid;
                     *oidSz = sizeof(hashSha512hOid);
                     break;
+            #endif
             }
             break;
@@ -1231,5 +1436,5 @@
         case oidSigType:
             switch (id) {
-                #ifndef NO_DSA
+                #if !defined(NO_DSA) && !defined(NO_SHA)
                 case CTC_SHAwDSA:
                     oid = sigSha1wDsaOid;
@@ -1238,54 +1443,78 @@
                 #endif /* NO_DSA */
                 #ifndef NO_RSA
+                #ifdef WOLFSSL_MD2
                 case CTC_MD2wRSA:
                     oid = sigMd2wRsaOid;
                     *oidSz = sizeof(sigMd2wRsaOid);
                     break;
+                #endif
+                #ifndef NO_MD5
                 case CTC_MD5wRSA:
                     oid = sigMd5wRsaOid;
                     *oidSz = sizeof(sigMd5wRsaOid);
                     break;
+                #endif
+                #ifndef NO_SHA
                 case CTC_SHAwRSA:
                     oid = sigSha1wRsaOid;
                     *oidSz = sizeof(sigSha1wRsaOid);
                     break;
+                #endif
+                #ifdef WOLFSSL_SHA224
                 case CTC_SHA224wRSA:
                     oid = sigSha224wRsaOid;
                     *oidSz = sizeof(sigSha224wRsaOid);
                     break;
+                #endif
+                #ifndef NO_SHA256
                 case CTC_SHA256wRSA:
                     oid = sigSha256wRsaOid;
                     *oidSz = sizeof(sigSha256wRsaOid);
                     break;
+                #endif
+                #ifdef WOLFSSL_SHA384
                 case CTC_SHA384wRSA:
                     oid = sigSha384wRsaOid;
                     *oidSz = sizeof(sigSha384wRsaOid);
                     break;
+                #endif
+                #ifdef WOLFSSL_SHA512
                 case CTC_SHA512wRSA:
                     oid = sigSha512wRsaOid;
                     *oidSz = sizeof(sigSha512wRsaOid);
                     break;
+                #endif /* WOLFSSL_SHA512 */
                 #endif /* NO_RSA */
                 #ifdef HAVE_ECC
+                #ifndef NO_SHA
                 case CTC_SHAwECDSA:
                     oid = sigSha1wEcdsaOid;
                     *oidSz = sizeof(sigSha1wEcdsaOid);
                     break;
+                #endif
+                #ifdef WOLFSSL_SHA224
                 case CTC_SHA224wECDSA:
                     oid = sigSha224wEcdsaOid;
                     *oidSz = sizeof(sigSha224wEcdsaOid);
                     break;
+                #endif
+                #ifndef NO_SHA256
                 case CTC_SHA256wECDSA:
                     oid = sigSha256wEcdsaOid;
                     *oidSz = sizeof(sigSha256wEcdsaOid);
                     break;
+                #endif
+                #ifdef WOLFSSL_SHA384
                 case CTC_SHA384wECDSA:
                     oid = sigSha384wEcdsaOid;
                     *oidSz = sizeof(sigSha384wEcdsaOid);
                     break;
+                #endif
+                #ifdef WOLFSSL_SHA512
                 case CTC_SHA512wECDSA:
                     oid = sigSha512wEcdsaOid;
                     *oidSz = sizeof(sigSha512wEcdsaOid);
                     break;
+                #endif
                 #endif /* HAVE_ECC */
                 #ifdef HAVE_ED25519
@@ -1347,16 +1576,65 @@
         case oidBlkType:
             switch (id) {
+    #ifdef HAVE_AES_CBC
+        #ifdef WOLFSSL_AES_128
                 case AES128CBCb:
                     oid = blkAes128CbcOid;
                     *oidSz = sizeof(blkAes128CbcOid);
                     break;
+        #endif
+        #ifdef WOLFSSL_AES_192
                 case AES192CBCb:
                     oid = blkAes192CbcOid;
                     *oidSz = sizeof(blkAes192CbcOid);
                     break;
+        #endif
+        #ifdef WOLFSSL_AES_256
                 case AES256CBCb:
                     oid = blkAes256CbcOid;
                     *oidSz = sizeof(blkAes256CbcOid);
                     break;
+        #endif
+    #endif /* HAVE_AES_CBC */
+    #ifdef HAVE_AESGCM
+        #ifdef WOLFSSL_AES_128
+                case AES128GCMb:
+                    oid = blkAes128GcmOid;
+                    *oidSz = sizeof(blkAes128GcmOid);
+                    break;
+        #endif
+        #ifdef WOLFSSL_AES_192
+                case AES192GCMb:
+                    oid = blkAes192GcmOid;
+                    *oidSz = sizeof(blkAes192GcmOid);
+                    break;
+        #endif
+        #ifdef WOLFSSL_AES_256
+                case AES256GCMb:
+                    oid = blkAes256GcmOid;
+                    *oidSz = sizeof(blkAes256GcmOid);
+                    break;
+        #endif
+    #endif /* HAVE_AESGCM */
+    #ifdef HAVE_AESCCM
+        #ifdef WOLFSSL_AES_128
+                case AES128CCMb:
+                    oid = blkAes128CcmOid;
+                    *oidSz = sizeof(blkAes128CcmOid);
+                    break;
+        #endif
+        #ifdef WOLFSSL_AES_192
+                case AES192CCMb:
+                    oid = blkAes192CcmOid;
+                    *oidSz = sizeof(blkAes192CcmOid);
+                    break;
+        #endif
+        #ifdef WOLFSSL_AES_256
+                case AES256CCMb:
+                    oid = blkAes256CcmOid;
+                    *oidSz = sizeof(blkAes256CcmOid);
+                    break;
+        #endif
+    #endif /* HAVE_AESCCM */
+    #ifndef NO_DES3
                 case DESb:
                     oid = blkDesCbcOid;
@@ -1367,4 +1645,5 @@
                     *oidSz = sizeof(blkDes3CbcOid);
                     break;
+    #endif /* !NO_DES3 */
             }
             break;
@@ -1427,8 +1706,10 @@
                     *oidSz = sizeof(extExtKeyUsageOid);
                     break;
+            #ifndef IGNORE_NAME_CONSTRAINTS
                 case NAME_CONS_OID:
                     oid = extNameConsOid;
                     *oidSz = sizeof(extNameConsOid);
                     break;
+            #endif
             }
             break;
@@ -1436,8 +1717,10 @@
         case oidCertAuthInfoType:
             switch (id) {
+            #ifdef HAVE_OCSP
                 case AIA_OCSP_OID:
                     oid = extAuthInfoOcspOid;
                     *oidSz = sizeof(extAuthInfoOcspOid);
                     break;
+            #endif
                 case AIA_CA_ISSUER_OID:
                     oid = extAuthInfoCaIssuerOid;
@@ -1507,18 +1790,58 @@
             break;
 
+        case oidPBEType:
+            switch (id) {
+        #if !defined(NO_SHA) && !defined(NO_RC4)
+                case PBE_SHA1_RC4_128:
+                    oid = pbeSha1RC4128;
+                    *oidSz = sizeof(pbeSha1RC4128);
+                    break;
+        #endif
+        #if !defined(NO_SHA) && !defined(NO_DES3)
+                case PBE_SHA1_DES:
+                    oid = pbeSha1Des;
+                    *oidSz = sizeof(pbeSha1Des);
+                    break;
+
+        #endif
+        #if !defined(NO_SHA) && !defined(NO_DES3)
+                case PBE_SHA1_DES3:
+                    oid = pbeSha1Des3;
+                    *oidSz = sizeof(pbeSha1Des3);
+                    break;
+        #endif
+                case PBES2:
+                    oid = pbes2;
+                    *oidSz = sizeof(pbes2);
+                    break;
+            }
+            break;
+
         case oidKeyWrapType:
             switch (id) {
+            #ifdef WOLFSSL_AES_128
                 case AES128_WRAP:
                     oid = wrapAes128Oid;
                     *oidSz = sizeof(wrapAes128Oid);
                     break;
+            #endif
+            #ifdef WOLFSSL_AES_192
                 case AES192_WRAP:
                     oid = wrapAes192Oid;
                     *oidSz = sizeof(wrapAes192Oid);
                     break;
+            #endif
+            #ifdef WOLFSSL_AES_256
                 case AES256_WRAP:
                     oid = wrapAes256Oid;
                     *oidSz = sizeof(wrapAes256Oid);
                     break;
+            #endif
+            #ifdef HAVE_PKCS7
+                case PWRI_KEK_WRAP:
+                    oid = wrapPwriKekOid;
+                    *oidSz = sizeof(wrapPwriKekOid);
+                    break;
+            #endif
             }
             break;
@@ -1526,26 +1849,78 @@
         case oidCmsKeyAgreeType:
             switch (id) {
+            #ifndef NO_SHA
                 case dhSinglePass_stdDH_sha1kdf_scheme:
                     oid = dhSinglePass_stdDH_sha1kdf_Oid;
                     *oidSz = sizeof(dhSinglePass_stdDH_sha1kdf_Oid);
                     break;
+            #endif
+            #ifdef WOLFSSL_SHA224
                 case dhSinglePass_stdDH_sha224kdf_scheme:
                     oid = dhSinglePass_stdDH_sha224kdf_Oid;
                     *oidSz = sizeof(dhSinglePass_stdDH_sha224kdf_Oid);
                     break;
+            #endif
+            #ifndef NO_SHA256
                 case dhSinglePass_stdDH_sha256kdf_scheme:
                     oid = dhSinglePass_stdDH_sha256kdf_Oid;
                     *oidSz = sizeof(dhSinglePass_stdDH_sha256kdf_Oid);
                     break;
+            #endif
+            #ifdef WOLFSSL_SHA384
                 case dhSinglePass_stdDH_sha384kdf_scheme:
                     oid = dhSinglePass_stdDH_sha384kdf_Oid;
                     *oidSz = sizeof(dhSinglePass_stdDH_sha384kdf_Oid);
                     break;
+            #endif
+            #ifdef WOLFSSL_SHA512
                 case dhSinglePass_stdDH_sha512kdf_scheme:
                     oid = dhSinglePass_stdDH_sha512kdf_Oid;
                     *oidSz = sizeof(dhSinglePass_stdDH_sha512kdf_Oid);
                     break;
+            #endif
             }
             break;
+
+#ifndef NO_HMAC
+        case oidHmacType:
+            switch (id) {
+        #ifdef WOLFSSL_SHA224
+                case HMAC_SHA224_OID:
+                    oid = hmacSha224Oid;
+                    *oidSz = sizeof(hmacSha224Oid);
+                    break;
+        #endif
+        #ifndef NO_SHA256
+                case HMAC_SHA256_OID:
+                    oid = hmacSha256Oid;
+                    *oidSz = sizeof(hmacSha256Oid);
+                    break;
+        #endif
+        #ifdef WOLFSSL_SHA384
+                case HMAC_SHA384_OID:
+                    oid = hmacSha384Oid;
+                    *oidSz = sizeof(hmacSha384Oid);
+                    break;
+        #endif
+        #ifdef WOLFSSL_SHA512
+                case HMAC_SHA512_OID:
+                    oid = hmacSha512Oid;
+                    *oidSz = sizeof(hmacSha512Oid);
+                    break;
+        #endif
+            }
+            break;
+#endif /* !NO_HMAC */
+
+#ifdef HAVE_LIBZ
+        case oidCompressType:
+            switch (id) {
+                case ZLIBc:
+                    oid = zlibCompress;
+                    *oidSz = sizeof(zlibCompress);
+                    break;
+            }
+            break;
+#endif /* HAVE_LIBZ */
 
         case oidIgnoreType:
@@ -1682,5 +2057,5 @@
  *         Otherwise, 0 to indicate success.
  */
-static int GetASNObjectId(const byte* input, word32* inOutIdx, int* len,
+int GetASNObjectId(const byte* input, word32* inOutIdx, int* len,
                           word32 maxIdx)
 {
@@ -1710,5 +2085,5 @@
  * returns the number of bytes added to the buffer.
  */
-static int SetObjectId(int len, byte* output)
+int SetObjectId(int len, byte* output)
 {
     int idx = 0;
@@ -1758,5 +2133,5 @@
         word32 checkOidSz;
     #ifdef ASN_DUMP_OID
-        int i;
+        word32 i;
     #endif
 
@@ -1836,5 +2211,5 @@
 
     /* could have NULL tag and 0 terminator, but may not */
-    if (input[idx] == ASN_TAG_NULL) {
+    if (idx < maxIdx && input[idx] == ASN_TAG_NULL) {
         ret = GetASNNull(input, &idx, maxIdx);
         if (ret != 0)
@@ -1868,10 +2243,25 @@
     if (GetInt(&key->n,  input, inOutIdx, inSz) < 0 ||
         GetInt(&key->e,  input, inOutIdx, inSz) < 0 ||
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
         GetInt(&key->d,  input, inOutIdx, inSz) < 0 ||
         GetInt(&key->p,  input, inOutIdx, inSz) < 0 ||
-        GetInt(&key->q,  input, inOutIdx, inSz) < 0 ||
-        GetInt(&key->dP, input, inOutIdx, inSz) < 0 ||
+        GetInt(&key->q,  input, inOutIdx, inSz) < 0)
+#else
+        SkipInt(input, inOutIdx, inSz) < 0 ||
+        SkipInt(input, inOutIdx, inSz) < 0 ||
+        SkipInt(input, inOutIdx, inSz) < 0 )
+
+#endif
+            return ASN_RSA_KEY_E;
+#if (defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA) || !defined(RSA_LOW_MEM)) \
+    && !defined(WOLFSSL_RSA_PUBLIC_ONLY)
+    if (GetInt(&key->dP, input, inOutIdx, inSz) < 0 ||
         GetInt(&key->dQ, input, inOutIdx, inSz) < 0 ||
         GetInt(&key->u,  input, inOutIdx, inSz) < 0 )  return ASN_RSA_KEY_E;
+#else
+    if (SkipInt(input, inOutIdx, inSz) < 0 ||
+        SkipInt(input, inOutIdx, inSz) < 0 ||
+        SkipInt(input, inOutIdx, inSz) < 0 )  return ASN_RSA_KEY_E;
+#endif
 
 #ifdef WOLFSSL_XILINX_CRYPT
@@ -1888,7 +2278,8 @@
 /* Remove PKCS8 header, place inOutIdx at beginning of traditional,
  * return traditional length on success, negative on error */
-int ToTraditionalInline(const byte* input, word32* inOutIdx, word32 sz)
-{
-    word32 idx, oid;
+int ToTraditionalInline_ex(const byte* input, word32* inOutIdx, word32 sz,
+                           word32* algId)
+{
+    word32 idx;
     int    version, length;
     int    ret;
@@ -1905,5 +2296,5 @@
         return ASN_PARSE_E;
 
-    if (GetAlgoId(input, &idx, &oid, oidKeyType, sz) < 0)
+    if (GetAlgoId(input, &idx, algId, oidKeyType, sz) < 0)
         return ASN_PARSE_E;
 
@@ -1922,6 +2313,13 @@
 }
 
+int ToTraditionalInline(const byte* input, word32* inOutIdx, word32 sz)
+{
+    word32 oid;
+
+    return ToTraditionalInline_ex(input, inOutIdx, sz, &oid);
+}
+
 /* Remove PKCS8 header, move beginning of traditional to beginning of input */
-int ToTraditional(byte* input, word32 sz)
+int ToTraditional_ex(byte* input, word32 sz, word32* algId)
 {
     word32 inOutIdx = 0;
@@ -1931,5 +2329,5 @@
         return BAD_FUNC_ARG;
 
-    length = ToTraditionalInline(input, &inOutIdx, sz);
+    length = ToTraditionalInline_ex(input, &inOutIdx, sz, algId);
     if (length < 0)
         return length;
@@ -1940,4 +2338,10 @@
 }
 
+int ToTraditional(byte* input, word32 sz)
+{
+    word32 oid;
+
+    return ToTraditional_ex(input, sz, &oid);
+}
 
 /* find beginning of traditional key inside PKCS#8 unencrypted buffer
@@ -1948,9 +2352,10 @@
 {
     int length;
+    word32 algId;
 
     if (input == NULL || inOutIdx == NULL || (*inOutIdx > sz))
         return BAD_FUNC_ARG;
 
-    length = ToTraditionalInline(input, inOutIdx, sz);
+    length = ToTraditionalInline_ex(input, inOutIdx, sz, &algId);
 
     return length;
@@ -2079,4 +2484,5 @@
 {
     int ret;
+    (void)keySz;
 
     if (key == NULL || der == NULL) {
@@ -2084,21 +2490,46 @@
     }
 
-    #if !defined(NO_RSA)
+    #if !defined(NO_RSA) && !defined(NO_ASN_CRYPT)
     /* test if RSA key */
     if (der->keyOID == RSAk) {
-        RsaKey a, b;
+    #ifdef WOLFSSL_SMALL_STACK
+        RsaKey* a = NULL;
+        RsaKey* b = NULL;
+    #else
+        RsaKey a[1], b[1];
+    #endif
         word32 keyIdx = 0;
 
-        if ((ret = wc_InitRsaKey(&a, NULL)) < 0)
+    #ifdef WOLFSSL_SMALL_STACK
+        a = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_RSA);
+        if (a == NULL)
+            return MEMORY_E;
+        b = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_RSA);
+        if (b == NULL) {
+            XFREE(a, NULL, DYNAMIC_TYPE_RSA);
+            return MEMORY_E;
+        }
+    #endif
+
+        if ((ret = wc_InitRsaKey(a, NULL)) < 0) {
+    #ifdef WOLFSSL_SMALL_STACK
+            XFREE(b, NULL, DYNAMIC_TYPE_RSA);
+            XFREE(a, NULL, DYNAMIC_TYPE_RSA);
+    #endif
             return ret;
-        if ((ret = wc_InitRsaKey(&b, NULL)) < 0) {
-            wc_FreeRsaKey(&a);
+        }
+        if ((ret = wc_InitRsaKey(b, NULL)) < 0) {
+            wc_FreeRsaKey(a);
+    #ifdef WOLFSSL_SMALL_STACK
+            XFREE(b, NULL, DYNAMIC_TYPE_RSA);
+            XFREE(a, NULL, DYNAMIC_TYPE_RSA);
+    #endif
             return ret;
         }
-        if ((ret = wc_RsaPrivateKeyDecode(key, &keyIdx, &a, keySz)) == 0) {
+        if ((ret = wc_RsaPrivateKeyDecode(key, &keyIdx, a, keySz)) == 0) {
             WOLFSSL_MSG("Checking RSA key pair");
             keyIdx = 0; /* reset to 0 for parsing public key */
 
-            if ((ret = wc_RsaPublicKeyDecode(der->publicKey, &keyIdx, &b,
+            if ((ret = wc_RsaPublicKeyDecode(der->publicKey, &keyIdx, b,
                                                        der->pubKeySize)) == 0) {
                 /* limit for user RSA crypto because of RsaKey
@@ -2110,6 +2541,6 @@
                 /* both keys extracted successfully now check n and e
                  * values are the same. This is dereferencing RsaKey */
-                if (mp_cmp(&(a.n), &(b.n)) != MP_EQ ||
-                    mp_cmp(&(a.e), &(b.e)) != MP_EQ) {
+                if (mp_cmp(&(a->n), &(b->n)) != MP_EQ ||
+                    mp_cmp(&(a->e), &(b->e)) != MP_EQ) {
                     ret = MP_CMP_E;
                 }
@@ -2119,63 +2550,127 @@
             }
         }
-        wc_FreeRsaKey(&b);
-        wc_FreeRsaKey(&a);
+        wc_FreeRsaKey(b);
+        wc_FreeRsaKey(a);
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(b, NULL, DYNAMIC_TYPE_RSA);
+        XFREE(a, NULL, DYNAMIC_TYPE_RSA);
+    #endif
     }
     else
-    #endif /* NO_RSA */
-
-    #ifdef HAVE_ECC
+    #endif /* !NO_RSA && !NO_ASN_CRYPT */
+
+    #if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) && !defined(NO_ASN_CRYPT)
     if (der->keyOID == ECDSAk) {
+    #ifdef WOLFSSL_SMALL_STACK
+        ecc_key* key_pair = NULL;
+        byte*    privDer;
+    #else
+        ecc_key  key_pair[1];
+        byte     privDer[MAX_ECC_BYTES];
+    #endif
+        word32   privSz = MAX_ECC_BYTES;
         word32  keyIdx = 0;
-        ecc_key key_pair;
-
-        if ((ret = wc_ecc_init(&key_pair)) < 0)
+
+    #ifdef WOLFSSL_SMALL_STACK
+        key_pair = (ecc_key*)XMALLOC(sizeof(ecc_key), NULL, DYNAMIC_TYPE_ECC);
+        if (key_pair == NULL)
+            return MEMORY_E;
+        privDer = (byte*)XMALLOC(MAX_ECC_BYTES, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (privDer == NULL) {
+            XFREE(key_pair, NULL, DYNAMIC_TYPE_ECC);
+            return MEMORY_E;
+        }
+    #endif
+
+        if ((ret = wc_ecc_init(key_pair)) < 0) {
+    #ifdef WOLFSSL_SMALL_STACK
+            XFREE(privDer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(key_pair, NULL, DYNAMIC_TYPE_ECC);
+    #endif
             return ret;
-        if ((ret = wc_EccPrivateKeyDecode(key, &keyIdx, &key_pair,
+        }
+
+        if ((ret = wc_EccPrivateKeyDecode(key, &keyIdx, key_pair,
                                                                  keySz)) == 0) {
             WOLFSSL_MSG("Checking ECC key pair");
-            keyIdx = 0;
-            if ((ret = wc_ecc_import_x963(der->publicKey, der->pubKeySize,
-                                                             &key_pair)) == 0) {
-                /* public and private extracted successfuly no check if is
+
+            if ((ret = wc_ecc_export_private_only(key_pair, privDer, &privSz))
+                                                                         == 0) {
+                wc_ecc_free(key_pair);
+                ret = wc_ecc_init(key_pair);
+                if (ret == 0) {
+                    ret = wc_ecc_import_private_key((const byte*)privDer,
+                                            privSz, (const byte*)der->publicKey,
+                                            der->pubKeySize, key_pair);
+                }
+
+                /* public and private extracted successfuly now check if is
                  * a pair and also do sanity checks on key. wc_ecc_check_key
                  * checks that private * base generator equals pubkey */
-                if ((ret = wc_ecc_check_key(&key_pair)) == 0)
+                if (ret == 0) {
+                    if ((ret = wc_ecc_check_key(key_pair)) == 0) {
                     ret = 1;
             }
         }
-        wc_ecc_free(&key_pair);
+                ForceZero(privDer, privSz);
+            }
+        }
+        wc_ecc_free(key_pair);
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(privDer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(key_pair, NULL, DYNAMIC_TYPE_ECC);
+    #endif
     }
     else
-    #endif /* HAVE_ECC */
-
-    #ifdef HAVE_ED25519
+    #endif /* HAVE_ECC && HAVE_ECC_KEY_EXPORT && !NO_ASN_CRYPT */
+
+    #if defined(HAVE_ED25519) && !defined(NO_ASN_CRYPT)
     if (der->keyOID == ED25519k) {
+    #ifdef WOLFSSL_SMALL_STACK
+        ed25519_key* key_pair = NULL;
+    #else
+        ed25519_key  key_pair[1];
+    #endif
         word32  keyIdx = 0;
-        ed25519_key key_pair;
-
-        if ((ret = wc_ed25519_init(&key_pair)) < 0)
+
+    #ifdef WOLFSSL_SMALL_STACK
+        key_pair = (ed25519_key*)XMALLOC(sizeof(ed25519_key), NULL,
+                                                          DYNAMIC_TYPE_ED25519);
+        if (key_pair == NULL)
+            return MEMORY_E;
+    #endif
+
+        if ((ret = wc_ed25519_init(key_pair)) < 0) {
+    #ifdef WOLFSSL_SMALL_STACK
+            XFREE(key_pair, NULL, DYNAMIC_TYPE_ED25519);
+    #endif
             return ret;
-        if ((ret = wc_Ed25519PrivateKeyDecode(key, &keyIdx, &key_pair,
+        }
+        if ((ret = wc_Ed25519PrivateKeyDecode(key, &keyIdx, key_pair,
                                                                  keySz)) == 0) {
             WOLFSSL_MSG("Checking ED25519 key pair");
             keyIdx = 0;
             if ((ret = wc_ed25519_import_public(der->publicKey, der->pubKeySize,
-                                                             &key_pair)) == 0) {
+                                                              key_pair)) == 0) {
                 /* public and private extracted successfuly no check if is
                  * a pair and also do sanity checks on key. wc_ecc_check_key
                  * checks that private * base generator equals pubkey */
-                if ((ret = wc_ed25519_check_key(&key_pair)) == 0)
+                if ((ret = wc_ed25519_check_key(key_pair)) == 0)
                     ret = 1;
             }
         }
-        wc_ed25519_free(&key_pair);
+        wc_ed25519_free(key_pair);
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(key_pair, NULL, DYNAMIC_TYPE_ED25519);
+    #endif
     }
     else
-    #endif
+    #endif /* HAVE_ED25519 && !NO_ASN_CRYPT */
     {
         ret = 0;
     }
 
+    (void)keySz;
+
     return ret;
 }
@@ -2185,19 +2680,27 @@
 /* Check To see if PKCS version algo is supported, set id if it is return 0
    < 0 on error */
-static int CheckAlgo(int first, int second, int* id, int* version)
+static int CheckAlgo(int first, int second, int* id, int* version, int* blockSz)
 {
     *id      = ALGO_ID_E;
     *version = PKCS5;   /* default */
+    if (blockSz) *blockSz = 8; /* default */
 
     if (first == 1) {
         switch (second) {
-        case 1:
+#if !defined(NO_SHA)
+    #ifndef NO_RC4
+        case PBE_SHA1_RC4_128:
             *id = PBE_SHA1_RC4_128;
             *version = PKCS12v1;
             return 0;
-        case 3:
+    #endif
+    #ifndef NO_DES3
+        case PBE_SHA1_DES3:
             *id = PBE_SHA1_DES3;
             *version = PKCS12v1;
+            if (blockSz) *blockSz = DES_BLOCK_SIZE;
             return 0;
+    #endif
+#endif /* !NO_SHA */
         default:
             return ALGO_ID_E;
@@ -2214,10 +2717,18 @@
 
     switch (second) {
+#ifndef NO_DES3
+    #ifndef NO_MD5
     case 3:                   /* see RFC 2898 for ids */
         *id = PBE_MD5_DES;
+        if (blockSz) *blockSz = DES_BLOCK_SIZE;
         return 0;
+    #endif
+    #ifndef NO_SHA
     case 10:
         *id = PBE_SHA1_DES;
+        if (blockSz) *blockSz = DES_BLOCK_SIZE;
         return 0;
+    #endif
+#endif /* !NO_DES3 */
     default:
         return ALGO_ID_E;
@@ -2229,13 +2740,25 @@
 /* Check To see if PKCS v2 algo is supported, set id if it is return 0
    < 0 on error */
-static int CheckAlgoV2(int oid, int* id)
-{
+static int CheckAlgoV2(int oid, int* id, int* blockSz)
+{
+    if (blockSz) *blockSz = 8; /* default */
+    (void)id; /* not used if AES and DES3 disabled */
     switch (oid) {
-    case 69:
+#if !defined(NO_DES3) && !defined(NO_SHA)
+    case DESb:
         *id = PBE_SHA1_DES;
+        if (blockSz) *blockSz = DES_BLOCK_SIZE;
         return 0;
-    case 652:
+    case DES3b:
         *id = PBE_SHA1_DES3;
+        if (blockSz) *blockSz = DES_BLOCK_SIZE;
         return 0;
+#endif
+#ifdef WOLFSSL_AES_256
+    case AES256CBCb:
+        *id = PBE_AES256_CBC;
+        if (blockSz) *blockSz = AES_BLOCK_SIZE;
+        return 0;
+#endif
     default:
         return ALGO_ID_E;
@@ -2245,208 +2768,22 @@
 
 
-/* Decrypt input in place from parameters based on id */
-static int DecryptKey(const char* password, int passwordSz, byte* salt,
-                      int saltSz, int iterations, int id, byte* input,
-                      int length, int version, byte* cbcIv)
-{
-    int typeH;
-    int derivedLen;
-    int decryptionType;
-    int ret = 0;
-#ifdef WOLFSSL_SMALL_STACK
-    byte* key;
-#else
-    byte key[MAX_KEY_SIZE];
-#endif
-
-    (void)input;
-    (void)length;
-
-    switch (id) {
-        case PBE_MD5_DES:
-            typeH = WC_MD5;
-            derivedLen = 16;           /* may need iv for v1.5 */
-            decryptionType = DES_TYPE;
-            break;
-
-        case PBE_SHA1_DES:
-            typeH = WC_SHA;
-            derivedLen = 16;           /* may need iv for v1.5 */
-            decryptionType = DES_TYPE;
-            break;
-
-        case PBE_SHA1_DES3:
-            typeH = WC_SHA;
-            derivedLen = 32;           /* may need iv for v1.5 */
-            decryptionType = DES3_TYPE;
-            break;
-
-        case PBE_SHA1_RC4_128:
-            typeH = WC_SHA;
-            derivedLen = 16;
-            decryptionType = RC4_TYPE;
-            break;
-
-        default:
-            return ALGO_ID_E;
-    }
-
-#ifdef WOLFSSL_SMALL_STACK
-    key = (byte*)XMALLOC(MAX_KEY_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-    if (key == NULL)
-        return MEMORY_E;
-#endif
-
-    if (version == PKCS5v2)
-        ret = wc_PBKDF2(key, (byte*)password, passwordSz,
-                        salt, saltSz, iterations, derivedLen, typeH);
-#ifndef NO_SHA
-    else if (version == PKCS5)
-        ret = wc_PBKDF1(key, (byte*)password, passwordSz,
-                        salt, saltSz, iterations, derivedLen, typeH);
-#endif
-    else if (version == PKCS12v1) {
-        int  i, idx = 0;
-        byte unicodePasswd[MAX_UNICODE_SZ];
-
-        if ( (passwordSz * 2 + 2) > (int)sizeof(unicodePasswd)) {
-#ifdef WOLFSSL_SMALL_STACK
-            XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
-            return UNICODE_SIZE_E;
-        }
-
-        for (i = 0; i < passwordSz; i++) {
-            unicodePasswd[idx++] = 0x00;
-            unicodePasswd[idx++] = (byte)password[i];
-        }
-        /* add trailing NULL */
-        unicodePasswd[idx++] = 0x00;
-        unicodePasswd[idx++] = 0x00;
-
-        ret =  wc_PKCS12_PBKDF(key, unicodePasswd, idx, salt, saltSz,
-                            iterations, derivedLen, typeH, 1);
-        if (decryptionType != RC4_TYPE)
-            ret += wc_PKCS12_PBKDF(cbcIv, unicodePasswd, idx, salt, saltSz,
-                                iterations, 8, typeH, 2);
-    }
-    else {
-#ifdef WOLFSSL_SMALL_STACK
-        XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
-        return ALGO_ID_E;
-    }
-
-    if (ret != 0) {
-#ifdef WOLFSSL_SMALL_STACK
-        XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
-        return ret;
-    }
-
-    switch (decryptionType) {
-#ifndef NO_DES3
-        case DES_TYPE:
-        {
-            Des    dec;
-            byte*  desIv = key + 8;
-
-            if (version == PKCS5v2 || version == PKCS12v1)
-                desIv = cbcIv;
-
-            ret = wc_Des_SetKey(&dec, key, desIv, DES_DECRYPTION);
-            if (ret != 0) {
-#ifdef WOLFSSL_SMALL_STACK
-                XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
-                return ret;
-            }
-
-            wc_Des_CbcDecrypt(&dec, input, input, length);
-            break;
-        }
-
-        case DES3_TYPE:
-        {
-            Des3   dec;
-            byte*  desIv = key + 24;
-
-            if (version == PKCS5v2 || version == PKCS12v1)
-                desIv = cbcIv;
-
-            ret = wc_Des3Init(&dec, NULL, INVALID_DEVID);
-            if (ret != 0) {
-#ifdef WOLFSSL_SMALL_STACK
-                XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
-                return ret;
-            }
-            ret = wc_Des3_SetKey(&dec, key, desIv, DES_DECRYPTION);
-            if (ret != 0) {
-#ifdef WOLFSSL_SMALL_STACK
-                XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
-                return ret;
-            }
-            ret = wc_Des3_CbcDecrypt(&dec, input, input, length);
-            if (ret != 0) {
-#ifdef WOLFSSL_SMALL_STACK
-                XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
-                return ret;
-            }
-            break;
-        }
-#endif
-#ifndef NO_RC4
-        case RC4_TYPE:
-        {
-            Arc4    dec;
-
-            wc_Arc4SetKey(&dec, key, derivedLen);
-            wc_Arc4Process(&dec, input, input, length);
-            break;
-        }
-#endif
-
-        default:
-#ifdef WOLFSSL_SMALL_STACK
-            XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
-            return ALGO_ID_E;
-    }
-
-#ifdef WOLFSSL_SMALL_STACK
-    XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
-
-    return 0;
-}
-
-
 int wc_GetKeyOID(byte* key, word32 keySz, const byte** curveOID, word32* oidSz,
         int* algoID, void* heap)
 {
     word32 tmpIdx = 0;
-#ifdef HAVE_ECC
-    ecc_key ecc;
-#endif
-#ifndef NO_RSA
-    RsaKey rsa;
-#endif
-#ifdef HAVE_ED25519
-    ed25519_key ed25519;
-#endif
-
-    if (algoID == NULL) {
+
+    if (key == NULL || algoID == NULL)
         return BAD_FUNC_ARG;
-    }
+
     *algoID = 0;
 
-#ifndef NO_RSA
-    if (wc_InitRsaKey(&rsa, heap) == 0) {
+    #if !defined(NO_RSA) && !defined(NO_ASN_CRYPT)
+    {
+        RsaKey rsa;
+
+        wc_InitRsaKey(&rsa, heap);
         if (wc_RsaPrivateKeyDecode(key, &tmpIdx, &rsa, keySz) == 0) {
             *algoID = RSAk;
-        }
+    }
         else {
             WOLFSSL_MSG("Not RSA DER key");
@@ -2454,56 +2791,47 @@
         wc_FreeRsaKey(&rsa);
     }
-    else {
-        WOLFSSL_MSG("GetKeyOID wc_InitRsaKey failed");
-    }
-#endif /* NO_RSA */
-#ifdef HAVE_ECC
-    if (*algoID != RSAk) {
+    #endif /* !NO_RSA && !NO_ASN_CRYPT */
+    #if defined(HAVE_ECC) && !defined(NO_ASN_CRYPT)
+    if (*algoID == 0) {
+        ecc_key ecc;
+
         tmpIdx = 0;
-        if (wc_ecc_init_ex(&ecc, heap, INVALID_DEVID) == 0) {
-            if (wc_EccPrivateKeyDecode(key, &tmpIdx, &ecc, keySz) == 0) {
-                *algoID = ECDSAk;
-
-                /* sanity check on arguments */
-                if (curveOID == NULL || oidSz == NULL) {
-                    WOLFSSL_MSG("Error getting ECC curve OID");
-                    wc_ecc_free(&ecc);
-                    return BAD_FUNC_ARG;
-                }
-
-                /* now find oid */
-                if (wc_ecc_get_oid(ecc.dp->oidSum, curveOID, oidSz) < 0) {
-                    WOLFSSL_MSG("Error getting ECC curve OID");
-                    wc_ecc_free(&ecc);
-                    return BAD_FUNC_ARG;
-                }
-            }
-            else {
-                WOLFSSL_MSG("Not ECC DER key either");
-            }
-            wc_ecc_free(&ecc);
+        wc_ecc_init_ex(&ecc, heap, INVALID_DEVID);
+        if (wc_EccPrivateKeyDecode(key, &tmpIdx, &ecc, keySz) == 0) {
+            *algoID = ECDSAk;
+
+            /* now find oid */
+            if (wc_ecc_get_oid(ecc.dp->oidSum, curveOID, oidSz) < 0) {
+                WOLFSSL_MSG("Error getting ECC curve OID");
+                wc_ecc_free(&ecc);
+                return BAD_FUNC_ARG;
+        }
         }
         else {
-            WOLFSSL_MSG("GetKeyOID wc_ecc_init_ex failed");
-        }
-    }
-#endif /* HAVE_ECC */
-#ifdef HAVE_ED25519
+            WOLFSSL_MSG("Not ECC DER key either");
+        }
+        wc_ecc_free(&ecc);
+    }
+#endif /* HAVE_ECC && !NO_ASN_CRYPT */
+#if defined(HAVE_ED25519) && !defined(NO_ASN_CRYPT)
     if (*algoID != RSAk && *algoID != ECDSAk) {
+        ed25519_key ed25519;
+
+        tmpIdx = 0;
         if (wc_ed25519_init(&ed25519) == 0) {
             if (wc_Ed25519PrivateKeyDecode(key, &tmpIdx, &ed25519, keySz)
                                                                          == 0) {
                 *algoID = ED25519k;
-            }
-            else {
+    }
+    else {
                 WOLFSSL_MSG("Not ED25519 DER key");
-            }
+    }
             wc_ed25519_free(&ed25519);
-        }
+    }
         else {
             WOLFSSL_MSG("GetKeyOID wc_ed25519_init failed");
         }
     }
-#endif
+#endif /* HAVE_ED25519 && !NO_ASN_CRYPT */
 
     /* if flag is not set then is neither RSA or ECC key that could be
@@ -2514,18 +2842,480 @@
     }
 
+    (void)tmpIdx;
     (void)curveOID;
     (void)oidSz;
+    (void)keySz;
+    (void)heap;
 
     return 1;
 }
 
+#define PKCS8_MIN_BLOCK_SIZE 8
+static int Pkcs8Pad(byte* buf, int sz, int blockSz)
+        {
+    int i, padSz;
+
+    /* calculate pad size */
+    padSz = blockSz - (sz & (blockSz - 1));
+
+    /* pad with padSz value */
+    if (buf) {
+        for (i = 0; i < padSz; i++) {
+            buf[sz+i] = (byte)(padSz & 0xFF);
+        }
+            }
+
+    /* return adjusted length */
+    return sz + padSz;
+        }
+
+/*
+ * Used when creating PKCS12 shrouded key bags
+ * vPKCS is the version of PKCS to use
+ * vAlgo is the algorithm version to use
+ *
+ * if salt is NULL a random number is generated
+ *
+ * returns the size of encrypted data on success
+ */
+int UnTraditionalEnc(byte* key, word32 keySz, byte* out, word32* outSz,
+        const char* password, int passwordSz, int vPKCS, int vAlgo,
+        byte* salt, word32 saltSz, int itt, WC_RNG* rng, void* heap)
+        {
+    int algoID = 0;
+    byte*  tmp;
+    word32 tmpSz = 0;
+    word32 sz;
+    word32 seqSz;
+    word32 inOutIdx = 0;
+    word32 totalSz = 0;
+    int    version, id;
+    int    ret;
+    int    blockSz = 0;
+
+    const byte* curveOID = NULL;
+    word32 oidSz   = 0;
+
+#ifdef WOLFSSL_SMALL_STACK
+    byte*  saltTmp = NULL;
+    byte*  cbcIv   = NULL;
+#else
+    byte   saltTmp[MAX_IV_SIZE];
+    byte   cbcIv[MAX_IV_SIZE];
+#endif
+
+    WOLFSSL_ENTER("UnTraditionalEnc()");
+
+    if (saltSz > MAX_SALT_SIZE)
+        return ASN_PARSE_E;
+
+
+    inOutIdx += MAX_SEQ_SZ; /* leave room for size of finished shroud */
+    if (CheckAlgo(vPKCS, vAlgo, &id, &version, &blockSz) < 0) {
+        WOLFSSL_MSG("Bad/Unsupported algorithm ID");
+        return ASN_INPUT_E;  /* Algo ID error */
+            }
+
+    if (out != NULL) {
+        if (*outSz < inOutIdx + MAX_ALGO_SZ + MAX_SALT_SIZE + MAX_SEQ_SZ + 1 +
+                MAX_LENGTH_SZ + MAX_SHORT_SZ + 1)
+                return BUFFER_E;
+
+        if (version == PKCS5v2) {
+            WOLFSSL_MSG("PKCS5v2 Not supported yet\n");
+            return ASN_VERSION_E;
+        }
+
+        if (salt == NULL || saltSz <= 0) {
+            saltSz = 8;
+        #ifdef WOLFSSL_SMALL_STACK
+            saltTmp = (byte*)XMALLOC(saltSz, heap, DYNAMIC_TYPE_TMP_BUFFER);
+            if (saltTmp == NULL)
+                return MEMORY_E;
+        #endif
+            salt = saltTmp;
+
+            if ((ret = wc_RNG_GenerateBlock(rng, saltTmp, saltSz)) != 0) {
+                WOLFSSL_MSG("Error generating random salt");
+#ifdef WOLFSSL_SMALL_STACK
+                if (saltTmp != NULL)
+                    XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+                return ret;
+            }
+        }
+
+
+        /* leave room for a sequence (contains salt and iterations int) */
+        inOutIdx += MAX_SEQ_SZ; sz = 0;
+        inOutIdx += MAX_ALGO_SZ;
+
+        /* place salt in buffer */
+        out[inOutIdx++] = ASN_OCTET_STRING; sz++;
+        tmpSz = SetLength(saltSz, out + inOutIdx);
+        inOutIdx += tmpSz; sz += tmpSz;
+        XMEMCPY(out + inOutIdx, salt, saltSz);
+        inOutIdx += saltSz; sz += saltSz;
+
+        /* place iteration count in buffer */
+        ret = SetShortInt(out, &inOutIdx, itt, *outSz);
+        if (ret < 0) {
+            return ret;
+        }
+        sz += (word32)ret;
+
+        /* wind back index and set sequence then clean up buffer */
+        inOutIdx -= (sz + MAX_SEQ_SZ);
+        tmpSz = SetSequence(sz, out + inOutIdx);
+        XMEMMOVE(out + inOutIdx + tmpSz, out + inOutIdx + MAX_SEQ_SZ, sz);
+        totalSz += tmpSz + sz; sz += tmpSz;
+
+        /* add in algo ID */
+        inOutIdx -= MAX_ALGO_SZ;
+        tmpSz =  SetAlgoID(id, out + inOutIdx, oidPBEType, sz);
+        XMEMMOVE(out + inOutIdx + tmpSz, out + inOutIdx + MAX_ALGO_SZ, sz);
+        totalSz += tmpSz; inOutIdx += tmpSz + sz;
+
+        /* octet string containing encrypted key */
+        out[inOutIdx++] = ASN_OCTET_STRING; totalSz++;
+    }
+
+    /* check key type and get OID if ECC */
+    if ((ret = wc_GetKeyOID(key, keySz, &curveOID, &oidSz, &algoID, heap))< 0) {
+            return ret;
+    }
+
+    /* PKCS#8 wrapping around key */
+    if (wc_CreatePKCS8Key(NULL, &tmpSz, key, keySz, algoID, curveOID, oidSz)
+            != LENGTH_ONLY_E) {
+#ifdef WOLFSSL_SMALL_STACK
+        if (saltTmp != NULL)
+            XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return MEMORY_E;
+            }
+
+    /* check if should return max size */
+    if (out == NULL) {
+        /* account for salt size */
+        if (salt == NULL || saltSz <= 0) {
+            tmpSz += MAX_SALT_SIZE;
+        }
+        else {
+            tmpSz += saltSz;
+        }
+
+        /* plus 3 for tags */
+        *outSz = tmpSz + MAX_ALGO_SZ + MAX_LENGTH_SZ +MAX_LENGTH_SZ + MAX_SEQ_SZ
+            + MAX_LENGTH_SZ + MAX_SEQ_SZ + 3;
+        return LENGTH_ONLY_E;
+        }
+
+    /* reserve buffer for crypto and make sure it supports full blocks */
+    tmp = (byte*)XMALLOC(tmpSz + (blockSz-1), heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (tmp == NULL) {
+    #ifdef WOLFSSL_SMALL_STACK
+        if (saltTmp != NULL)
+            XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return MEMORY_E;
+    }
+
+    if ((ret = wc_CreatePKCS8Key(tmp, &tmpSz, key, keySz, algoID, curveOID,
+                    oidSz)) < 0) {
+        XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+        WOLFSSL_MSG("Error wrapping key with PKCS#8");
+    #ifdef WOLFSSL_SMALL_STACK
+        if (saltTmp != NULL)
+            XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+        return ret;
+    }
+    tmpSz = ret;
+
+    /* adjust size to pad */
+    tmpSz = Pkcs8Pad(tmp, tmpSz, blockSz);
+
+#ifdef WOLFSSL_SMALL_STACK
+    cbcIv = (byte*)XMALLOC(MAX_IV_SIZE, heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (cbcIv == NULL) {
+        if (saltTmp != NULL)
+            XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(salt, heap, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+        }
+#endif
+
+    /* encrypt PKCS#8 wrapped key */
+    if ((ret = wc_CryptKey(password, passwordSz, salt, saltSz, itt, id,
+               tmp, tmpSz, version, cbcIv, 1)) < 0) {
+        XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+        WOLFSSL_MSG("Error encrypting key");
+#ifdef WOLFSSL_SMALL_STACK
+        if (saltTmp != NULL)
+            XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+        if (cbcIv != NULL)
+            XFREE(cbcIv, heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ret;  /* encryption failure */
+    }
+    totalSz += tmpSz;
+
+#ifdef WOLFSSL_SMALL_STACK
+    if (saltTmp != NULL)
+        XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (cbcIv != NULL)
+        XFREE(cbcIv, heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    if (*outSz < inOutIdx + tmpSz + MAX_LENGTH_SZ) {
+        XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+        return BUFFER_E;
+}
+
+    /* set length of key and copy over encrypted key */
+    seqSz = SetLength(tmpSz, out + inOutIdx);
+    inOutIdx += seqSz; totalSz += seqSz;
+    XMEMCPY(out + inOutIdx, tmp, tmpSz);
+    XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+
+    /* set total size at beginning */
+    sz = SetSequence(totalSz, out);
+    XMEMMOVE(out + sz, out + MAX_SEQ_SZ, totalSz);
+
+    (void)rng;
+
+    return totalSz + sz;
+}
+
+static int GetAlgoV2(int encAlgId, const byte** oid, int *len, int* id,
+                     int *blkSz)
+{
+    int ret = 0;
+
+    switch (encAlgId) {
+#if !defined(NO_DES3) && !defined(NO_SHA)
+    case DESb:
+        *len = sizeof(blkDesCbcOid);
+        *oid = blkDesCbcOid;
+        *id = PBE_SHA1_DES;
+        *blkSz = 8;
+        break;
+    case DES3b:
+        *len = sizeof(blkDes3CbcOid);
+        *oid = blkDes3CbcOid;
+        *id = PBE_SHA1_DES3;
+        *blkSz = 8;
+        break;
+#endif
+#if defined(WOLFSSL_AES_256) && defined(HAVE_AES_CBC)
+    case AES256CBCb:
+        *len = sizeof(blkAes256CbcOid);
+        *oid = blkAes256CbcOid;
+        *id = PBE_AES256_CBC;
+        *blkSz = 16;
+        break;
+#endif
+    default:
+        (void)len;
+        (void)oid;
+        (void)id;
+        (void)blkSz;
+        ret = ALGO_ID_E;
+    }
+
+    return ret;
+        }
+
+/* Converts Encrypted PKCS#8 to 'traditional' (i.e. PKCS#8 removed from
+ * decrypted key.)
+ */
+int TraditionalEnc(byte* key, word32 keySz, byte* out, word32* outSz,
+        const char* password, int passwordSz, int vPKCS, int vAlgo,
+        int encAlgId, byte* salt, word32 saltSz, int itt, WC_RNG* rng,
+        void* heap)
+{
+    int ret = 0;
+    int version, blockSz, id;
+    word32 idx = 0, encIdx;
+#ifdef WOLFSSL_SMALL_STACK
+    byte* saltTmp = NULL;
+#else
+    byte saltTmp[MAX_SALT_SIZE];
+#endif
+    byte cbcIv[MAX_IV_SIZE];
+    byte *pkcs8Key = NULL;
+    word32 pkcs8KeySz, padSz = 0;
+    int algId;
+    const byte* curveOid = NULL;
+    word32 curveOidSz = 0;
+    const byte* pbeOid = NULL;
+    word32 pbeOidSz;
+    const byte* encOid = NULL;
+    int encOidSz = 0;
+    word32 pbeLen = 0, kdfLen = 0, encLen = 0;
+    word32 innerLen = 0, outerLen;
+
+    ret = CheckAlgo(vPKCS, vAlgo, &id, &version, &blockSz);
+    /* create random salt if one not provided */
+    if (ret == 0 && (salt == NULL || saltSz <= 0)) {
+        saltSz = 8;
+    #ifdef WOLFSSL_SMALL_STACK
+        saltTmp = (byte*)XMALLOC(saltSz, heap, DYNAMIC_TYPE_TMP_BUFFER);
+        if (saltTmp == NULL)
+            return MEMORY_E;
+    #endif
+        salt = saltTmp;
+
+        if ((ret = wc_RNG_GenerateBlock(rng, saltTmp, saltSz)) != 0) {
+            WOLFSSL_MSG("Error generating random salt");
+        #ifdef WOLFSSL_SMALL_STACK
+            XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+        #endif
+            return ret;
+    }
+    }
+
+    if (ret == 0) {
+        /* check key type and get OID if ECC */
+        ret = wc_GetKeyOID(key, keySz, &curveOid, &curveOidSz, &algId, heap);
+        if (ret == 1)
+            ret = 0;
+                }
+    if (ret == 0) {
+        ret = wc_CreatePKCS8Key(NULL, &pkcs8KeySz, key, keySz, algId, curveOid,
+                                                                    curveOidSz);
+        if (ret == LENGTH_ONLY_E)
+            ret = 0;
+                }
+    if (ret == 0) {
+        pkcs8Key = (byte*)XMALLOC(pkcs8KeySz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (pkcs8Key == NULL)
+            ret = MEMORY_E;
+            }
+    if (ret == 0) {
+        ret = wc_CreatePKCS8Key(pkcs8Key, &pkcs8KeySz, key, keySz, algId,
+                                                          curveOid, curveOidSz);
+        if (ret >= 0) {
+            pkcs8KeySz = ret;
+            ret = 0;
+            }
+        }
+
+    if (ret == 0 && version == PKCS5v2)
+        ret = GetAlgoV2(encAlgId, &encOid, &encOidSz, &id, &blockSz);
+
+    if (ret == 0) {
+        padSz = (blockSz - (pkcs8KeySz & (blockSz - 1))) & (blockSz - 1);
+        /* inner = OCT salt INT itt */
+        innerLen = 2 + saltSz + 2 + (itt < 256 ? 1 : 2);
+
+        if (version != PKCS5v2) {
+            pbeOid = OidFromId(id, oidPBEType, &pbeOidSz);
+            /* pbe = OBJ pbse1 SEQ [ inner ] */
+            pbeLen = 2 + pbeOidSz + 2 + innerLen;
+        }
+        else {
+            pbeOid = pbes2;
+            pbeOidSz = sizeof(pbes2);
+            /* kdf = OBJ pbkdf2 [ SEQ innerLen ] */
+            kdfLen = 2 + sizeof(pbkdf2Oid) + 2 + innerLen;
+            /* enc = OBJ enc_alg OCT iv */
+            encLen = 2 + encOidSz + 2 + blockSz;
+            /* pbe = OBJ pbse2 SEQ [ SEQ [ kdf ] SEQ [ enc ] ] */
+            pbeLen = 2 + sizeof(pbes2) + 2 + 2 + kdfLen + 2 + encLen;
+
+            ret = wc_RNG_GenerateBlock(rng, cbcIv, blockSz);
+        }
+    }
+    if (ret == 0) {
+        /* outer = SEQ [ pbe ] OCT encrypted_PKCS#8_key */
+        outerLen = 2 + pbeLen;
+        outerLen += SetOctetString(pkcs8KeySz + padSz, out);
+        outerLen += pkcs8KeySz + padSz;
+
+        idx += SetSequence(outerLen, out + idx);
+
+        encIdx = idx + outerLen - pkcs8KeySz - padSz;
+        /* Put Encrypted content in place. */
+        XMEMCPY(out + encIdx, pkcs8Key, pkcs8KeySz);
+        if (padSz > 0) {
+            XMEMSET(out + encIdx + pkcs8KeySz, padSz, padSz);
+            pkcs8KeySz += padSz;
+            }
+        ret = wc_CryptKey(password, passwordSz, salt, saltSz, itt, id,
+                                   out + encIdx, pkcs8KeySz, version, cbcIv, 1);
+            }
+    if (ret == 0) {
+        if (version != PKCS5v2) {
+            /* PBE algorithm */
+            idx += SetSequence(pbeLen, out + idx);
+            idx += SetObjectId(pbeOidSz, out + idx);
+            XMEMCPY(out + idx, pbeOid, pbeOidSz);
+            idx += pbeOidSz;
+        }
+        else {
+            /* PBES2 algorithm identifier */
+            idx += SetSequence(pbeLen, out + idx);
+            idx += SetObjectId(pbeOidSz, out + idx);
+            XMEMCPY(out + idx, pbeOid, pbeOidSz);
+            idx += pbeOidSz;
+            /* PBES2 Parameters: SEQ [ kdf ] SEQ [ enc ] */
+            idx += SetSequence(2 + kdfLen + 2 + encLen, out + idx);
+            /* KDF Algorithm Identifier */
+            idx += SetSequence(kdfLen, out + idx);
+            idx += SetObjectId(sizeof(pbkdf2Oid), out + idx);
+            XMEMCPY(out + idx, pbkdf2Oid, sizeof(pbkdf2Oid));
+            idx += sizeof(pbkdf2Oid);
+        }
+        idx += SetSequence(innerLen, out + idx);
+        idx += SetOctetString(saltSz, out + idx);
+        XMEMCPY(out + idx, salt, saltSz); idx += saltSz;
+        ret = SetShortInt(out, &idx, itt, *outSz);
+        if (ret > 0)
+            ret = 0;
+        }
+    if (ret == 0) {
+        if (version == PKCS5v2) {
+            /* Encryption Algorithm Identifier */
+            idx += SetSequence(encLen, out + idx);
+            idx += SetObjectId(encOidSz, out + idx);
+            XMEMCPY(out + idx, encOid, encOidSz);
+            idx += encOidSz;
+            /* Encryption Algorithm Parameter: CBC IV */
+            idx += SetOctetString(blockSz, out + idx);
+            XMEMCPY(out + idx, cbcIv, blockSz);
+            idx += blockSz;
+        }
+        idx += SetOctetString(pkcs8KeySz, out + idx);
+        /* Default PRF - no need to write out OID */
+        idx += pkcs8KeySz;
+
+        ret = idx;
+    }
+
+    if (pkcs8Key != NULL) {
+        ForceZero(pkcs8Key, pkcs8KeySz);
+        XFREE(pkcs8Key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        }
+#ifdef WOLFSSL_SMALL_STACK
+    if (saltTmp != NULL) {
+        XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+    }
+#endif
+
+    (void)rng;
+
+    return ret;
+}
 
 /* Remove Encrypted PKCS8 header, move beginning of traditional to beginning
    of input */
-int ToTraditionalEnc(byte* input, word32 sz,const char* password,int passwordSz)
-{
-    word32 inOutIdx = 0, oid;
+int ToTraditionalEnc(byte* input, word32 sz,const char* password,
+                     int passwordSz, word32* algId)
+{
+    word32 inOutIdx = 0, seqEnd, oid;
     int    ret = 0, first, second, length = 0, version, saltSz, id;
-    int    iterations = 0;
+    int    iterations = 0, keySz = 0;
 #ifdef WOLFSSL_SMALL_STACK
     byte*  salt = NULL;
@@ -2536,9 +3326,14 @@
 #endif
 
+    if (passwordSz < 0) {
+        WOLFSSL_MSG("Bad password size");
+        return BAD_FUNC_ARG;
+    }
+
     if (GetSequence(input, &inOutIdx, &length, sz) < 0) {
         ERROR_OUT(ASN_PARSE_E, exit_tte);
     }
 
-    if (GetAlgoId(input, &inOutIdx, &oid, oidSigType, sz) < 0) {
+    if (GetAlgoId(input, &inOutIdx, &oid, oidIgnoreType, sz) < 0) {
         ERROR_OUT(ASN_PARSE_E, exit_tte);
     }
@@ -2547,5 +3342,5 @@
     second = input[inOutIdx - 1];   /* version.algo, algo id last byte */
 
-    if (CheckAlgo(first, second, &id, &version) < 0) {
+    if (CheckAlgo(first, second, &id, &version, NULL) < 0) {
         ERROR_OUT(ASN_INPUT_E, exit_tte); /* Algo ID error */
     }
@@ -2568,4 +3363,7 @@
         ERROR_OUT(ASN_PARSE_E, exit_tte);
     }
+    /* Find the end of this SEQUENCE so we can check for the OPTIONAL and
+     * DEFAULT items. */
+    seqEnd = inOutIdx + length;
 
     ret = GetOctetString(input, &inOutIdx, &saltSz, sz);
@@ -2591,4 +3389,18 @@
     }
 
+    /* OPTIONAL key length */
+    if (seqEnd > inOutIdx && input[inOutIdx] == ASN_INTEGER) {
+        if (GetShortInt(input, &inOutIdx, &keySz, sz) < 0) {
+            ERROR_OUT(ASN_PARSE_E, exit_tte);
+        }
+    }
+
+    /* DEFAULT HMAC is SHA-1 */
+    if (seqEnd > inOutIdx) {
+        if (GetAlgoId(input, &inOutIdx, &oid, oidHmacType, sz) < 0) {
+            ERROR_OUT(ASN_PARSE_E, exit_tte);
+        }
+    }
+
 #ifdef WOLFSSL_SMALL_STACK
     cbcIv = (byte*)XMALLOC(MAX_IV_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
@@ -2600,10 +3412,9 @@
     if (version == PKCS5v2) {
         /* get encryption algo */
-        /* JOHN: New type. Need a little more research. */
         if (GetAlgoId(input, &inOutIdx, &oid, oidBlkType, sz) < 0) {
             ERROR_OUT(ASN_PARSE_E, exit_tte);
         }
 
-        if (CheckAlgoV2(oid, &id) < 0) {
+        if (CheckAlgoV2(oid, &id, NULL) < 0) {
             ERROR_OUT(ASN_PARSE_E, exit_tte); /* PKCS v2 algo id error */
         }
@@ -2625,6 +3436,6 @@
         goto exit_tte;
 
-    ret = DecryptKey(password, passwordSz, salt, saltSz, iterations, id,
-                                   input + inOutIdx, length, version, cbcIv);
+    ret = wc_CryptKey(password, passwordSz, salt, saltSz, iterations, id,
+                   input + inOutIdx, length, version, cbcIv, 0);
 
 exit_tte:
@@ -2636,5 +3447,5 @@
     if (ret == 0) {
         XMEMMOVE(input, input + inOutIdx, length);
-        ret = ToTraditional(input, length);
+        ret = ToTraditional_ex(input, length, algId);
     }
 
@@ -2642,11 +3453,229 @@
 }
 
-/* decrypt PKCS */
-int DecryptContent(byte* input, word32 sz,const char* password,int passwordSz)
-{
-    word32 inOutIdx = 0, oid;
+
+/* encrypt PKCS 12 content
+ *
+ * NOTE: if out is NULL then outSz is set with the total buffer size needed and
+ *       the error value LENGTH_ONLY_E is returned.
+ *
+ * input      data to encrypt
+ * inputSz    size of input buffer
+ * out        buffer to hold the result
+ * outSz      size of out buffer
+ * password   password if used. Can be NULL for no password
+ * passwordSz size of password buffer
+ * vPKCS      version of PKCS i.e. PKCS5v2
+ * vAlgo      algorithm version
+ * salt       buffer holding salt if used. If NULL then a random salt is created
+ * saltSz     size of salt buffer if it is not NULL
+ * itt        number of iterations used
+ * rng        random number generator to use
+ * heap       possible heap hint for mallocs/frees
+ *
+ * returns the total size of encrypted content on success.
+ */
+int EncryptContent(byte* input, word32 inputSz, byte* out, word32* outSz,
+        const char* password, int passwordSz, int vPKCS, int vAlgo,
+        byte* salt, word32 saltSz, int itt, WC_RNG* rng, void* heap)
+{
+    word32 sz;
+    word32 inOutIdx = 0;
+    word32 tmpIdx   = 0;
+    word32 totalSz  = 0;
+    word32 seqSz;
+    int    ret;
+    int    version, id, blockSz = 0;
+#ifdef WOLFSSL_SMALL_STACK
+    byte*  saltTmp = NULL;
+    byte*  cbcIv = NULL;
+#else
+    byte   saltTmp[MAX_SALT_SIZE];
+    byte   cbcIv[MAX_IV_SIZE];
+#endif
+
+    (void)heap;
+
+    WOLFSSL_ENTER("EncryptContent()");
+
+    if (CheckAlgo(vPKCS, vAlgo, &id, &version, &blockSz) < 0)
+        return ASN_INPUT_E;  /* Algo ID error */
+
+    if (version == PKCS5v2) {
+        WOLFSSL_MSG("PKCS#5 version 2 not supported yet");
+        return BAD_FUNC_ARG;
+        }
+
+    if (saltSz > MAX_SALT_SIZE)
+        return ASN_PARSE_E;
+
+    if (outSz == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    if (out == NULL) {
+        sz = inputSz;
+        switch (id) {
+        #if !defined(NO_DES3) && (!defined(NO_MD5) || !defined(NO_SHA))
+            case PBE_MD5_DES:
+            case PBE_SHA1_DES:
+            case PBE_SHA1_DES3:
+                /* set to block size of 8 for DES operations. This rounds up
+                 * to the nearest multiple of 8 */
+                sz &= 0xfffffff8;
+                sz += 8;
+                break;
+        #endif /* !NO_DES3 && (!NO_MD5 || !NO_SHA) */
+        #if !defined(NO_RC4) && !defined(NO_SHA)
+            case PBE_SHA1_RC4_128:
+                break;
+        #endif
+            case -1:
+                break;
+
+            default:
+                return ALGO_ID_E;
+        }
+
+        if (saltSz <= 0) {
+            sz += MAX_SALT_SIZE;
+        }
+        else {
+            sz += saltSz;
+        }
+
+        /* add 2 for tags */
+        totalSz = sz + MAX_ALGO_SZ + MAX_SEQ_SZ + MAX_LENGTH_SZ +
+            MAX_LENGTH_SZ + MAX_LENGTH_SZ + MAX_SHORT_SZ + 2;
+
+        /* adjust size to pad */
+        totalSz = Pkcs8Pad(NULL, totalSz, blockSz);
+
+        /* return result */
+        *outSz = totalSz;
+
+        return LENGTH_ONLY_E;
+    }
+
+    if (inOutIdx + MAX_ALGO_SZ + MAX_SEQ_SZ + 1 > *outSz)
+        return BUFFER_E;
+
+    sz = SetAlgoID(id, out + inOutIdx, oidPBEType, 0);
+    inOutIdx += sz; totalSz += sz;
+    tmpIdx = inOutIdx;
+    tmpIdx += MAX_SEQ_SZ; /* save room for salt and itter sequence */
+    out[tmpIdx++] = ASN_OCTET_STRING;
+
+    /* create random salt if one not provided */
+    if (salt == NULL || saltSz <= 0) {
+        saltSz = 8;
+    #ifdef WOLFSSL_SMALL_STACK
+        saltTmp = (byte*)XMALLOC(saltSz, heap, DYNAMIC_TYPE_TMP_BUFFER);
+        if (saltTmp == NULL)
+            return MEMORY_E;
+    #endif
+        salt = saltTmp;
+
+        if ((ret = wc_RNG_GenerateBlock(rng, saltTmp, saltSz)) != 0) {
+            WOLFSSL_MSG("Error generating random salt");
+        #ifdef WOLFSSL_SMALL_STACK
+            XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+        #endif
+            return ret;
+        }
+    }
+
+    if (tmpIdx + MAX_LENGTH_SZ + saltSz + MAX_SHORT_SZ > *outSz) {
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+        return BUFFER_E;
+    }
+
+    sz = SetLength(saltSz, out + tmpIdx);
+    tmpIdx += sz;
+
+    XMEMCPY(out + tmpIdx, salt, saltSz);
+    tmpIdx += saltSz;
+
+    /* place iteration setting in buffer */
+    ret = SetShortInt(out, &tmpIdx, itt, *outSz);
+    if (ret < 0) {
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+        return ret;
+    }
+
+    /* rewind and place sequence */
+    sz = tmpIdx - inOutIdx - MAX_SEQ_SZ;
+    seqSz = SetSequence(sz, out + inOutIdx);
+    XMEMMOVE(out + inOutIdx + seqSz, out + inOutIdx + MAX_SEQ_SZ, sz);
+    inOutIdx += seqSz; totalSz += seqSz;
+    inOutIdx += sz; totalSz += sz;
+
+#ifdef WOLFSSL_SMALL_STACK
+    cbcIv = (byte*)XMALLOC(MAX_IV_SIZE, heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (cbcIv == NULL) {
+        XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+#endif
+
+    if (inOutIdx + 1 + MAX_LENGTH_SZ + inputSz > *outSz)
+        return BUFFER_E;
+
+    out[inOutIdx++] = ASN_CONTEXT_SPECIFIC | 0; totalSz++;
+    sz = SetLength(inputSz, out + inOutIdx);
+    inOutIdx += sz; totalSz += sz;
+
+    /* get pad size and verify buffer room */
+    sz = Pkcs8Pad(NULL, inputSz, blockSz);
+    if (sz + inOutIdx > *outSz)
+        return BUFFER_E;
+
+    /* copy input to output buffer and pad end */
+    XMEMCPY(out + inOutIdx, input, inputSz);
+    sz = Pkcs8Pad(out + inOutIdx, inputSz, blockSz);
+    totalSz += sz;
+
+    /* encrypt */
+    if ((ret = wc_CryptKey(password, passwordSz, salt, saltSz, itt, id,
+                   out + inOutIdx, sz, version, cbcIv, 1)) < 0) {
+
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(cbcIv,   heap, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+        return ret;  /* encrypt failure */
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(cbcIv,   heap, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    (void)rng;
+
+    return totalSz;
+}
+
+
+/* decrypt PKCS
+ *
+ * NOTE: input buffer is overwritten with decrypted data!
+ *
+ * input[in/out] data to decrypt and results are written to
+ * sz            size of input buffer
+ * password      password if used. Can be NULL for no password
+ * passwordSz    size of password buffer
+ *
+ * returns the total size of decrypted content on success.
+ */
+int DecryptContent(byte* input, word32 sz,const char* password, int passwordSz)
+{
+    word32 inOutIdx = 0, seqEnd, oid;
     int    ret = 0;
     int    first, second, length = 0, version, saltSz, id;
-    int    iterations = 0;
+    int    iterations = 0, keySz = 0;
 #ifdef WOLFSSL_SMALL_STACK
     byte*  salt = NULL;
@@ -2657,5 +3686,5 @@
 #endif
 
-    if (GetAlgoId(input, &inOutIdx, &oid, oidSigType, sz) < 0) {
+    if (GetAlgoId(input, &inOutIdx, &oid, oidIgnoreType, sz) < 0) {
         ERROR_OUT(ASN_PARSE_E, exit_dc);
     }
@@ -2664,5 +3693,5 @@
     second = input[inOutIdx - 1];   /* version.algo, algo id last byte */
 
-    if (CheckAlgo(first, second, &id, &version) < 0) {
+    if (CheckAlgo(first, second, &id, &version, NULL) < 0) {
         ERROR_OUT(ASN_INPUT_E, exit_dc); /* Algo ID error */
     }
@@ -2685,4 +3714,7 @@
         ERROR_OUT(ASN_PARSE_E, exit_dc);
     }
+    /* Find the end of this SEQUENCE so we can check for the OPTIONAL and
+     * DEFAULT items. */
+    seqEnd = inOutIdx + length;
 
     ret = GetOctetString(input, &inOutIdx, &saltSz, sz);
@@ -2708,4 +3740,18 @@
     }
 
+    /* OPTIONAL key length */
+    if (seqEnd > inOutIdx && input[inOutIdx] == ASN_INTEGER) {
+        if (GetShortInt(input, &inOutIdx, &keySz, sz) < 0) {
+            ERROR_OUT(ASN_PARSE_E, exit_dc);
+        }
+    }
+
+    /* DEFAULT HMAC is SHA-1 */
+    if (seqEnd > inOutIdx) {
+        if (GetAlgoId(input, &inOutIdx, &oid, oidHmacType, sz) < 0) {
+            ERROR_OUT(ASN_PARSE_E, exit_dc);
+        }
+    }
+
 #ifdef WOLFSSL_SMALL_STACK
     cbcIv = (byte*)XMALLOC(MAX_IV_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
@@ -2717,10 +3763,9 @@
     if (version == PKCS5v2) {
         /* get encryption algo */
-        /* JOHN: New type. Need a little more research. */
         if (GetAlgoId(input, &inOutIdx, &oid, oidBlkType, sz) < 0) {
             ERROR_OUT(ASN_PARSE_E, exit_dc);
         }
 
-        if (CheckAlgoV2(oid, &id) < 0) {
+        if (CheckAlgoV2(oid, &id, NULL) < 0) {
             ERROR_OUT(ASN_PARSE_E, exit_dc); /* PKCS v2 algo id error */
         }
@@ -2730,4 +3775,8 @@
             goto exit_dc;
 
+        if (length > MAX_IV_SIZE) {
+            ERROR_OUT(ASN_PARSE_E, exit_dc);
+        }
+
         XMEMCPY(cbcIv, &input[inOutIdx], length);
         inOutIdx += length;
@@ -2742,6 +3791,6 @@
     }
 
-    ret = DecryptKey(password, passwordSz, salt, saltSz, iterations, id,
-                                   input + inOutIdx, length, version, cbcIv);
+    ret = wc_CryptKey(password, passwordSz, salt, saltSz, iterations, id,
+                   input + inOutIdx, length, version, cbcIv, 0);
 
 exit_dc:
@@ -2764,20 +3813,18 @@
 
 #ifndef HAVE_USER_RSA
-int wc_RsaPublicKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key,
-                       word32 inSz)
-{
+int wc_RsaPublicKeyDecode_ex(const byte* input, word32* inOutIdx, word32 inSz,
+    const byte** n, word32* nSz, const byte** e, word32* eSz)
+{
+    int ret = 0;
     int  length;
 #if defined(OPENSSL_EXTRA) || defined(RSA_DECODE_EXTRA)
     byte b;
 #endif
-    int ret;
-
-    if (input == NULL || inOutIdx == NULL || key == NULL)
+
+    if (input == NULL || inOutIdx == NULL)
         return BAD_FUNC_ARG;
 
     if (GetSequence(input, inOutIdx, &length, inSz) < 0)
         return ASN_PARSE_E;
-
-    key->type = RSA_PUBLIC;
 
 #if defined(OPENSSL_EXTRA) || defined(RSA_DECODE_EXTRA)
@@ -2795,4 +3842,7 @@
 
         /* Option NULL ASN.1 tag */
+        if (*inOutIdx  >= inSz) {
+            return BUFFER_E;
+        }
         if (input[*inOutIdx] == ASN_TAG_NULL) {
             ret = GetASNNull(input, inOutIdx, inSz);
@@ -2811,18 +3861,45 @@
 #endif /* OPENSSL_EXTRA */
 
-    if (GetInt(&key->n,  input, inOutIdx, inSz) < 0)
+    /* Get modulus */
+    ret = GetASNInt(input, inOutIdx, &length, inSz);
+    if (ret < 0) {
         return ASN_RSA_KEY_E;
-    if (GetInt(&key->e,  input, inOutIdx, inSz) < 0) {
-        mp_clear(&key->n);
+    }
+    if (nSz)
+        *nSz = length;
+    if (n)
+        *n = &input[*inOutIdx];
+    *inOutIdx += length;
+
+    /* Get exponent */
+    ret = GetASNInt(input, inOutIdx, &length, inSz);
+    if (ret < 0) {
         return ASN_RSA_KEY_E;
     }
-
-#ifdef WOLFSSL_XILINX_CRYPT
-    if (wc_InitRsaHw(key) != 0) {
-        return BAD_STATE_E;
-    }
-#endif
-
-    return 0;
+    if (eSz)
+        *eSz = length;
+    if (e)
+        *e = &input[*inOutIdx];
+    *inOutIdx += length;
+
+    return ret;
+    }
+
+int wc_RsaPublicKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key,
+                       word32 inSz)
+{
+    int ret;
+    const byte *n = NULL, *e = NULL;
+    word32 nSz = 0, eSz = 0;
+
+    if (key == NULL)
+        return BAD_FUNC_ARG;
+
+    ret = wc_RsaPublicKeyDecode_ex(input, inOutIdx, inSz, &n, &nSz, &e, &eSz);
+    if (ret == 0) {
+        ret = wc_RsaPublicKeyDecodeRaw(n, nSz, e, eSz, key);
+    }
+
+    return ret;
 }
 
@@ -2843,4 +3920,10 @@
         return ASN_GETINT_E;
     }
+#ifdef HAVE_WOLF_BIGINT
+    if ((int)nSz > 0 && wc_bigint_from_unsigned_bin(&key->n.raw, n, nSz) != 0) {
+        mp_clear(&key->n);
+        return ASN_GETINT_E;
+    }
+#endif /* HAVE_WOLF_BIGINT */
 
     if (mp_init(&key->e) != MP_OKAY) {
@@ -2854,4 +3937,11 @@
         return ASN_GETINT_E;
     }
+#ifdef HAVE_WOLF_BIGINT
+    if ((int)eSz > 0 && wc_bigint_from_unsigned_bin(&key->e.raw, e, eSz) != 0) {
+        mp_clear(&key->n);
+        mp_clear(&key->e);
+        return ASN_GETINT_E;
+    }
+#endif /* HAVE_WOLF_BIGINT */
 
 #ifdef WOLFSSL_XILINX_CRYPT
@@ -2864,5 +3954,5 @@
 }
 #endif /* HAVE_USER_RSA */
-#endif
+#endif /* !NO_RSA */
 
 #ifndef NO_DH
@@ -2994,5 +4084,5 @@
 
 /* Release Tmp DSA resources */
-static INLINE void FreeTmpDsas(byte** tmps, void* heap)
+static WC_INLINE void FreeTmpDsas(byte** tmps, void* heap)
 {
     int i;
@@ -3076,5 +4166,6 @@
 
 
-void InitDecodedCert(DecodedCert* cert, byte* source, word32 inSz, void* heap)
+void InitDecodedCert(DecodedCert* cert,
+                     const byte* source, word32 inSz, void* heap)
 {
     if (cert != NULL) {
@@ -3136,5 +4227,5 @@
         XFREE(cert->subjectCN, cert->heap, DYNAMIC_TYPE_SUBJECT_CN);
     if (cert->pubKeyStored == 1)
-        XFREE(cert->publicKey, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+        XFREE((void*)cert->publicKey, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY);
     if (cert->weOwnAltNames && cert->altNames)
         FreeAltNames(cert->altNames, cert->heap);
@@ -3152,5 +4243,5 @@
     XFREE(cert->hwSerialNum, cert->heap, DYNAMIC_TYPE_X509_EXT);
 #endif /* WOLFSSL_SEP */
-#ifdef OPENSSL_EXTRA
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
     if (cert->issuerName.fullName != NULL)
         XFREE(cert->issuerName.fullName, cert->heap, DYNAMIC_TYPE_X509);
@@ -3231,5 +4322,5 @@
 {
     int length;
-#ifdef HAVE_NTRU
+#if defined(HAVE_ECC) || defined(HAVE_NTRU)
     int tmpIdx = cert->srcIdx;
 #endif
@@ -3264,4 +4355,5 @@
             word32      rc;
             word32      remaining = cert->maxIdx - cert->srcIdx;
+            byte*       publicKey;
 #ifdef WOLFSSL_SMALL_STACK
             byte*       keyBlob = NULL;
@@ -3277,5 +4369,5 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-            keyBlob = (byte*)XMALLOC(MAX_NTRU_KEY_SZ, NULL,
+            keyBlob = (byte*)XMALLOC(MAX_NTRU_KEY_SZ, cert->heap,
                                      DYNAMIC_TYPE_TMP_BUFFER);
             if (keyBlob == NULL)
@@ -3287,5 +4379,5 @@
             if (rc != NTRU_OK) {
 #ifdef WOLFSSL_SMALL_STACK
-                XFREE(keyBlob, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(keyBlob, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
                 return ASN_NTRU_KEY_E;
@@ -3294,5 +4386,5 @@
             if ( (next - key) < 0) {
 #ifdef WOLFSSL_SMALL_STACK
-                XFREE(keyBlob, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(keyBlob, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
                 return ASN_NTRU_KEY_E;
@@ -3301,18 +4393,19 @@
             cert->srcIdx = tmpIdx + (int)(next - key);
 
-            cert->publicKey = (byte*) XMALLOC(keyLen, cert->heap,
+            publicKey = (byte*)XMALLOC(keyLen, cert->heap,
                                               DYNAMIC_TYPE_PUBLIC_KEY);
-            if (cert->publicKey == NULL) {
+            if (publicKey == NULL) {
 #ifdef WOLFSSL_SMALL_STACK
-                XFREE(keyBlob, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(keyBlob, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
                 return MEMORY_E;
             }
-            XMEMCPY(cert->publicKey, keyBlob, keyLen);
+            XMEMCPY(publicKey, keyBlob, keyLen);
+            cert->publicKey = publicKey;
             cert->pubKeyStored = 1;
             cert->pubKeySize   = keyLen;
 
 #ifdef WOLFSSL_SMALL_STACK
-            XFREE(keyBlob, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(keyBlob, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
 
@@ -3324,5 +4417,10 @@
         {
             int ret;
-
+            byte seq[5];
+            int pubLen = length + 1 + SetLength(length, seq);
+            byte* publicKey;
+
+            if (cert->source[cert->srcIdx] !=
+                                             (ASN_SEQUENCE | ASN_CONSTRUCTED)) {
             if (GetObjectId(cert->source, &cert->srcIdx,
                             &cert->pkCurveOID, oidCurveType, cert->maxIdx) < 0)
@@ -3337,14 +4435,16 @@
             if (ret != 0)
                 return ret;
-
-            cert->publicKey = (byte*)XMALLOC(length, cert->heap,
+            }
+
+            publicKey = (byte*)XMALLOC(pubLen, cert->heap,
                                              DYNAMIC_TYPE_PUBLIC_KEY);
-            if (cert->publicKey == NULL)
+            if (publicKey == NULL)
                 return MEMORY_E;
-            XMEMCPY(cert->publicKey, &cert->source[cert->srcIdx], length);
+            XMEMCPY(publicKey, &cert->source[tmpIdx], pubLen);
+            cert->publicKey = publicKey;
             cert->pubKeyStored = 1;
-            cert->pubKeySize   = length;
-
-            cert->srcIdx += length;
+            cert->pubKeySize   = pubLen;
+
+            cert->srcIdx = tmpIdx + pubLen;
 
             return 0;
@@ -3354,4 +4454,5 @@
         case ED25519k:
         {
+            byte* publicKey;
             int ret;
 
@@ -3363,9 +4464,10 @@
                 return ret;
 
-            cert->publicKey = (byte*) XMALLOC(length, cert->heap,
+            publicKey = (byte*) XMALLOC(length, cert->heap,
                                               DYNAMIC_TYPE_PUBLIC_KEY);
-            if (cert->publicKey == NULL)
+            if (publicKey == NULL)
                 return MEMORY_E;
-            XMEMCPY(cert->publicKey, &cert->source[cert->srcIdx], length);
+            XMEMCPY(publicKey, &cert->source[cert->srcIdx], length);
+            cert->publicKey = publicKey;
             cert->pubKeyStored = 1;
             cert->pubKeySize   = length;
@@ -3380,4 +4482,46 @@
     }
 }
+
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+WOLFSSL_LOCAL int OBJ_sn2nid(const char *sn)
+{
+    static const struct {
+        const char *sn;
+        int  nid;
+    } sn2nid[] = {
+        {WOLFSSL_COMMON_NAME, NID_commonName},
+        {WOLFSSL_COUNTRY_NAME, NID_countryName},
+        {WOLFSSL_LOCALITY_NAME, NID_localityName},
+        {WOLFSSL_STATE_NAME, NID_stateOrProvinceName},
+        {WOLFSSL_ORG_NAME, NID_organizationName},
+        {WOLFSSL_ORGUNIT_NAME, NID_organizationalUnitName},
+        {WOLFSSL_EMAIL_ADDR, NID_emailAddress},
+        {NULL, -1}};
+
+    int i;
+    WOLFSSL_ENTER("OBJ_osn2nid");
+    #ifdef HAVE_ECC
+    /* Nginx uses this OpenSSL string. */
+    if (XSTRNCMP(sn, "prime256v1", 10) == 0)
+        sn = "SECP256R1";
+    if (XSTRNCMP(sn, "secp384r1", 10) == 0)
+        sn = "SECP384R1";
+    /* find based on name and return NID */
+    for (i = 0; i < ecc_sets[i].size; i++) {
+        if (XSTRNCMP(sn, ecc_sets[i].name, ECC_MAXNAME) == 0) {
+            return ecc_sets[i].id;
+        }
+    }
+    #endif
+
+    for(i=0; sn2nid[i].sn != NULL; i++) {
+        if(XSTRNCMP(sn, sn2nid[i].sn, XSTRLEN(sn2nid[i].sn)) == 0) {
+            return sn2nid[i].nid;
+        }
+    }
+
+    return NID_undef;
+}
+#endif
 
 /* process NAME, either issuer or subject */
@@ -3390,7 +4534,8 @@
     byte*  hash;
     word32 idx;
-    #ifdef OPENSSL_EXTRA
+    #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
         DecodedName* dName =
                   (nameType == ISSUER) ? &cert->issuerName : &cert->subjectName;
+        int dcnum = 0;
     #endif /* OPENSSL_EXTRA */
 
@@ -3404,4 +4549,8 @@
         full = cert->subject;
         hash = cert->subjectHash;
+    }
+
+    if (cert->srcIdx >= cert->maxIdx) {
+        return BUFFER_E;
     }
 
@@ -3421,9 +4570,5 @@
         return ASN_PARSE_E;
 
-#ifdef NO_SHA
-    ret = wc_Sha256Hash(&cert->source[idx], length + cert->srcIdx - idx, hash);
-#else
-    ret = wc_ShaHash(&cert->source[idx], length + cert->srcIdx - idx, hash);
-#endif
+    ret = CalcHashId(&cert->source[idx], length + cert->srcIdx - idx, hash);
     if (ret != 0)
         return ret;
@@ -3432,5 +4577,5 @@
     idx = 0;
 
-#ifdef HAVE_PKCS7
+#if defined(HAVE_PKCS7) || defined(WOLFSSL_CERT_EXT)
     /* store pointer to raw issuer */
     if (nameType == ISSUER) {
@@ -3471,7 +4616,7 @@
         /* v1 name types */
         if (joint[0] == 0x55 && joint[1] == 0x04) {
+            const char*  copy = NULL;
+            int    strLen;
             byte   id;
-            byte   copy = FALSE;
-            int    strLen;
 
             cert->srcIdx += 2;
@@ -3496,10 +4641,6 @@
                 }
 
-                if (!tooBig) {
-                    XMEMCPY(&full[idx], "/CN=", 4);
-                    idx += 4;
-                    copy = TRUE;
-                }
-                #ifdef OPENSSL_EXTRA
+                copy = WOLFSSL_COMMON_NAME;
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     dName->cnIdx = cert->srcIdx;
                     dName->cnLen = strLen;
@@ -3507,9 +4648,5 @@
             }
             else if (id == ASN_SUR_NAME) {
-                if (!tooBig) {
-                    XMEMCPY(&full[idx], "/SN=", 4);
-                    idx += 4;
-                    copy = TRUE;
-                }
+                copy = WOLFSSL_SUR_NAME;
                 #ifdef WOLFSSL_CERT_GEN
                     if (nameType == SUBJECT) {
@@ -3519,5 +4656,5 @@
                     }
                 #endif /* WOLFSSL_CERT_GEN */
-                #ifdef OPENSSL_EXTRA
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     dName->snIdx = cert->srcIdx;
                     dName->snLen = strLen;
@@ -3525,9 +4662,5 @@
             }
             else if (id == ASN_COUNTRY_NAME) {
-                if (!tooBig) {
-                    XMEMCPY(&full[idx], "/C=", 3);
-                    idx += 3;
-                    copy = TRUE;
-                }
+                copy = WOLFSSL_COUNTRY_NAME;
                 #ifdef WOLFSSL_CERT_GEN
                     if (nameType == SUBJECT) {
@@ -3537,5 +4670,5 @@
                     }
                 #endif /* WOLFSSL_CERT_GEN */
-                #ifdef OPENSSL_EXTRA
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     dName->cIdx = cert->srcIdx;
                     dName->cLen = strLen;
@@ -3543,9 +4676,5 @@
             }
             else if (id == ASN_LOCALITY_NAME) {
-                if (!tooBig) {
-                    XMEMCPY(&full[idx], "/L=", 3);
-                    idx += 3;
-                    copy = TRUE;
-                }
+                copy = WOLFSSL_LOCALITY_NAME;
                 #ifdef WOLFSSL_CERT_GEN
                     if (nameType == SUBJECT) {
@@ -3555,5 +4684,5 @@
                     }
                 #endif /* WOLFSSL_CERT_GEN */
-                #ifdef OPENSSL_EXTRA
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     dName->lIdx = cert->srcIdx;
                     dName->lLen = strLen;
@@ -3561,9 +4690,5 @@
             }
             else if (id == ASN_STATE_NAME) {
-                if (!tooBig) {
-                    XMEMCPY(&full[idx], "/ST=", 4);
-                    idx += 4;
-                    copy = TRUE;
-                }
+                copy = WOLFSSL_STATE_NAME;
                 #ifdef WOLFSSL_CERT_GEN
                     if (nameType == SUBJECT) {
@@ -3573,5 +4698,5 @@
                     }
                 #endif /* WOLFSSL_CERT_GEN */
-                #ifdef OPENSSL_EXTRA
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     dName->stIdx = cert->srcIdx;
                     dName->stLen = strLen;
@@ -3579,9 +4704,5 @@
             }
             else if (id == ASN_ORG_NAME) {
-                if (!tooBig) {
-                    XMEMCPY(&full[idx], "/O=", 3);
-                    idx += 3;
-                    copy = TRUE;
-                }
+                copy = WOLFSSL_ORG_NAME;
                 #ifdef WOLFSSL_CERT_GEN
                     if (nameType == SUBJECT) {
@@ -3591,5 +4712,5 @@
                     }
                 #endif /* WOLFSSL_CERT_GEN */
-                #ifdef OPENSSL_EXTRA
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     dName->oIdx = cert->srcIdx;
                     dName->oLen = strLen;
@@ -3597,9 +4718,5 @@
             }
             else if (id == ASN_ORGUNIT_NAME) {
-                if (!tooBig) {
-                    XMEMCPY(&full[idx], "/OU=", 4);
-                    idx += 4;
-                    copy = TRUE;
-                }
+                copy = WOLFSSL_ORGUNIT_NAME;
                 #ifdef WOLFSSL_CERT_GEN
                     if (nameType == SUBJECT) {
@@ -3609,5 +4726,5 @@
                     }
                 #endif /* WOLFSSL_CERT_GEN */
-                #ifdef OPENSSL_EXTRA
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     dName->ouIdx = cert->srcIdx;
                     dName->ouLen = strLen;
@@ -3615,16 +4732,40 @@
             }
             else if (id == ASN_SERIAL_NUMBER) {
-                if (!tooBig) {
-                   XMEMCPY(&full[idx], "/serialNumber=", 14);
-                   idx += 14;
-                   copy = TRUE;
+                copy = WOLFSSL_SERIAL_NUMBER;
+                #ifdef WOLFSSL_CERT_GEN
+                    if (nameType == SUBJECT) {
+                        cert->subjectSND = (char*)&cert->source[cert->srcIdx];
+                        cert->subjectSNDLen = strLen;
+                        cert->subjectSNDEnc = b;
                 }
-                #ifdef OPENSSL_EXTRA
+                #endif /* WOLFSSL_CERT_GEN */
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     dName->snIdx = cert->srcIdx;
                     dName->snLen = strLen;
                 #endif /* OPENSSL_EXTRA */
             }
-
+        #ifdef WOLFSSL_CERT_EXT
+            else if (id == ASN_BUS_CAT) {
+                copy = WOLFSSL_BUS_CAT;
+            #ifdef WOLFSSL_CERT_GEN
+                if (nameType == SUBJECT) {
+                    cert->subjectBC = (char*)&cert->source[cert->srcIdx];
+                    cert->subjectBCLen = strLen;
+                    cert->subjectBCEnc = b;
+                }
+            #endif /* WOLFSSL_CERT_GEN */
+            #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+                dName->bcIdx = cert->srcIdx;
+                dName->bcLen = strLen;
+            #endif /* OPENSSL_EXTRA */
+            }
+        #endif /* WOLFSSL_CERT_EXT */
             if (copy && !tooBig) {
+                XMEMCPY(&full[idx], copy, XSTRLEN(copy));
+                idx += (word32)XSTRLEN(copy);
+            #ifdef WOLFSSL_WPAS
+                full[idx] = '=';
+                idx++;
+            #endif
                 XMEMCPY(&full[idx], &cert->source[cert->srcIdx], strLen);
                 idx += strLen;
@@ -3633,8 +4774,80 @@
             cert->srcIdx += strLen;
         }
+    #ifdef WOLFSSL_CERT_EXT
+        else if ((0 == XMEMCMP(&cert->source[cert->srcIdx], ASN_JOI_PREFIX,
+                               XSTRLEN(ASN_JOI_PREFIX))) &&
+                 ((cert->source[cert->srcIdx + XSTRLEN(ASN_JOI_PREFIX)] ==
+                         ASN_JOI_C) ||
+                  (cert->source[cert->srcIdx + XSTRLEN(ASN_JOI_PREFIX)] ==
+                          ASN_JOI_ST)))
+        {
+            int strLen;
+            byte id;
+            const char* copy = NULL;
+
+            cert->srcIdx += 10;
+            id = cert->source[cert->srcIdx++];
+            b = cert->source[cert->srcIdx++]; /* encoding */
+
+            if (GetLength(cert->source, &cert->srcIdx, &strLen,
+                          cert->maxIdx) < 0)
+                return ASN_PARSE_E;
+
+            if ((strLen + strlen(WOLFSSL_JOI_ST)) > (ASN_NAME_MAX - idx)) {
+                WOLFSSL_MSG("ASN Name too big, skipping");
+                tooBig = TRUE;
+            }
+
+            /* Check for jurisdiction of incorporation country name */
+            if (id == ASN_JOI_C) {
+                copy = WOLFSSL_JOI_C;
+                #ifdef WOLFSSL_CERT_GEN
+                    if (nameType == SUBJECT) {
+                        cert->subjectJC = (char*)&cert->source[cert->srcIdx];
+                        cert->subjectJCLen = strLen;
+                        cert->subjectJCEnc = b;
+                    }
+                #endif /* WOLFSSL_CERT_GEN */
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+                    dName->jcIdx = cert->srcIdx;
+                    dName->jcLen = strLen;
+                #endif /* OPENSSL_EXTRA */
+            }
+
+            /* Check for jurisdiction of incorporation state name */
+            else if (id == ASN_JOI_ST) {
+                copy = WOLFSSL_JOI_ST;
+                #ifdef WOLFSSL_CERT_GEN
+                    if (nameType == SUBJECT) {
+                        cert->subjectJS = (char*)&cert->source[cert->srcIdx];
+                        cert->subjectJSLen = strLen;
+                        cert->subjectJSEnc = b;
+                    }
+                #endif /* WOLFSSL_CERT_GEN */
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+                    dName->jsIdx = cert->srcIdx;
+                    dName->jsLen = strLen;
+                #endif /* OPENSSL_EXTRA */
+            }
+
+            if ((copy != NULL) && (tooBig != 1)) {
+                XMEMCPY(&full[idx], copy, XSTRLEN(copy));
+                idx += (word32)XSTRLEN(copy);
+            #ifdef WOLFSSL_WPAS
+                full[idx] = '=';
+                idx++;
+            #endif
+                XMEMCPY(&full[idx], &cert->source[cert->srcIdx], strLen);
+                idx += strLen;
+            }
+
+            cert->srcIdx += strLen;
+        }
+    #endif /* WOLFSSL_CERT_EXT */
         else {
             /* skip */
             byte email = FALSE;
-            byte uid   = FALSE;
+            byte pilot = FALSE;
+            byte id    = 0;
             int  adv;
 
@@ -3642,6 +4855,9 @@
                 email = TRUE;
 
-            if (joint[0] == 0x9  && joint[1] == 0x92)  /* uid id hdr */
-                uid = TRUE;
+            if (joint[0] == 0x9  && joint[1] == 0x92) { /* uid id hdr */
+                /* last value of OID is the type of pilot attribute */
+                id    = cert->source[cert->srcIdx + oidSz - 1];
+                pilot = TRUE;
+            }
 
             cert->srcIdx += oidSz + 1;
@@ -3671,5 +4887,5 @@
                     }
                 #endif /* WOLFSSL_CERT_GEN */
-                #ifdef OPENSSL_EXTRA
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     dName->emailIdx = cert->srcIdx;
                     dName->emailLen = adv;
@@ -3685,4 +4901,5 @@
                             return MEMORY_E;
                         }
+                        emailName->type = 0;
                         emailName->name = (char*)XMALLOC(adv + 1,
                                               cert->heap, DYNAMIC_TYPE_ALTNAME);
@@ -3692,7 +4909,8 @@
                             return MEMORY_E;
                         }
+                        emailName->len = adv;
                         XMEMCPY(emailName->name,
                                               &cert->source[cert->srcIdx], adv);
-                        emailName->name[adv] = 0;
+                        emailName->name[adv] = '\0';
 
                         emailName->next = cert->altEmailNames;
@@ -3706,5 +4924,5 @@
             }
 
-            if (uid) {
+            if (pilot) {
                 if ( (5 + adv) > (int)(ASN_NAME_MAX - idx)) {
                     WOLFSSL_MSG("ASN name too big, skipping");
@@ -3712,14 +4930,34 @@
                 }
                 if (!tooBig) {
+                    switch (id) {
+                        case ASN_USER_ID:
                     XMEMCPY(&full[idx], "/UID=", 5);
                     idx += 5;
-
+                        #if defined(OPENSSL_EXTRA) || \
+                            defined(OPENSSL_EXTRA_X509_SMALL)
+                            dName->uidIdx = cert->srcIdx;
+                            dName->uidLen = adv;
+                        #endif /* OPENSSL_EXTRA */
+                            break;
+
+                        case ASN_DOMAIN_COMPONENT:
+                            XMEMCPY(&full[idx], "/DC=", 4);
+                            idx += 4;
+                        #if defined(OPENSSL_EXTRA) || \
+                            defined(OPENSSL_EXTRA_X509_SMALL)
+                            dName->dcIdx[dcnum] = cert->srcIdx;
+                            dName->dcLen[dcnum] = adv;
+                            dName->dcNum = dcnum + 1;
+                            dcnum++;
+                        #endif /* OPENSSL_EXTRA */
+                            break;
+
+                        default:
+                            WOLFSSL_MSG("Unknown pilot attribute type");
+                            return ASN_PARSE_E;
+                    }
                     XMEMCPY(&full[idx], &cert->source[cert->srcIdx], adv);
                     idx += adv;
                 }
-                #ifdef OPENSSL_EXTRA
-                    dName->uidIdx = cert->srcIdx;
-                    dName->uidLen = adv;
-                #endif /* OPENSSL_EXTRA */
             }
 
@@ -3729,7 +4967,8 @@
     full[idx++] = 0;
 
-    #ifdef OPENSSL_EXTRA
+    #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
     {
         int totalLen = 0;
+        int i = 0;
 
         if (dName->cnLen != 0)
@@ -3753,4 +4992,8 @@
         if (dName->serialLen != 0)
             totalLen += dName->serialLen + 14;
+        if (dName->dcNum != 0){
+            for (i = 0;i < dName->dcNum;i++)
+                totalLen += dName->dcLen[i] + 4;
+        }
 
         dName->fullName = (char*)XMALLOC(totalLen + 1, cert->heap,
@@ -3761,5 +5004,6 @@
             if (dName->cnLen != 0) {
                 dName->entryCount++;
-                XMEMCPY(&dName->fullName[idx], "/CN=", 4);
+                XMEMCPY(&dName->fullName[idx], WOLFSSL_COMMON_NAME, 4);
+                dName->cnNid = OBJ_sn2nid((const char *)WOLFSSL_COMMON_NAME);
                 idx += 4;
                 XMEMCPY(&dName->fullName[idx],
@@ -3770,5 +5014,6 @@
             if (dName->snLen != 0) {
                 dName->entryCount++;
-                XMEMCPY(&dName->fullName[idx], "/SN=", 4);
+                XMEMCPY(&dName->fullName[idx], WOLFSSL_SUR_NAME, 4);
+                dName->snNid = OBJ_sn2nid((const char *)WOLFSSL_SUR_NAME);
                 idx += 4;
                 XMEMCPY(&dName->fullName[idx],
@@ -3779,5 +5024,6 @@
             if (dName->cLen != 0) {
                 dName->entryCount++;
-                XMEMCPY(&dName->fullName[idx], "/C=", 3);
+                XMEMCPY(&dName->fullName[idx], WOLFSSL_COUNTRY_NAME, 3);
+                dName->cNid = OBJ_sn2nid((const char *)WOLFSSL_COUNTRY_NAME);
                 idx += 3;
                 XMEMCPY(&dName->fullName[idx],
@@ -3788,5 +5034,6 @@
             if (dName->lLen != 0) {
                 dName->entryCount++;
-                XMEMCPY(&dName->fullName[idx], "/L=", 3);
+                XMEMCPY(&dName->fullName[idx], WOLFSSL_LOCALITY_NAME, 3);
+                dName->lNid = OBJ_sn2nid((const char *)WOLFSSL_LOCALITY_NAME);
                 idx += 3;
                 XMEMCPY(&dName->fullName[idx],
@@ -3797,5 +5044,6 @@
             if (dName->stLen != 0) {
                 dName->entryCount++;
-                XMEMCPY(&dName->fullName[idx], "/ST=", 4);
+                XMEMCPY(&dName->fullName[idx], WOLFSSL_STATE_NAME, 4);
+                dName->stNid = OBJ_sn2nid((const char *)WOLFSSL_STATE_NAME);
                 idx += 4;
                 XMEMCPY(&dName->fullName[idx],
@@ -3806,5 +5054,6 @@
             if (dName->oLen != 0) {
                 dName->entryCount++;
-                XMEMCPY(&dName->fullName[idx], "/O=", 3);
+                XMEMCPY(&dName->fullName[idx], WOLFSSL_ORG_NAME, 3);
+                dName->oNid = OBJ_sn2nid((const char *)WOLFSSL_ORG_NAME);
                 idx += 3;
                 XMEMCPY(&dName->fullName[idx],
@@ -3815,5 +5064,6 @@
             if (dName->ouLen != 0) {
                 dName->entryCount++;
-                XMEMCPY(&dName->fullName[idx], "/OU=", 4);
+                XMEMCPY(&dName->fullName[idx], WOLFSSL_ORGUNIT_NAME, 4);
+                dName->ouNid = OBJ_sn2nid((const char *)WOLFSSL_ORGUNIT_NAME);
                 idx += 4;
                 XMEMCPY(&dName->fullName[idx],
@@ -3825,4 +5075,5 @@
                 dName->entryCount++;
                 XMEMCPY(&dName->fullName[idx], "/emailAddress=", 14);
+                dName->emailNid = OBJ_sn2nid((const char *)"/emailAddress=");
                 idx += 14;
                 XMEMCPY(&dName->fullName[idx],
@@ -3831,7 +5082,19 @@
                 idx += dName->emailLen;
             }
+            for (i = 0;i < dName->dcNum;i++){
+                if (dName->dcLen[i] != 0) {
+                    dName->entryCount++;
+                    XMEMCPY(&dName->fullName[idx], WOLFSSL_DOMAIN_COMPONENT, 4);
+                    idx += 4;
+                    XMEMCPY(&dName->fullName[idx],
+                                    &cert->source[dName->dcIdx[i]], dName->dcLen[i]);
+                    dName->dcIdx[i] = idx;
+                    idx += dName->dcLen[i];
+                }
+            }
             if (dName->uidLen != 0) {
                 dName->entryCount++;
                 XMEMCPY(&dName->fullName[idx], "/UID=", 5);
+                dName->uidNid = OBJ_sn2nid((const char *)"/UID=");
                 idx += 5;
                 XMEMCPY(&dName->fullName[idx],
@@ -3842,5 +5105,6 @@
             if (dName->serialLen != 0) {
                 dName->entryCount++;
-                XMEMCPY(&dName->fullName[idx], "/serialNumber=", 14);
+                XMEMCPY(&dName->fullName[idx], WOLFSSL_SERIAL_NUMBER, 14);
+                dName->serialNid = OBJ_sn2nid((const char *)WOLFSSL_SERIAL_NUMBER);
                 idx += 14;
                 XMEMCPY(&dName->fullName[idx],
@@ -3860,86 +5124,15 @@
 
 #ifndef NO_ASN_TIME
-#if !defined(NO_TIME_H) && defined(USE_WOLF_VALIDDATE)
-
-/* to the second */
-static int DateGreaterThan(const struct tm* a, const struct tm* b)
-{
-    if (a->tm_year > b->tm_year)
-        return 1;
-
-    if (a->tm_year == b->tm_year && a->tm_mon > b->tm_mon)
-        return 1;
-
-    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
-           a->tm_mday > b->tm_mday)
-        return 1;
-
-    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
-        a->tm_mday == b->tm_mday && a->tm_hour > b->tm_hour)
-        return 1;
-
-    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
-        a->tm_mday == b->tm_mday && a->tm_hour == b->tm_hour &&
-        a->tm_min > b->tm_min)
-        return 1;
-
-    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
-        a->tm_mday == b->tm_mday && a->tm_hour == b->tm_hour &&
-        a->tm_min  == b->tm_min  && a->tm_sec > b->tm_sec)
-        return 1;
-
-    return 0; /* false */
-}
-
-
-static INLINE int DateLessThan(const struct tm* a, const struct tm* b)
-{
-    return DateGreaterThan(b,a);
-}
-
-
-#if defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
-int GetTimeString(byte* date, int format, char* buf, int len)
-{
-    struct tm t;
-    int idx = 0;
-
-    if (!ExtractDate(date, format, &t, &idx)) {
-        return 0;
-    }
-
-    if (date[idx] != 'Z') {
-        WOLFSSL_MSG("UTCtime, not Zulu") ;
-        return 0;
-    }
-
-    /* place month in buffer */
-    buf[0] = '\0';
-    switch(t.tm_mon) {
-        case 0:  XSTRNCAT(buf, "Jan ", 4); break;
-        case 1:  XSTRNCAT(buf, "Feb ", 4); break;
-        case 2:  XSTRNCAT(buf, "Mar ", 4); break;
-        case 3:  XSTRNCAT(buf, "Apr ", 4); break;
-        case 4:  XSTRNCAT(buf, "May ", 4); break;
-        case 5:  XSTRNCAT(buf, "Jun ", 4); break;
-        case 6:  XSTRNCAT(buf, "Jul ", 4); break;
-        case 7:  XSTRNCAT(buf, "Aug ", 4); break;
-        case 8:  XSTRNCAT(buf, "Sep ", 4); break;
-        case 9:  XSTRNCAT(buf, "Oct ", 4); break;
-        case 10: XSTRNCAT(buf, "Nov ", 4); break;
-        case 11: XSTRNCAT(buf, "Dec ", 4); break;
-        default:
-            return 0;
-
-    }
-    idx = 4; /* use idx now for char buffer */
-    buf[idx] = ' ';
-
-    XSNPRINTF(buf + idx, len - idx, "%2d %02d:%02d:%02d %d GMT",
-              t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, t.tm_year + 1900);
-
-    return 1;
-}
-#endif /* WOLFSSL_MYSQL_COMPATIBLE */
+
+/* two byte date/time, add to value */
+static WC_INLINE void GetTime(int* value, const byte* date, int* idx)
+{
+    int i = *idx;
+
+    *value += btoi(date[i++]) * 10;
+    *value += btoi(date[i++]);
+
+    *idx = i;
+}
 
 int ExtractDate(const unsigned char* date, unsigned char format,
@@ -3957,5 +5150,5 @@
         certTime->tm_year += btoi(date[*idx]) * 1000; *idx = *idx + 1;
         certTime->tm_year += btoi(date[*idx]) * 100;  *idx = *idx + 1;
-    }
+}
 
     /* adjust tm_year, tm_mon */
@@ -3970,4 +5163,178 @@
 }
 
+
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_MYSQL_COMPATIBLE) || \
+    defined(OPENSSL_EXTRA) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+int GetTimeString(byte* date, int format, char* buf, int len)
+{
+    struct tm t;
+    int idx = 0;
+
+    if (!ExtractDate(date, (unsigned char)format, &t, &idx)) {
+        return 0;
+    }
+
+    if (date[idx] != 'Z') {
+        WOLFSSL_MSG("UTCtime, not Zulu") ;
+        return 0;
+    }
+
+    /* place month in buffer */
+    buf[0] = '\0';
+    switch(t.tm_mon) {
+        case 0:  XSTRNCAT(buf, "Jan ", 5); break;
+        case 1:  XSTRNCAT(buf, "Feb ", 5); break;
+        case 2:  XSTRNCAT(buf, "Mar ", 5); break;
+        case 3:  XSTRNCAT(buf, "Apr ", 5); break;
+        case 4:  XSTRNCAT(buf, "May ", 5); break;
+        case 5:  XSTRNCAT(buf, "Jun ", 5); break;
+        case 6:  XSTRNCAT(buf, "Jul ", 5); break;
+        case 7:  XSTRNCAT(buf, "Aug ", 5); break;
+        case 8:  XSTRNCAT(buf, "Sep ", 5); break;
+        case 9:  XSTRNCAT(buf, "Oct ", 5); break;
+        case 10: XSTRNCAT(buf, "Nov ", 5); break;
+        case 11: XSTRNCAT(buf, "Dec ", 5); break;
+        default:
+            return 0;
+
+    }
+    idx = 4; /* use idx now for char buffer */
+
+    XSNPRINTF(buf + idx, len - idx, "%2d %02d:%02d:%02d %d GMT",
+              t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, t.tm_year + 1900);
+
+    return 1;
+}
+#endif /* OPENSSL_ALL || WOLFSSL_MYSQL_COMPATIBLE || WOLFSSL_NGINX || WOLFSSL_HAPROXY */
+
+
+#if !defined(NO_ASN_TIME) && defined(HAVE_PKCS7)
+
+/* Set current time string, either UTC or GeneralizedTime.
+ * (void*) tm should be a pointer to time_t, output is placed in buf.
+ *
+ * Return time string length placed in buf on success, negative on error */
+int GetAsnTimeString(void* currTime, byte* buf, word32 len)
+{
+    struct tm* ts      = NULL;
+    struct tm* tmpTime = NULL;
+#if defined(NEED_TMP_TIME)
+    struct tm tmpTimeStorage;
+    tmpTime = &tmpTimeStorage;
+#else
+    (void)tmpTime;
+#endif
+    byte* data_ptr  = buf;
+    word32 data_len = 0;
+    int year, mon, day, hour, mini, sec;
+
+    WOLFSSL_ENTER("SetAsnTimeString");
+
+    if (buf == NULL || len == 0)
+        return BAD_FUNC_ARG;
+
+    ts = (struct tm *)XGMTIME((time_t*)currTime, tmpTime);
+    if (ts == NULL){
+        WOLFSSL_MSG("failed to get time data.");
+        return ASN_TIME_E;
+    }
+
+    /* Note ASN_UTC_TIME_SIZE and ASN_GENERALIZED_TIME_SIZE include space for
+     * the null terminator. ASN encoded values leave off the terminator. */
+
+    if (ts->tm_year >= 50 && ts->tm_year < 150) {
+        /* UTC Time */
+        char utc_str[ASN_UTC_TIME_SIZE];
+        data_len = ASN_UTC_TIME_SIZE - 1 + 2;
+
+        if (len < data_len)
+            return BUFFER_E;
+
+        if (ts->tm_year >= 50 && ts->tm_year < 100) {
+            year = ts->tm_year;
+        } else if (ts->tm_year >= 100 && ts->tm_year < 150) {
+            year = ts->tm_year - 100;
+        }
+        else {
+            WOLFSSL_MSG("unsupported year range");
+            return BAD_FUNC_ARG;
+    }
+        mon  = ts->tm_mon + 1;
+        day  = ts->tm_mday;
+        hour = ts->tm_hour;
+        mini = ts->tm_min;
+        sec  = ts->tm_sec;
+        XSNPRINTF((char *)utc_str, ASN_UTC_TIME_SIZE,
+                  "%02d%02d%02d%02d%02d%02dZ", year, mon, day, hour, mini, sec);
+        *data_ptr = (byte) ASN_UTC_TIME; data_ptr++;
+        /* -1 below excludes null terminator */
+        *data_ptr = (byte) ASN_UTC_TIME_SIZE - 1; data_ptr++;
+        XMEMCPY(data_ptr,(byte *)utc_str, ASN_UTC_TIME_SIZE - 1);
+
+    } else {
+        /* GeneralizedTime */
+        char gt_str[ASN_GENERALIZED_TIME_SIZE];
+        data_len = ASN_GENERALIZED_TIME_SIZE - 1 + 2;
+
+        if (len < data_len)
+            return BUFFER_E;
+
+        year = ts->tm_year + 1900;
+        mon  = ts->tm_mon + 1;
+        day  = ts->tm_mday;
+        hour = ts->tm_hour;
+        mini = ts->tm_min;
+        sec  = ts->tm_sec;
+        XSNPRINTF((char *)gt_str, ASN_GENERALIZED_TIME_SIZE,
+                  "%4d%02d%02d%02d%02d%02dZ", year, mon, day, hour, mini, sec);
+        *data_ptr = (byte) ASN_GENERALIZED_TIME; data_ptr++;
+        /* -1 below excludes null terminator */
+        *data_ptr = (byte) ASN_GENERALIZED_TIME_SIZE - 1; data_ptr++;
+        XMEMCPY(data_ptr,(byte *)gt_str, ASN_GENERALIZED_TIME_SIZE - 1);
+    }
+
+    return data_len;
+}
+
+#endif /* !NO_ASN_TIME && HAVE_PKCS7 */
+
+
+#if defined(USE_WOLF_VALIDDATE)
+
+/* to the second */
+static int DateGreaterThan(const struct tm* a, const struct tm* b)
+{
+    if (a->tm_year > b->tm_year)
+        return 1;
+
+    if (a->tm_year == b->tm_year && a->tm_mon > b->tm_mon)
+        return 1;
+
+    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
+           a->tm_mday > b->tm_mday)
+        return 1;
+
+    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
+        a->tm_mday == b->tm_mday && a->tm_hour > b->tm_hour)
+        return 1;
+
+    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
+        a->tm_mday == b->tm_mday && a->tm_hour == b->tm_hour &&
+        a->tm_min > b->tm_min)
+        return 1;
+
+    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
+        a->tm_mday == b->tm_mday && a->tm_hour == b->tm_hour &&
+        a->tm_min  == b->tm_min  && a->tm_sec > b->tm_sec)
+    return 1;
+
+    return 0; /* false */
+}
+
+
+static WC_INLINE int DateLessThan(const struct tm* a, const struct tm* b)
+{
+    return DateGreaterThan(b,a);
+}
 
 /* like atoi but only use first byte */
@@ -4046,5 +5413,5 @@
     return 1;
 }
-#endif /* !NO_TIME_H && USE_WOLF_VALIDDATE */
+#endif /* USE_WOLF_VALIDDATE */
 
 int wc_GetTime(void* timePtr, word32 timeSize)
@@ -4067,12 +5434,49 @@
 #endif /* !NO_ASN_TIME */
 
-static int GetDate(DecodedCert* cert, int dateType)
+
+/* Get date buffer, format and length. Returns 0=success or error */
+static int GetDateInfo(const byte* source, word32* idx, const byte** pDate,
+                        byte* pFormat, int* pLength, word32 maxIdx)
 {
     int    length;
+    byte format;
+
+    if (source == NULL || idx == NULL)
+        return BAD_FUNC_ARG;
+
+    /* get ASN format header */
+    if (*idx+1 > maxIdx)
+        return BUFFER_E;
+    format = source[*idx];
+    *idx += 1;
+    if (format != ASN_UTC_TIME && format != ASN_GENERALIZED_TIME)
+        return ASN_TIME_E;
+
+    /* get length */
+    if (GetLength(source, idx, &length, maxIdx) < 0)
+        return ASN_PARSE_E;
+    if (length > MAX_DATE_SIZE || length < MIN_DATE_SIZE)
+        return ASN_DATE_SZ_E;
+
+    /* return format, date and length */
+    if (pFormat)
+        *pFormat = format;
+    if (pDate)
+        *pDate = &source[*idx];
+    if (pLength)
+        *pLength = length;
+
+    *idx += length;
+
+    return 0;
+}
+
+static int GetDate(DecodedCert* cert, int dateType, int verify)
+{
+    int    ret, length;
+    const byte *datePtr = NULL;
     byte   date[MAX_DATE_SIZE];
-    byte   b;
+    byte   format;
     word32 startIdx = 0;
-
-    XMEMSET(date, 0, MAX_DATE_SIZE);
 
     if (dateType == BEFORE)
@@ -4082,16 +5486,11 @@
     startIdx = cert->srcIdx;
 
-    b = cert->source[cert->srcIdx++];
-    if (b != ASN_UTC_TIME && b != ASN_GENERALIZED_TIME)
-        return ASN_TIME_E;
-
-    if (GetLength(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0)
-        return ASN_PARSE_E;
-
-    if (length > MAX_DATE_SIZE || length < MIN_DATE_SIZE)
-        return ASN_DATE_SZ_E;
-
-    XMEMCPY(date, &cert->source[cert->srcIdx], length);
-    cert->srcIdx += length;
+    ret = GetDateInfo(cert->source, &cert->srcIdx, &datePtr, &format,
+                      &length, cert->maxIdx);
+    if (ret < 0)
+        return ret;
+
+    XMEMSET(date, 0, MAX_DATE_SIZE);
+    XMEMCPY(date, datePtr, length);
 
     if (dateType == BEFORE)
@@ -4101,5 +5500,5 @@
 
 #ifndef NO_ASN_TIME
-    if (!XVALIDATE_DATE(date, b, dateType)) {
+    if (verify != NO_VERIFY && !XVALIDATE_DATE(date, format, dateType)) {
         if (dateType == BEFORE)
             return ASN_BEFORE_DATE_E;
@@ -4107,4 +5506,6 @@
             return ASN_AFTER_DATE_E;
     }
+#else
+    (void)verify;
 #endif
 
@@ -4120,8 +5521,8 @@
         return ASN_PARSE_E;
 
-    if (GetDate(cert, BEFORE) < 0 && verify != NO_VERIFY)
+    if (GetDate(cert, BEFORE, verify) < 0)
         badDate = ASN_BEFORE_DATE_E;           /* continue parsing */
 
-    if (GetDate(cert, AFTER) < 0 && verify != NO_VERIFY)
+    if (GetDate(cert, AFTER, verify) < 0)
         return ASN_AFTER_DATE_E;
 
@@ -4131,4 +5532,58 @@
     return 0;
 }
+
+
+int wc_GetDateInfo(const byte* certDate, int certDateSz, const byte** date,
+    byte* format, int* length)
+{
+    int ret;
+    word32 idx = 0;
+
+    ret = GetDateInfo(certDate, &idx, date, format, length, certDateSz);
+    if (ret < 0)
+        return ret;
+
+    return 0;
+}
+
+#ifndef NO_ASN_TIME
+int wc_GetDateAsCalendarTime(const byte* date, int length, byte format,
+    struct tm* timearg)
+{
+    int idx = 0;
+    (void)length;
+    if (!ExtractDate(date, format, timearg, &idx))
+        return ASN_TIME_E;
+    return 0;
+}
+
+#if defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_ALT_NAMES)
+int wc_GetCertDates(Cert* cert, struct tm* before, struct tm* after)
+{
+    int ret = 0;
+    const byte* date;
+    byte format;
+    int length;
+
+    if (cert == NULL)
+        return BAD_FUNC_ARG;
+
+    if (before && cert->beforeDateSz > 0) {
+        ret = wc_GetDateInfo(cert->beforeDate, cert->beforeDateSz, &date,
+                             &format, &length);
+        if (ret == 0)
+            ret = wc_GetDateAsCalendarTime(date, length, format, before);
+    }
+    if (after && cert->afterDateSz > 0) {
+        ret = wc_GetDateInfo(cert->afterDate, cert->afterDateSz, &date,
+                             &format, &length);
+        if (ret == 0)
+            ret = wc_GetDateAsCalendarTime(date, length, format, after);
+    }
+
+    return ret;
+}
+#endif /* WOLFSSL_CERT_GEN && WOLFSSL_ALT_NAMES */
+#endif /* !NO_ASN_TIME */
 
 
@@ -4267,5 +5722,5 @@
 
 
-#if defined(HAVE_ECC) && (defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_GEN))
+#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT)
 
 static int SetCurve(ecc_key* key, byte* output)
@@ -4306,8 +5761,9 @@
 }
 
-#endif /* HAVE_ECC && (WOLFSSL_CERT_GEN || WOLFSSL_KEY_GEN) */
-
-
-static INLINE int IsSigAlgoECDSA(int algoOID)
+#endif /* HAVE_ECC && HAVE_ECC_KEY_EXPORT */
+
+
+#ifdef HAVE_ECC
+static WC_INLINE int IsSigAlgoECDSA(int algoOID)
 {
     /* ECDSA sigAlgo must not have ASN1 NULL parameters */
@@ -4319,4 +5775,5 @@
     return 0;
 }
+#endif
 
 WOLFSSL_LOCAL word32 SetAlgoID(int algoOID, byte* output, int type, int curveSz)
@@ -4328,6 +5785,12 @@
 
     tagSz = (type == oidHashType ||
-             (type == oidSigType && !IsSigAlgoECDSA(algoOID) &&
-                                         algoOID != ED25519k) ||
+             (type == oidSigType
+        #ifdef HAVE_ECC
+              && !IsSigAlgoECDSA(algoOID)
+        #endif
+        #ifdef HAVE_ED25519
+              && algoOID != ED25519k
+        #endif
+              ) ||
              (type == oidKeyType && algoOID == RSAk)) ? 2 : 0;
 
@@ -4375,36 +5838,13 @@
 int wc_GetCTC_HashOID(int type)
 {
-    switch (type) {
-#ifdef WOLFSSL_MD2
-        case MD2:
-            return MD2h;
-#endif
-#ifndef NO_MD5
-        case WC_MD5:
-            return MD5h;
-#endif
-#ifndef NO_SHA
-        case WC_SHA:
-            return SHAh;
-#endif
-#ifdef WOLFSSL_SHA224
-        case WC_SHA224:
-            return SHA224h;
-#endif
-#ifndef NO_SHA256
-        case WC_SHA256:
-            return SHA256h;
-#endif
-#ifdef WOLFSSL_SHA384
-        case WC_SHA384:
-            return SHA384h;
-#endif
-#ifdef WOLFSSL_SHA512
-        case WC_SHA512:
-            return SHA512h;
-#endif
-        default:
-            return 0;
-    };
+    int ret;
+    enum wc_HashType hType;
+
+    hType = wc_HashTypeConvert(type);
+    ret = wc_HashGetOID(hType);
+    if (ret < 0)
+        ret = 0; /* backwards compatibility */
+
+    return ret;
 }
 
@@ -4433,4 +5873,5 @@
     }
 #endif
+#ifndef NO_ASN_CRYPT
     if (sigCtx->key.ptr) {
         switch (sigCtx->keyOID) {
@@ -4458,4 +5899,5 @@
         sigCtx->key.ptr = NULL;
     }
+#endif
 
     /* reset state, we are done */
@@ -4463,4 +5905,5 @@
 }
 
+#ifndef NO_ASN_CRYPT
 static int HashForSignature(const byte* buf, word32 bufSz, word32 sigOID,
                             byte* digest, int* typeH, int* digestSz, int verify)
@@ -4549,4 +5992,5 @@
     return ret;
 }
+#endif /* !NO_ASN_CRYPT */
 
 /* Return codes: 0=Success, Negative (see error-crypt.h), ASN_SIG_CONFIRM_E */
@@ -4570,7 +6014,10 @@
     WOLFSSL_ENTER("ConfirmSignature");
 
+#ifndef NO_ASN_CRYPT
     switch (sigCtx->state) {
         case SIG_STATE_BEGIN:
         {
+            sigCtx->keyOID = keyOID; /* must set early for cleanup */
+
             sigCtx->digest = (byte*)XMALLOC(WC_MAX_DIGEST_SIZE, sigCtx->heap,
                                                     DYNAMIC_TYPE_DIGEST);
@@ -4597,6 +6044,4 @@
         case SIG_STATE_KEY:
         {
-            sigCtx->keyOID = keyOID;
-
             switch (keyOID) {
             #ifndef NO_RSA
@@ -4637,4 +6082,6 @@
                 case ECDSAk:
                 {
+                    word32 idx = 0;
+
                     sigCtx->verify = 0;
                     sigCtx->key.ecc = (ecc_key*)XMALLOC(sizeof(ecc_key),
@@ -4647,6 +6094,7 @@
                         goto exit_cs;
                     }
-                    if ((ret = wc_ecc_import_x963(key, keySz,
-                                                        sigCtx->key.ecc)) < 0) {
+                    ret = wc_EccPublicKeyDecode(key, &idx, sigCtx->key.ecc,
+                                                                         keySz);
+                    if (ret < 0) {
                         WOLFSSL_MSG("ASN Key import error ECC");
                         goto exit_cs;
@@ -4696,5 +6144,5 @@
         #ifdef WOLFSSL_ASYNC_CRYPT
             if (sigCtx->devId != INVALID_DEVID && sigCtx->asyncDev && sigCtx->asyncCtx) {
-                /* make sure event is intialized */
+                /* make sure event is initialized */
                 WOLF_EVENT* event = &sigCtx->asyncDev->event;
                 ret = wolfAsync_EventInit(event, WOLF_EVENT_TYPE_ASYNC_WOLFSSL,
@@ -4711,6 +6159,17 @@
                 case RSAk:
                 {
+                #ifdef HAVE_PK_CALLBACKS
+                    if (sigCtx->pkCbRsa) {
+                        ret = sigCtx->pkCbRsa(
+                                sigCtx->plain, sigSz, &sigCtx->out,
+                                key, keySz,
+                                sigCtx->pkCtxRsa);
+                    }
+                    else
+                #endif /* HAVE_PK_CALLBACKS */
+                    {
                     ret = wc_RsaSSL_VerifyInline(sigCtx->plain, sigSz,
                                                 &sigCtx->out, sigCtx->key.rsa);
+                    }
                     break;
                 }
@@ -4719,6 +6178,19 @@
                 case ECDSAk:
                 {
+                #ifdef HAVE_PK_CALLBACKS
+                    if (sigCtx->pkCbEcc) {
+                        ret = sigCtx->pkCbEcc(
+                                sig, sigSz,
+                                sigCtx->digest, sigCtx->digestSz,
+                                key, keySz, &sigCtx->verify,
+                                sigCtx->pkCtxEcc);
+                    }
+                    else
+                #endif /* HAVE_PK_CALLBACKS */
+                    {
                     ret = wc_ecc_verify_hash(sig, sigSz, sigCtx->digest,
-                        sigCtx->digestSz, &sigCtx->verify, sigCtx->key.ecc);
+                                            sigCtx->digestSz, &sigCtx->verify,
+                                            sigCtx->key.ecc);
+                    }
                     break;
                 }
@@ -4769,5 +6241,5 @@
                     encodedSigSz = wc_EncodeSignature(encodedSig,
                             sigCtx->digest, sigCtx->digestSz, sigCtx->typeH);
-                    if (encodedSigSz == verifySz &&
+                    if (encodedSigSz == verifySz && sigCtx->out != NULL &&
                         XMEMCMP(sigCtx->out, encodedSig, encodedSigSz) == 0) {
                         ret = 0;
@@ -4820,4 +6292,9 @@
 exit_cs:
 
+#endif /* !NO_ASN_CRYPT */
+
+    (void)keyOID;
+    (void)sigOID;
+
     WOLFSSL_LEAVE("ConfirmSignature", ret);
 
@@ -4911,5 +6388,5 @@
                     while (name != NULL) {
                         if (MatchBaseName(ASN_DNS_TYPE,
-                                          name->name, (int)XSTRLEN(name->name),
+                                          name->name, name->len,
                                           base->name, base->nameSz)) {
                             return 0;
@@ -4924,5 +6401,5 @@
                     while (name != NULL) {
                         if (MatchBaseName(ASN_RFC822_TYPE,
-                                          name->name, (int)XSTRLEN(name->name),
+                                          name->name, name->len,
                                           base->name, base->nameSz)) {
                             return 0;
@@ -4968,5 +6445,5 @@
                     while (name != NULL) {
                         matchDns = MatchBaseName(ASN_DNS_TYPE,
-                                          name->name, (int)XSTRLEN(name->name),
+                                          name->name, name->len,
                                           base->name, base->nameSz);
                         name = name->next;
@@ -4983,5 +6460,5 @@
                     while (name != NULL) {
                         matchEmail = MatchBaseName(ASN_DNS_TYPE,
-                                          name->name, (int)XSTRLEN(name->name),
+                                          name->name, name->len,
                                           base->name, base->nameSz);
                         name = name->next;
@@ -5017,5 +6494,5 @@
 #endif /* IGNORE_NAME_CONSTRAINTS */
 
-static int DecodeAltNames(byte* input, int sz, DecodedCert* cert)
+static int DecodeAltNames(const byte* input, int sz, DecodedCert* cert)
 {
     word32 idx = 0;
@@ -5056,4 +6533,5 @@
             }
 
+            dnsEntry->type = ASN_DNS_TYPE;
             dnsEntry->name = (char*)XMALLOC(strLen + 1, cert->heap,
                                          DYNAMIC_TYPE_ALTNAME);
@@ -5063,5 +6541,5 @@
                 return MEMORY_E;
             }
-
+            dnsEntry->len = strLen;
             XMEMCPY(dnsEntry->name, &input[idx], strLen);
             dnsEntry->name[strLen] = '\0';
@@ -5092,4 +6570,5 @@
             }
 
+            emailEntry->type = ASN_RFC822_TYPE;
             emailEntry->name = (char*)XMALLOC(strLen + 1, cert->heap,
                                          DYNAMIC_TYPE_ALTNAME);
@@ -5099,5 +6578,5 @@
                 return MEMORY_E;
             }
-
+            emailEntry->len = strLen;
             XMEMCPY(emailEntry->name, &input[idx], strLen);
             emailEntry->name[strLen] = '\0';
@@ -5105,4 +6584,75 @@
             emailEntry->next = cert->altEmailNames;
             cert->altEmailNames = emailEntry;
+
+            length -= strLen;
+            idx    += strLen;
+        }
+        else if (b == (ASN_CONTEXT_SPECIFIC | ASN_URI_TYPE)) {
+            DNS_entry* uriEntry;
+            int strLen;
+            word32 lenStartIdx = idx;
+
+            WOLFSSL_MSG("\tPutting URI into list but not using");
+            if (GetLength(input, &idx, &strLen, sz) < 0) {
+                WOLFSSL_MSG("\tfail: str length");
+                return ASN_PARSE_E;
+            }
+            length -= (idx - lenStartIdx);
+
+            /* check that strLen at index is not past input buffer */
+            if (strLen + (int)idx > sz) {
+                return BUFFER_E;
+            }
+
+        #ifndef WOLFSSL_NO_ASN_STRICT
+            /* Verify RFC 5280 Sec 4.2.1.6 rule:
+                "The name MUST NOT be a relative URI" */
+
+            {
+                int i;
+
+                /* skip past scheme (i.e http,ftp,...) finding first ':' char */
+                for (i = 0; i < strLen; i++) {
+                    if (input[idx + i] == ':') {
+                        break;
+                    }
+                    if (input[idx + i] == '/') {
+                        i = strLen; /* error, found relative path since '/' was
+                                     * encountered before ':'. Returning error
+                                     * value in next if statement. */
+                    }
+                }
+
+                /* test if no ':' char was found and test that the next two
+                 * chars are // to match the pattern "://" */
+                if (i >= strLen - 2 || (input[idx + i + 1] != '/' ||
+                                        input[idx + i + 2] != '/')) {
+                    WOLFSSL_MSG("\tAlt Name must be absolute URI");
+                    return ASN_ALT_NAME_E;
+                }
+            }
+        #endif
+
+            uriEntry = (DNS_entry*)XMALLOC(sizeof(DNS_entry), cert->heap,
+                                        DYNAMIC_TYPE_ALTNAME);
+            if (uriEntry == NULL) {
+                WOLFSSL_MSG("\tOut of Memory");
+                return MEMORY_E;
+            }
+
+            uriEntry->type = ASN_URI_TYPE;
+            uriEntry->name = (char*)XMALLOC(strLen + 1, cert->heap,
+                                         DYNAMIC_TYPE_ALTNAME);
+            if (uriEntry->name == NULL) {
+                WOLFSSL_MSG("\tOut of Memory");
+                XFREE(uriEntry, cert->heap, DYNAMIC_TYPE_ALTNAME);
+                return MEMORY_E;
+            }
+            uriEntry->len = strLen;
+            XMEMCPY(uriEntry->name, &input[idx], strLen);
+            uriEntry->name[strLen] = '\0';
+
+            uriEntry->next = cert->altNames;
+            cert->altNames = uriEntry;
 
             length -= strLen;
@@ -5201,5 +6751,5 @@
 }
 
-static int DecodeBasicCaConstraint(byte* input, int sz, DecodedCert* cert)
+static int DecodeBasicCaConstraint(const byte* input, int sz, DecodedCert* cert)
 {
     word32 idx = 0;
@@ -5248,5 +6798,5 @@
     /* From RFC3280 SS4.2.1.7, GeneralName */
 
-static int DecodeCrlDist(byte* input, int sz, DecodedCert* cert)
+static int DecodeCrlDist(const byte* input, int sz, DecodedCert* cert)
 {
     word32 idx = 0;
@@ -5329,5 +6879,5 @@
 
 
-static int DecodeAuthInfo(byte* input, int sz, DecodedCert* cert)
+static int DecodeAuthInfo(const byte* input, int sz, DecodedCert* cert)
 /*
  *  Read the first of the Authority Information Access records. If there are
@@ -5375,5 +6925,5 @@
 
 
-static int DecodeAuthKeyId(byte* input, int sz, DecodedCert* cert)
+static int DecodeAuthKeyId(const byte* input, int sz, DecodedCert* cert)
 {
     word32 idx = 0;
@@ -5397,5 +6947,5 @@
     }
 
-#ifdef OPENSSL_EXTRA
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
     cert->extAuthKeyIdSrc = &input[idx];
     cert->extAuthKeyIdSz = length;
@@ -5405,11 +6955,6 @@
         XMEMCPY(cert->extAuthKeyId, input + idx, length);
     }
-    else {
-    #ifdef NO_SHA
-        ret = wc_Sha256Hash(input + idx, length, cert->extAuthKeyId);
-    #else
-        ret = wc_ShaHash(input + idx, length, cert->extAuthKeyId);
-    #endif
-    }
+    else
+        ret = CalcHashId(input + idx, length, cert->extAuthKeyId);
 
     return ret;
@@ -5417,5 +6962,5 @@
 
 
-static int DecodeSubjKeyId(byte* input, int sz, DecodedCert* cert)
+static int DecodeSubjKeyId(const byte* input, int sz, DecodedCert* cert)
 {
     word32 idx = 0;
@@ -5431,19 +6976,14 @@
         return ret;
 
-    #ifdef OPENSSL_EXTRA
+    #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
         cert->extSubjKeyIdSrc = &input[idx];
         cert->extSubjKeyIdSz = length;
     #endif /* OPENSSL_EXTRA */
 
-    if (length == SIGNER_DIGEST_SIZE) {
+    if (length == KEYID_SIZE) {
         XMEMCPY(cert->extSubjKeyId, input + idx, length);
     }
-    else {
-    #ifdef NO_SHA
-        ret = wc_Sha256Hash(input + idx, length, cert->extSubjKeyId);
-    #else
-        ret = wc_ShaHash(input + idx, length, cert->extSubjKeyId);
-    #endif
-    }
+    else
+        ret = CalcHashId(input + idx, length, cert->extSubjKeyId);
 
     return ret;
@@ -5451,5 +6991,5 @@
 
 
-static int DecodeKeyUsage(byte* input, int sz, DecodedCert* cert)
+static int DecodeKeyUsage(const byte* input, int sz, DecodedCert* cert)
 {
     word32 idx = 0;
@@ -5470,10 +7010,10 @@
 
 
-static int DecodeExtKeyUsage(byte* input, int sz, DecodedCert* cert)
+static int DecodeExtKeyUsage(const byte* input, int sz, DecodedCert* cert)
 {
     word32 idx = 0, oid;
-    int length;
-
-    WOLFSSL_ENTER("DecodeExtKeyUsage");
+    int length, ret;
+
+    WOLFSSL_MSG("DecodeExtKeyUsage");
 
     if (GetSequence(input, &idx, &length, sz) < 0) {
@@ -5482,5 +7022,5 @@
     }
 
-#ifdef OPENSSL_EXTRA
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
     cert->extExtKeyUsageSrc = input + idx;
     cert->extExtKeyUsageSz = length;
@@ -5488,6 +7028,9 @@
 
     while (idx < (word32)sz) {
-        if (GetObjectId(input, &idx, &oid, oidCertKeyUseType, sz) < 0)
-            return ASN_PARSE_E;
+        ret = GetObjectId(input, &idx, &oid, oidCertKeyUseType, sz);
+        if (ret == ASN_UNKNOWN_OID_E)
+            continue;
+        else if (ret < 0)
+            return ret;
 
         switch (oid) {
@@ -5515,5 +7058,5 @@
         }
 
-    #ifdef OPENSSL_EXTRA
+    #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
         cert->extExtKeyUsageCount++;
     #endif
@@ -5526,5 +7069,6 @@
 #ifndef IGNORE_NAME_CONSTRAINTS
 #define ASN_TYPE_MASK 0xF
-static int DecodeSubtree(byte* input, int sz, Base_entry** head, void* heap)
+static int DecodeSubtree(const byte* input, int sz,
+                         Base_entry** head, void* heap)
 {
     word32 idx = 0;
@@ -5593,5 +7137,5 @@
 
 
-static int DecodeNameConstraints(byte* input, int sz, DecodedCert* cert)
+static int DecodeNameConstraints(const byte* input, int sz, DecodedCert* cert)
 {
     word32 idx = 0;
@@ -5632,6 +7176,5 @@
 #endif /* IGNORE_NAME_CONSTRAINTS */
 
-
-#if defined(WOLFSSL_CERT_EXT) && !defined(WOLFSSL_SEP)
+#if (defined(WOLFSSL_CERT_EXT) && !defined(WOLFSSL_SEP)) || defined(OPENSSL_EXTRA)
 
 static int Word32ToString(char* d, word32 number)
@@ -5669,5 +7212,5 @@
 /* Decode ITU-T X.690 OID format to a string representation
  * return string length */
-static int DecodePolicyOID(char *out, word32 outSz, byte *in, word32 inSz)
+int DecodePolicyOID(char *out, word32 outSz, const byte *in, word32 inSz)
 {
     word32 val, idx = 0, nb_bytes;
@@ -5716,5 +7259,5 @@
     }
 
-    return 0;
+    return (int)w_bytes;
 }
 #endif /* WOLFSSL_CERT_EXT && !WOLFSSL_SEP */
@@ -5722,5 +7265,5 @@
 #if defined(WOLFSSL_SEP) || defined(WOLFSSL_CERT_EXT)
     /* Reference: https://tools.ietf.org/html/rfc5280#section-4.2.1.4 */
-    static int DecodeCertPolicy(byte* input, int sz, DecodedCert* cert)
+    static int DecodeCertPolicy(const byte* input, int sz, DecodedCert* cert)
     {
         word32 idx = 0;
@@ -5778,6 +7321,6 @@
         #elif defined(WOLFSSL_CERT_EXT)
                 /* decode cert policy */
-                if (DecodePolicyOID(cert->extCertPolicies[cert->extCertPoliciesNb],
-                                    MAX_CERTPOL_SZ, input + idx, length) != 0) {
+                if (DecodePolicyOID(cert->extCertPolicies[cert->extCertPoliciesNb], MAX_CERTPOL_SZ,
+                                    input + idx, length) <= 0) {
                     WOLFSSL_MSG("\tCouldn't decode CertPolicy");
                     return ASN_PARSE_E;
@@ -5817,4 +7360,18 @@
 #endif /* WOLFSSL_SEP */
 
+/* Macro to check if bit is set, if not sets and return success.
+    Otherwise returns failure */
+/* Macro required here because bit-field operation */
+#ifndef WOLFSSL_NO_ASN_STRICT
+    #define VERIFY_AND_SET_OID(bit) \
+        if (bit == 0) \
+            bit = 1; \
+        else \
+            return ASN_OBJECT_ID_E;
+#else
+    /* With no strict defined, the verify is skipped */
+#define VERIFY_AND_SET_OID(bit) bit = 1;
+#endif
+
 static int DecodeCertExtensions(DecodedCert* cert)
 /*
@@ -5823,8 +7380,8 @@
  */
 {
-    int ret;
+    int ret = 0;
     word32 idx = 0;
     int sz = cert->extensionsSz;
-    byte* input = cert->extensions;
+    const byte* input = cert->extensions;
     int length;
     word32 oid;
@@ -5885,6 +7442,6 @@
         switch (oid) {
             case BASIC_CA_OID:
-                #ifdef OPENSSL_EXTRA
-                    cert->extBasicConstSet = 1;
+                VERIFY_AND_SET_OID(cert->extBasicConstSet);
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     cert->extBasicConstCrit = critical;
                 #endif
@@ -5894,6 +7451,6 @@
 
             case CRL_DIST_OID:
-                #ifdef OPENSSL_EXTRA
-                    cert->extCRLdistSet  = 1;
+                VERIFY_AND_SET_OID(cert->extCRLdistSet);
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     cert->extCRLdistCrit = critical;
                 #endif
@@ -5903,6 +7460,6 @@
 
             case AUTH_INFO_OID:
-                #ifdef OPENSSL_EXTRA
-                    cert->extAuthInfoSet  = 1;
+                VERIFY_AND_SET_OID(cert->extAuthInfoSet);
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     cert->extAuthInfoCrit = critical;
                 #endif
@@ -5912,16 +7469,28 @@
 
             case ALT_NAMES_OID:
-                #ifdef OPENSSL_EXTRA
-                    cert->extSubjAltNameSet = 1;
+                VERIFY_AND_SET_OID(cert->extSubjAltNameSet);
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     cert->extSubjAltNameCrit = critical;
                 #endif
-                if (DecodeAltNames(&input[idx], length, cert) < 0)
-                    return ASN_PARSE_E;
+                ret = DecodeAltNames(&input[idx], length, cert);
+                if (ret < 0)
+                    return ret;
                 break;
 
             case AUTH_KEY_OID:
-                cert->extAuthKeyIdSet = 1;
-                #ifdef OPENSSL_EXTRA
+                VERIFY_AND_SET_OID(cert->extAuthKeyIdSet);
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     cert->extAuthKeyIdCrit = critical;
+                #endif
+                #ifndef WOLFSSL_ALLOW_CRIT_SKID
+                    /* This check is added due to RFC 5280 section 4.2.1.1
+                     * stating that conforming CA's must mark this extension
+                     * as non-critical. When parsing extensions check that
+                     * certificate was made in compliance with this. */
+                    if (critical) {
+                        WOLFSSL_MSG("Critical Auth Key ID is not allowed");
+                        WOLFSSL_MSG("Use macro WOLFSSL_ALLOW_CRIT_SKID if wanted");
+                        return ASN_CRIT_EXT_E;
+                    }
                 #endif
                 if (DecodeAuthKeyId(&input[idx], length, cert) < 0)
@@ -5930,6 +7499,6 @@
 
             case SUBJ_KEY_OID:
-                cert->extSubjKeyIdSet = 1;
-                #ifdef OPENSSL_EXTRA
+                VERIFY_AND_SET_OID(cert->extSubjKeyIdSet);
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     cert->extSubjKeyIdCrit = critical;
                 #endif
@@ -5952,6 +7521,7 @@
             case CERT_POLICY_OID:
                 #ifdef WOLFSSL_SEP
-                    #ifdef OPENSSL_EXTRA
-                        cert->extCertPolicySet = 1;
+                    VERIFY_AND_SET_OID(cert->extCertPolicySet);
+                    #if defined(OPENSSL_EXTRA) || \
+                        defined(OPENSSL_EXTRA_X509_SMALL)
                         cert->extCertPolicyCrit = critical;
                     #endif
@@ -5967,6 +7537,6 @@
 
             case KEY_USAGE_OID:
-                cert->extKeyUsageSet = 1;
-                #ifdef OPENSSL_EXTRA
+                VERIFY_AND_SET_OID(cert->extKeyUsageSet);
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     cert->extKeyUsageCrit = critical;
                 #endif
@@ -5976,6 +7546,6 @@
 
             case EXT_KEY_USAGE_OID:
-                cert->extExtKeyUsageSet = 1;
-                #ifdef OPENSSL_EXTRA
+                VERIFY_AND_SET_OID(cert->extExtKeyUsageSet);
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     cert->extExtKeyUsageCrit = critical;
                 #endif
@@ -5986,6 +7556,15 @@
             #ifndef IGNORE_NAME_CONSTRAINTS
             case NAME_CONS_OID:
-                cert->extNameConstraintSet = 1;
-                #ifdef OPENSSL_EXTRA
+            #ifndef WOLFSSL_NO_ASN_STRICT
+                /* Verify RFC 5280 Sec 4.2.1.10 rule:
+                    "The name constraints extension,
+                    which MUST be used only in a CA certificate" */
+                if (!cert->isCA) {
+                    WOLFSSL_MSG("Name constraints allowed only for CA certs");
+                    return ASN_NAME_INVALID_E;
+                }
+            #endif
+                VERIFY_AND_SET_OID(cert->extNameConstraintSet);
+                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                     cert->extNameConstraintCrit = critical;
                 #endif
@@ -5996,8 +7575,10 @@
 
             case INHIBIT_ANY_OID:
+                VERIFY_AND_SET_OID(cert->inhibitAnyOidSet);
                 WOLFSSL_MSG("Inhibit anyPolicy extension not supported yet.");
                 break;
 
             default:
+            #ifndef WOLFSSL_NO_ASN_STRICT
                 /* While it is a failure to not support critical extensions,
                  * still parse the certificate ignoring the unsupported
@@ -6006,4 +7587,5 @@
                 if (critical)
                     criticalFail = 1;
+            #endif
                 break;
         }
@@ -6048,4 +7630,5 @@
 }
 
+
 /* from SSL proper, for locking can't do find here anymore */
 #ifdef __cplusplus
@@ -6101,4 +7684,270 @@
 #endif
 
+#ifdef WOLFSSL_SMALL_CERT_VERIFY
+/* Only quick step through the certificate to find fields that are then used
+ * in certificate signature verification.
+ * Must use the signature OID from the signed part of the certificate.
+ *
+ * This is only for minimizing dynamic memory usage during TLS certificate
+ * chain processing.
+ * Doesn't support:
+ *   OCSP Only: alt lookup using subject and pub key w/o sig check
+ */
+int CheckCertSignature(const byte* cert, word32 certSz, void* heap, void* cm)
+{
+#ifndef WOLFSSL_SMALL_STACK
+    SignatureCtx  sigCtx[1];
+#else
+    SignatureCtx* sigCtx;
+#endif
+    byte          hash[KEYID_SIZE];
+    Signer*       ca = NULL;
+    word32        idx = 0;
+    int           len;
+    word32        tbsCertIdx;
+    word32        sigIndex;
+    word32        signatureOID;
+    word32        oid;
+    word32        issuerIdx;
+    word32        issuerSz;
+#ifndef NO_SKID
+    int           extLen;
+    word32        extIdx;
+    word32        extEndIdx;
+    int           extAuthKeyIdSet = 0;
+#endif
+    int    ret = 0;
+
+    if (cert == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    sigCtx = XMALLOC(sizeof(*sigCtx), heap, DYNAMIC_TYPE_SIGNATURE);
+    if (sigCtx == NULL)
+        return MEMORY_E;
+#endif
+    InitSignatureCtx(sigCtx, heap, INVALID_DEVID);
+
+    /* Certificate SEQUENCE */
+    if (GetSequence(cert, &idx, &len, certSz) < 0)
+        ret = ASN_PARSE_E;
+    if (ret == 0) {
+        tbsCertIdx = idx;
+
+        /* TBSCertificate SEQUENCE */
+        if (GetSequence(cert, &idx, &len, certSz) < 0)
+            ret = ASN_PARSE_E;
+            }
+    if (ret == 0) {
+        sigIndex = len + idx;
+
+        if ((idx + 1) > certSz)
+            ret = BUFFER_E;
+    }
+    if (ret == 0) {
+        /* version - optional */
+        if (cert[idx] == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED)) {
+            idx++;
+            if (GetLength(cert, &idx, &len, certSz) < 0)
+                ret = ASN_PARSE_E;
+            idx += len;
+        }
+            }
+
+    if (ret == 0) {
+        /* serialNumber */
+        if (GetASNHeader(cert, ASN_INTEGER, &idx, &len, certSz) < 0)
+            ret = ASN_PARSE_E;
+        }
+    if (ret == 0) {
+        idx += len;
+
+        /* signature */
+        if (GetAlgoId(cert, &idx, &signatureOID, oidSigType, certSz) < 0)
+            ret = ASN_PARSE_E;
+    }
+
+    if (ret == 0) {
+        issuerIdx = idx;
+        /* issuer */
+        if (GetSequence(cert, &idx, &len, certSz) < 0)
+            ret = ASN_PARSE_E;
+    }
+    if (ret == 0) {
+        issuerSz = len + idx - issuerIdx;
+    }
+#ifndef NO_SKID
+    if (ret == 0) {
+        idx += len;
+
+        /* validity */
+        if (GetSequence(cert, &idx, &len, certSz) < 0)
+            ret = ASN_PARSE_E;
+    }
+    if (ret == 0) {
+        idx += len;
+
+        /* subject */
+        if (GetSequence(cert, &idx, &len, certSz) < 0)
+            ret = ASN_PARSE_E;
+    }
+    if (ret == 0) {
+        idx += len;
+
+        /* subjectPublicKeyInfo */
+        if (GetSequence(cert, &idx, &len, certSz) < 0)
+            ret = ASN_PARSE_E;
+    }
+    if (ret == 0) {
+        idx += len;
+
+        if ((idx + 1) > certSz)
+            ret = BUFFER_E;
+    }
+    if (ret == 0) {
+        /* issuerUniqueID - optional */
+        if (cert[idx] == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 1)) {
+            idx++;
+            if (GetLength(cert, &idx, &len, certSz) < 0)
+                ret = ASN_PARSE_E;
+            idx += len;
+        }
+    }
+    if (ret == 0) {
+        if ((idx + 1) > certSz)
+            ret = BUFFER_E;
+    }
+    if (ret == 0) {
+        /* subjectUniqueID - optional */
+        if (cert[idx] == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 2)) {
+            idx++;
+            if (GetLength(cert, &idx, &len, certSz) < 0)
+                ret = ASN_PARSE_E;
+            idx += len;
+        }
+    }
+
+    if (ret == 0) {
+        if ((idx + 1) > certSz)
+            ret = BUFFER_E;
+    }
+    /* extensions - optional */
+    if (ret == 0 && cert[idx] == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 3)) {
+        idx++;
+        if (GetLength(cert, &idx, &extLen, certSz) < 0)
+            ret = ASN_PARSE_E;
+        if (ret == 0) {
+            if (GetSequence(cert, &idx, &extLen, certSz) < 0)
+                ret = ASN_PARSE_E;
+        }
+        if (ret == 0) {
+            extEndIdx = idx + extLen;
+
+            /* Check each extension for the ones we want. */
+            while (ret == 0 && idx < extEndIdx) {
+                if (GetSequence(cert, &idx, &len, certSz) < 0)
+                    ret = ASN_PARSE_E;
+                if (ret == 0) {
+                    extIdx = idx;
+                    if (GetObjectId(cert, &extIdx, &oid, oidCertExtType,
+                                                                  certSz) < 0) {
+                        ret = ASN_PARSE_E;
+                    }
+                }
+                if (ret == 0) {
+                    if (cert[extIdx] == ASN_BOOLEAN) {
+                        if (GetBoolean(cert, &extIdx, certSz) < 0)
+                            ret = ASN_PARSE_E;
+                    }
+                }
+                if (ret == 0) {
+                    if (GetOctetString(cert, &extIdx, &extLen, certSz) < 0)
+                        ret = ASN_PARSE_E;
+                }
+
+                if (ret == 0) {
+                    switch (oid) {
+                    case AUTH_KEY_OID:
+                        extAuthKeyIdSet = 1;
+                        if (GetSequence(cert, &extIdx, &extLen, certSz) < 0)
+                            ret = ASN_PARSE_E;
+
+                        if (ret == 0 &&
+                                 cert[extIdx++] == (ASN_CONTEXT_SPECIFIC | 0)) {
+                            if (GetLength(cert, &extIdx, &extLen, certSz) <= 0)
+                                ret = ASN_PARSE_E;
+                            if (ret == 0) {
+                                if (extLen == KEYID_SIZE)
+                                    XMEMCPY(hash, cert + extIdx, extLen);
+                                else {
+                                    ret = CalcHashId(cert + extIdx, extLen,
+                                                                          hash);
+                                }
+                            }
+                        }
+                        break;
+
+                    default:
+                        break;
+                    }
+                }
+                idx += len;
+            }
+        }
+    }
+
+    if (ret == 0) {
+        if (extAuthKeyIdSet)
+            ca = GetCA(cm, hash);
+        if (ca == NULL) {
+            ret = CalcHashId(cert + issuerIdx, issuerSz, hash);
+            if (ret == 0)
+                ca = GetCAByName(cm, hash);
+        }
+    }
+#else
+    if (ret == 0) {
+        ret = CalcHashId(cert + issuerIdx, issuerSz, hash);
+        if (ret == 0)
+            ca = GetCA(cm, hash);
+    }
+#endif /* !NO_SKID */
+    if (ca == NULL)
+        ret = ASN_NO_SIGNER_E;
+
+    if (ret == 0) {
+        idx = sigIndex;
+        /* signatureAlgorithm */
+        if (GetAlgoId(cert, &idx, &oid, oidSigType, certSz) < 0)
+            ret = ASN_PARSE_E;
+    }
+    if (ret == 0) {
+        if (oid != signatureOID)
+            ret = ASN_SIG_OID_E;
+    }
+    if (ret == 0) {
+        /* signatureValue */
+        if (CheckBitString(cert, &idx, &len, certSz, 1, NULL) < 0)
+            ret = ASN_PARSE_E;
+    }
+
+    if (ret == 0) {
+        ret = ConfirmSignature(sigCtx, cert + tbsCertIdx, sigIndex - tbsCertIdx,
+                               ca->publicKey, ca->pubKeySize, ca->keyOID,
+                               cert + idx, len, signatureOID);
+        if (ret != WC_PENDING_E) {
+            WOLFSSL_MSG("Confirm signature failed");
+        }
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    if (sigCtx != NULL)
+        XFREE(sigCtx, heap, DYNAMIC_TYPE_SIGNATURE);
+#endif
+    return ret;
+}
+#endif /* WOLFSSL_SMALL_CERT_VERIFY */
+
 int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm)
 {
@@ -6107,4 +7956,5 @@
     int    criticalExt = 0;
     word32 confirmOID;
+    int    selfSigned = 0;
 
     if (cert == NULL) {
@@ -6159,11 +8009,6 @@
         if (cert->extSubjKeyIdSet == 0 && cert->publicKey != NULL &&
                                                         cert->pubKeySize > 0) {
-        #ifdef NO_SHA
-            ret = wc_Sha256Hash(cert->publicKey, cert->pubKeySize,
+            ret = CalcHashId(cert->publicKey, cert->pubKeySize,
                                                             cert->extSubjKeyId);
-        #else
-            ret = wc_ShaHash(cert->publicKey, cert->pubKeySize,
-                                                            cert->extSubjKeyId);
-        #endif /* NO_SHA */
             if (ret != 0)
                 return ret;
@@ -6197,16 +8042,23 @@
     #else
             cert->ca = GetCA(cm, cert->issuerHash);
+            if (XMEMCMP(cert->issuerHash, cert->subjectHash, KEYID_SIZE) == 0)
+                selfSigned = 1;
     #endif /* !NO_SKID */
 
             WOLFSSL_MSG("About to verify certificate signature");
             if (cert->ca) {
-                if (cert->isCA) {
-                    if (cert->ca->pathLengthSet) {
+                if (cert->isCA && cert->ca->pathLengthSet) {
+                    if (selfSigned) {
+                        if (cert->ca->pathLength != 0) {
+                           WOLFSSL_MSG("Root CA with path length > 0");
+                           return ASN_PATHLEN_INV_E;
+                        }
+                    }
+                    else {
                         if (cert->ca->pathLength == 0) {
                             WOLFSSL_MSG("CA with path length 0 signing a CA");
                             return ASN_PATHLEN_INV_E;
                         }
-                        if (cert->pathLengthSet &&
-                            cert->pathLength >= cert->ca->pathLength) {
+                        else if (cert->pathLength >= cert->ca->pathLength) {
 
                             WOLFSSL_MSG("CA signing CA with longer path length");
@@ -6218,11 +8070,6 @@
         #ifdef HAVE_OCSP
                 /* Need the CA's public key hash for OCSP */
-            #ifdef NO_SHA
-                ret = wc_Sha256Hash(cert->ca->publicKey, cert->ca->pubKeySize,
+            ret = CalcHashId(cert->ca->publicKey, cert->ca->pubKeySize,
                                                            cert->issuerKeyHash);
-            #else
-                ret = wc_ShaHash(cert->ca->publicKey, cert->ca->pubKeySize,
-                                                           cert->issuerKeyHash);
-            #endif /* NO_SHA */
                 if (ret != 0)
                     return ret;
@@ -6247,5 +8094,8 @@
                     return ret;
                 }
+            }
             #ifndef IGNORE_NAME_CONSTRAINTS
+            if (verify == VERIFY || verify == VERIFY_OCSP ||
+                                                        verify == VERIFY_NAME) {
                 /* check that this cert's name is permitted by the signer's
                  * name constraints */
@@ -6254,6 +8104,6 @@
                     return ASN_NAME_INVALID_E;
                 }
-            #endif /* IGNORE_NAME_CONSTRAINTS */
-            }
+            }
+        #endif /* IGNORE_NAME_CONSTRAINTS */
         }
         else {
@@ -6294,4 +8144,7 @@
         signer->pathLengthSet = 0;
         signer->pathLength = 0;
+    #ifdef WOLFSSL_SIGNER_DER_CERT
+        signer->derCert    = NULL;
+    #endif
         signer->next       = NULL;
     }
@@ -6306,5 +8159,5 @@
 {
     XFREE(signer->name, heap, DYNAMIC_TYPE_SUBJECT_CN);
-    XFREE(signer->publicKey, heap, DYNAMIC_TYPE_PUBLIC_KEY);
+    XFREE((void*)signer->publicKey, heap, DYNAMIC_TYPE_PUBLIC_KEY);
 #ifndef IGNORE_NAME_CONSTRAINTS
     if (signer->permittedNames)
@@ -6312,4 +8165,7 @@
     if (signer->excludedNames)
         FreeNameSubtrees(signer->excludedNames, heap);
+#endif
+#ifdef WOLFSSL_SIGNER_DER_CERT
+    FreeDer(&signer->derCert);
 #endif
     XFREE(signer, heap, DYNAMIC_TYPE_SIGNER);
@@ -6476,31 +8332,414 @@
 
 
-
-const char* BEGIN_CERT         = "-----BEGIN CERTIFICATE-----";
-const char* END_CERT           = "-----END CERTIFICATE-----";
-const char* BEGIN_CERT_REQ     = "-----BEGIN CERTIFICATE REQUEST-----";
-const char* END_CERT_REQ       = "-----END CERTIFICATE REQUEST-----";
-const char* BEGIN_DH_PARAM     = "-----BEGIN DH PARAMETERS-----";
-const char* END_DH_PARAM       = "-----END DH PARAMETERS-----";
-const char* BEGIN_DSA_PARAM    = "-----BEGIN DSA PARAMETERS-----";
-const char* END_DSA_PARAM      = "-----END DSA PARAMETERS-----";
-const char* BEGIN_X509_CRL     = "-----BEGIN X509 CRL-----";
-const char* END_X509_CRL       = "-----END X509 CRL-----";
-const char* BEGIN_RSA_PRIV     = "-----BEGIN RSA PRIVATE KEY-----";
-const char* END_RSA_PRIV       = "-----END RSA PRIVATE KEY-----";
-const char* BEGIN_PRIV_KEY     = "-----BEGIN PRIVATE KEY-----";
-const char* END_PRIV_KEY       = "-----END PRIVATE KEY-----";
-const char* BEGIN_ENC_PRIV_KEY = "-----BEGIN ENCRYPTED PRIVATE KEY-----";
-const char* END_ENC_PRIV_KEY   = "-----END ENCRYPTED PRIVATE KEY-----";
-const char* BEGIN_EC_PRIV      = "-----BEGIN EC PRIVATE KEY-----";
-const char* END_EC_PRIV        = "-----END EC PRIVATE KEY-----";
-const char* BEGIN_DSA_PRIV     = "-----BEGIN DSA PRIVATE KEY-----";
-const char* END_DSA_PRIV       = "-----END DSA PRIVATE KEY-----";
-const char* BEGIN_PUB_KEY      = "-----BEGIN PUBLIC KEY-----";
-const char* END_PUB_KEY        = "-----END PUBLIC KEY-----";
-const char* BEGIN_EDDSA_PRIV   = "-----BEGIN EDDSA PRIVATE KEY-----";
-const char* END_EDDSA_PRIV     = "-----END EDDSA PRIVATE KEY-----";
-
-#if defined(WOLFSSL_KEY_GEN) || defined(WOLFSSL_CERT_GEN) || defined(OPENSSL_EXTRA)
+int AllocDer(DerBuffer** pDer, word32 length, int type, void* heap)
+{
+    int ret = BAD_FUNC_ARG;
+    if (pDer) {
+        int dynType = 0;
+        DerBuffer* der;
+
+        /* Determine dynamic type */
+        switch (type) {
+            case CA_TYPE:   dynType = DYNAMIC_TYPE_CA;   break;
+            case CERT_TYPE: dynType = DYNAMIC_TYPE_CERT; break;
+            case CRL_TYPE:  dynType = DYNAMIC_TYPE_CRL;  break;
+            case DSA_TYPE:  dynType = DYNAMIC_TYPE_DSA;  break;
+            case ECC_TYPE:  dynType = DYNAMIC_TYPE_ECC;  break;
+            case RSA_TYPE:  dynType = DYNAMIC_TYPE_RSA;  break;
+            default:        dynType = DYNAMIC_TYPE_KEY;  break;
+        }
+
+        /* Setup new buffer */
+        *pDer = (DerBuffer*)XMALLOC(sizeof(DerBuffer) + length, heap, dynType);
+        if (*pDer == NULL) {
+            return MEMORY_E;
+        }
+        XMEMSET(*pDer, 0, sizeof(DerBuffer) + length);
+
+        der = *pDer;
+        der->type = type;
+        der->dynType = dynType; /* Cache this for FreeDer */
+        der->heap = heap;
+        der->buffer = (byte*)der + sizeof(DerBuffer);
+        der->length = length;
+        ret = 0; /* Success */
+    }
+    return ret;
+}
+
+void FreeDer(DerBuffer** pDer)
+{
+    if (pDer && *pDer)
+    {
+        DerBuffer* der = (DerBuffer*)*pDer;
+
+        /* ForceZero private keys */
+        if (der->type == PRIVATEKEY_TYPE) {
+            ForceZero(der->buffer, der->length);
+}
+        der->buffer = NULL;
+        der->length = 0;
+        XFREE(der, der->heap, der->dynType);
+
+        *pDer = NULL;
+    }
+}
+
+int wc_AllocDer(DerBuffer** pDer, word32 length, int type, void* heap)
+{
+    return AllocDer(pDer, length, type, heap);
+}
+void wc_FreeDer(DerBuffer** pDer)
+{
+    FreeDer(pDer);
+}
+
+
+#if defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM)
+
+/* Max X509 header length indicates the max length + 2 ('\n', '\0') */
+#define MAX_X509_HEADER_SZ  (37 + 2)
+
+const char* const BEGIN_CERT           = "-----BEGIN CERTIFICATE-----";
+const char* const END_CERT             = "-----END CERTIFICATE-----";
+#ifdef WOLFSSL_CERT_REQ
+    const char* const BEGIN_CERT_REQ   = "-----BEGIN CERTIFICATE REQUEST-----";
+    const char* const END_CERT_REQ     = "-----END CERTIFICATE REQUEST-----";
+#endif
+#ifndef NO_DH
+    const char* const BEGIN_DH_PARAM   = "-----BEGIN DH PARAMETERS-----";
+    const char* const END_DH_PARAM     = "-----END DH PARAMETERS-----";
+#endif
+#ifndef NO_DSA
+    const char* const BEGIN_DSA_PARAM  = "-----BEGIN DSA PARAMETERS-----";
+    const char* const END_DSA_PARAM    = "-----END DSA PARAMETERS-----";
+#endif
+const char* const BEGIN_X509_CRL       = "-----BEGIN X509 CRL-----";
+const char* const END_X509_CRL         = "-----END X509 CRL-----";
+const char* const BEGIN_RSA_PRIV       = "-----BEGIN RSA PRIVATE KEY-----";
+const char* const END_RSA_PRIV         = "-----END RSA PRIVATE KEY-----";
+const char* const BEGIN_PRIV_KEY       = "-----BEGIN PRIVATE KEY-----";
+const char* const END_PRIV_KEY         = "-----END PRIVATE KEY-----";
+const char* const BEGIN_ENC_PRIV_KEY   = "-----BEGIN ENCRYPTED PRIVATE KEY-----";
+const char* const END_ENC_PRIV_KEY     = "-----END ENCRYPTED PRIVATE KEY-----";
+#ifdef HAVE_ECC
+    const char* const BEGIN_EC_PRIV    = "-----BEGIN EC PRIVATE KEY-----";
+    const char* const END_EC_PRIV      = "-----END EC PRIVATE KEY-----";
+#endif
+#if defined(HAVE_ECC) || defined(HAVE_ED25519) || !defined(NO_DSA)
+    const char* const BEGIN_DSA_PRIV   = "-----BEGIN DSA PRIVATE KEY-----";
+    const char* const END_DSA_PRIV     = "-----END DSA PRIVATE KEY-----";
+#endif
+const char* const BEGIN_PUB_KEY        = "-----BEGIN PUBLIC KEY-----";
+const char* const END_PUB_KEY          = "-----END PUBLIC KEY-----";
+#ifdef HAVE_ED25519
+    const char* const BEGIN_EDDSA_PRIV = "-----BEGIN EDDSA PRIVATE KEY-----";
+    const char* const END_EDDSA_PRIV   = "-----END EDDSA PRIVATE KEY-----";
+#endif
+#ifdef HAVE_CRL
+    const char *const BEGIN_CRL = "-----BEGIN X509 CRL-----";
+    const char* const END_CRL   = "-----END X509 CRL-----";
+#endif
+
+
+static WC_INLINE char* SkipEndOfLineChars(char* line, const char* endOfLine)
+{
+    /* eat end of line characters */
+    while (line < endOfLine &&
+              (line[0] == '\r' || line[0] == '\n')) {
+        line++;
+    }
+    return line;
+    }
+
+int wc_PemGetHeaderFooter(int type, const char** header, const char** footer)
+{
+    int ret = BAD_FUNC_ARG;
+
+    switch (type) {
+        case CA_TYPE:       /* same as below */
+        case TRUSTED_PEER_TYPE:
+        case CERT_TYPE:
+            if (header) *header = BEGIN_CERT;
+            if (footer) *footer = END_CERT;
+            ret = 0;
+            break;
+
+        case CRL_TYPE:
+            if (header) *header = BEGIN_X509_CRL;
+            if (footer) *footer = END_X509_CRL;
+            ret = 0;
+            break;
+    #ifndef NO_DH
+        case DH_PARAM_TYPE:
+            if (header) *header = BEGIN_DH_PARAM;
+            if (footer) *footer = END_DH_PARAM;
+            ret = 0;
+            break;
+    #endif
+    #ifndef NO_DSA
+        case DSA_PARAM_TYPE:
+            if (header) *header = BEGIN_DSA_PARAM;
+            if (footer) *footer = END_DSA_PARAM;
+            ret = 0;
+            break;
+    #endif
+    #ifdef WOLFSSL_CERT_REQ
+        case CERTREQ_TYPE:
+            if (header) *header = BEGIN_CERT_REQ;
+            if (footer) *footer = END_CERT_REQ;
+            ret = 0;
+            break;
+    #endif
+    #ifndef NO_DSA
+        case DSA_TYPE:
+        case DSA_PRIVATEKEY_TYPE:
+            if (header) *header = BEGIN_DSA_PRIV;
+            if (footer) *footer = END_DSA_PRIV;
+            ret = 0;
+            break;
+    #endif
+    #ifdef HAVE_ECC
+        case ECC_TYPE:
+        case ECC_PRIVATEKEY_TYPE:
+            if (header) *header = BEGIN_EC_PRIV;
+            if (footer) *footer = END_EC_PRIV;
+            ret = 0;
+            break;
+    #endif
+        case RSA_TYPE:
+        case PRIVATEKEY_TYPE:
+            if (header) *header = BEGIN_RSA_PRIV;
+            if (footer) *footer = END_RSA_PRIV;
+            ret = 0;
+            break;
+    #ifdef HAVE_ED25519
+        case ED25519_TYPE:
+        case EDDSA_PRIVATEKEY_TYPE:
+            if (header) *header = BEGIN_EDDSA_PRIV;
+            if (footer) *footer = END_EDDSA_PRIV;
+            ret = 0;
+            break;
+    #endif
+        case PUBLICKEY_TYPE:
+            if (header) *header = BEGIN_PUB_KEY;
+            if (footer) *footer = END_PUB_KEY;
+            ret = 0;
+            break;
+        case PKCS8_PRIVATEKEY_TYPE:
+            if (header) *header = BEGIN_PRIV_KEY;
+            if (footer) *footer = END_PRIV_KEY;
+            ret = 0;
+            break;
+        case PKCS8_ENC_PRIVATEKEY_TYPE:
+            if (header) *header = BEGIN_ENC_PRIV_KEY;
+            if (footer) *footer = END_ENC_PRIV_KEY;
+            ret = 0;
+            break;
+        default:
+            break;
+    }
+    return ret;
+}
+
+#ifdef WOLFSSL_ENCRYPTED_KEYS
+
+static const char* const kProcTypeHeader = "Proc-Type";
+static const char* const kDecInfoHeader = "DEK-Info";
+
+#ifdef WOLFSSL_PEM_TO_DER
+#ifndef NO_DES3
+    static const char* const kEncTypeDes = "DES-CBC";
+    static const char* const kEncTypeDes3 = "DES-EDE3-CBC";
+#endif
+#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_128)
+    static const char* const kEncTypeAesCbc128 = "AES-128-CBC";
+#endif
+#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_192)
+    static const char* const kEncTypeAesCbc192 = "AES-192-CBC";
+#endif
+#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_256)
+    static const char* const kEncTypeAesCbc256 = "AES-256-CBC";
+#endif
+
+int wc_EncryptedInfoGet(EncryptedInfo* info, const char* cipherInfo)
+{
+    int ret = 0;
+
+    if (info == NULL || cipherInfo == NULL)
+        return BAD_FUNC_ARG;
+
+    /* determine cipher information */
+#ifndef NO_DES3
+    if (XSTRNCMP(cipherInfo, kEncTypeDes, XSTRLEN(kEncTypeDes)) == 0) {
+        info->cipherType = WC_CIPHER_DES;
+        info->keySz = DES_KEY_SIZE;
+        if (info->ivSz == 0) info->ivSz  = DES_IV_SIZE;
+    }
+    else if (XSTRNCMP(cipherInfo, kEncTypeDes3, XSTRLEN(kEncTypeDes3)) == 0) {
+        info->cipherType = WC_CIPHER_DES3;
+        info->keySz = DES3_KEY_SIZE;
+        if (info->ivSz == 0) info->ivSz  = DES_IV_SIZE;
+    }
+    else
+#endif /* !NO_DES3 */
+#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_128)
+    if (XSTRNCMP(cipherInfo, kEncTypeAesCbc128, XSTRLEN(kEncTypeAesCbc128)) == 0) {
+        info->cipherType = WC_CIPHER_AES_CBC;
+        info->keySz = AES_128_KEY_SIZE;
+        if (info->ivSz == 0) info->ivSz  = AES_IV_SIZE;
+    }
+    else
+#endif
+#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_192)
+    if (XSTRNCMP(cipherInfo, kEncTypeAesCbc192, XSTRLEN(kEncTypeAesCbc192)) == 0) {
+        info->cipherType = WC_CIPHER_AES_CBC;
+        info->keySz = AES_192_KEY_SIZE;
+        if (info->ivSz == 0) info->ivSz  = AES_IV_SIZE;
+    }
+    else
+#endif
+#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_256)
+    if (XSTRNCMP(cipherInfo, kEncTypeAesCbc256, XSTRLEN(kEncTypeAesCbc256)) == 0) {
+        info->cipherType = WC_CIPHER_AES_CBC;
+        info->keySz = AES_256_KEY_SIZE;
+        if (info->ivSz == 0) info->ivSz  = AES_IV_SIZE;
+    }
+    else
+#endif
+    {
+        ret = NOT_COMPILED_IN;
+    }
+    return ret;
+}
+
+int wc_EncryptedInfoParse(EncryptedInfo* info, char** pBuffer, size_t bufSz)
+{
+    int err = 0;
+    char*  bufferStart;
+    char*  bufferEnd;
+    char*  line;
+    word32 lineSz;
+    char*  finish;
+    word32 finishSz;
+    char*  start = NULL;
+    word32 startSz;
+    char*  newline = NULL;
+
+    if (info == NULL || pBuffer == NULL || bufSz == 0)
+        return BAD_FUNC_ARG;
+
+    bufferStart = *pBuffer;
+    bufferEnd = bufferStart + bufSz;
+
+    /* find encrypted info marker */
+    line = XSTRNSTR(bufferStart, kProcTypeHeader,
+                    min((word32)bufSz, PEM_LINE_LEN));
+    if (line != NULL) {
+        if (line >= bufferEnd) {
+            return BUFFER_E;
+        }
+
+        lineSz = (word32)(bufferEnd - line);
+
+        /* find DEC-Info marker */
+        start = XSTRNSTR(line, kDecInfoHeader, min(lineSz, PEM_LINE_LEN));
+
+        if (start == NULL)
+            return BUFFER_E;
+
+        /* skip dec-info and ": " */
+        start += XSTRLEN(kDecInfoHeader);
+        if (start >= bufferEnd)
+            return BUFFER_E;
+
+        if (start[0] == ':') {
+            start++;
+            if (start >= bufferEnd)
+                return BUFFER_E;
+        }
+        if (start[0] == ' ')
+            start++;
+
+        startSz = (word32)(bufferEnd - start);
+        finish = XSTRNSTR(start, ",", min(startSz, PEM_LINE_LEN));
+
+        if ((start != NULL) && (finish != NULL) && (start < finish)) {
+            if (finish >= bufferEnd) {
+                return BUFFER_E;
+            }
+
+            finishSz = (word32)(bufferEnd - finish);
+            newline = XSTRNSTR(finish, "\r", min(finishSz, PEM_LINE_LEN));
+
+            /* get cipher name */
+            if (NAME_SZ < (finish - start)) /* buffer size of info->name */
+                return BUFFER_E;
+            if (XMEMCPY(info->name, start, finish - start) == NULL)
+                return BUFFER_E;
+            info->name[finish - start] = '\0'; /* null term */
+
+            /* populate info */
+            err = wc_EncryptedInfoGet(info, info->name);
+            if (err != 0)
+                return err;
+
+            /* get IV */
+            if (finishSz < info->ivSz + 1)
+                return BUFFER_E;
+
+            if (newline == NULL) {
+                newline = XSTRNSTR(finish, "\n", min(finishSz,
+                                                     PEM_LINE_LEN));
+            }
+            if ((newline != NULL) && (newline > finish)) {
+                info->ivSz = (word32)(newline - (finish + 1));
+                if (XMEMCPY(info->iv, finish + 1, info->ivSz) == NULL)
+                    return BUFFER_E;
+                info->set = 1;
+            }
+            else
+                return BUFFER_E;
+        }
+        else
+            return BUFFER_E;
+
+        /* eat end of line characters */
+        newline = SkipEndOfLineChars(newline, bufferEnd);
+
+        /* return new headerEnd */
+        if (pBuffer)
+            *pBuffer = newline;
+    }
+
+    return err;
+}
+#endif /* WOLFSSL_PEM_TO_DER */
+
+#ifdef WOLFSSL_DER_TO_PEM
+static int wc_EncryptedInfoAppend(char* dest, int destSz, char* cipherInfo)
+{
+    if (cipherInfo != NULL) {
+        int cipherInfoStrLen = (int)XSTRLEN((char*)cipherInfo);
+
+        if (cipherInfoStrLen > HEADER_ENCRYPTED_KEY_SIZE - (9+14+10+3))
+            cipherInfoStrLen = HEADER_ENCRYPTED_KEY_SIZE - (9+14+10+3);
+
+        if (destSz - (int)XSTRLEN(dest) >= cipherInfoStrLen + (9+14+8+2+2+1)) {
+            /* strncat's src length needs to include the NULL */
+            XSTRNCAT(dest, kProcTypeHeader, 10);
+            XSTRNCAT(dest, ": 4,ENCRYPTED\n", 15);
+            XSTRNCAT(dest, kDecInfoHeader, 9);
+            XSTRNCAT(dest, ": ", 3);
+            XSTRNCAT(dest, cipherInfo, destSz - (int)XSTRLEN(dest) - 1);
+            XSTRNCAT(dest, "\n\n", 4);
+        }
+    }
+    return 0;
+}
+#endif /* WOLFSSL_DER_TO_PEM */
+#endif /* WOLFSSL_ENCRYPTED_KEYS */
+
+#ifdef WOLFSSL_DER_TO_PEM
 
 /* Used for compatibility API */
@@ -6516,20 +8755,27 @@
              byte *cipher_info, int type)
 {
+    const char* headerStr = NULL;
+    const char* footerStr = NULL;
 #ifdef WOLFSSL_SMALL_STACK
     char* header = NULL;
     char* footer = NULL;
 #else
-    char header[40 + HEADER_ENCRYPTED_KEY_SIZE];
-    char footer[40];
-#endif
-
-    int headerLen = 40 + HEADER_ENCRYPTED_KEY_SIZE;
-    int footerLen = 40;
+    char header[MAX_X509_HEADER_SZ + HEADER_ENCRYPTED_KEY_SIZE];
+    char footer[MAX_X509_HEADER_SZ];
+#endif
+    int headerLen = MAX_X509_HEADER_SZ + HEADER_ENCRYPTED_KEY_SIZE;
+    int footerLen = MAX_X509_HEADER_SZ;
     int i;
     int err;
     int outLen;   /* return length or error */
 
+    (void)cipher_info;
+
     if (der == output)      /* no in place conversion */
         return BAD_FUNC_ARG;
+
+    err = wc_PemGetHeaderFooter(type, &headerStr, &footerStr);
+    if (err != 0)
+        return err;
 
 #ifdef WOLFSSL_SMALL_STACK
@@ -6544,84 +8790,25 @@
     }
 #endif
-    if (type == CERT_TYPE) {
-        XSTRNCPY(header, BEGIN_CERT, headerLen);
-        XSTRNCAT(header, "\n", 1);
-
-        XSTRNCPY(footer, END_CERT, footerLen);
-        XSTRNCAT(footer, "\n", 1);
-    }
-    else if (type == PRIVATEKEY_TYPE) {
-        XSTRNCPY(header, BEGIN_RSA_PRIV, headerLen);
-        XSTRNCAT(header, "\n", 1);
-
-        XSTRNCPY(footer, END_RSA_PRIV, footerLen);
-        XSTRNCAT(footer, "\n", 1);
-    }
-#ifndef NO_DSA
-    else if (type == DSA_PRIVATEKEY_TYPE) {
-        XSTRNCPY(header, BEGIN_DSA_PRIV, headerLen);
-        XSTRNCAT(header, "\n", 1);
-
-        XSTRNCPY(footer, END_DSA_PRIV, footerLen);
-        XSTRNCAT(footer, "\n", 1);
-    }
-#endif
-#ifdef HAVE_ECC
-    else if (type == ECC_PRIVATEKEY_TYPE) {
-        XSTRNCPY(header, BEGIN_EC_PRIV, headerLen);
-        XSTRNCAT(header, "\n", 1);
-
-        XSTRNCPY(footer, END_EC_PRIV, footerLen);
-        XSTRNCAT(footer, "\n", 1);
-    }
-#endif
-#ifdef HAVE_ED25519
-    else if (type == EDDSA_PRIVATEKEY_TYPE) {
-        XSTRNCPY(header, BEGIN_EDDSA_PRIV, headerLen);
-        XSTRNCAT(header, "\n", 1);
-
-        XSTRNCPY(footer, END_EDDSA_PRIV, footerLen);
-        XSTRNCAT(footer, "\n", 1);
-    }
-#endif
-#ifdef WOLFSSL_CERT_REQ
-    else if (type == CERTREQ_TYPE)
-    {
-        XSTRNCPY(header, BEGIN_CERT_REQ, headerLen);
-        XSTRNCAT(header, "\n", 1);
-
-        XSTRNCPY(footer, END_CERT_REQ, footerLen);
-        XSTRNCAT(footer, "\n", 1);
-    }
-#endif
-#ifdef HAVE_CRL
-    else if (type == CRL_TYPE)
-    {
-        XSTRNCPY(header, BEGIN_X509_CRL, headerLen);
-        XSTRNCAT(header, "\n", 1);
-
-        XSTRNCPY(footer, END_X509_CRL, footerLen);
-        XSTRNCAT(footer, "\n", 1);
-    }
-#endif
-    else {
-#ifdef WOLFSSL_SMALL_STACK
+
+    /* build header and footer based on type */
+    XSTRNCPY(header, headerStr, headerLen - 1);
+    header[headerLen - 1] = 0;
+    XSTRNCPY(footer, footerStr, footerLen - 1);
+    footer[footerLen - 1] = 0;
+
+    /* add new line to end */
+    XSTRNCAT(header, "\n", 2);
+    XSTRNCAT(footer, "\n", 2);
+
+#ifdef WOLFSSL_ENCRYPTED_KEYS
+    err = wc_EncryptedInfoAppend(header, headerLen, (char*)cipher_info);
+    if (err != 0) {
+    #ifdef WOLFSSL_SMALL_STACK
         XFREE(header, NULL, DYNAMIC_TYPE_TMP_BUFFER);
         XFREE(footer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
-        return BAD_FUNC_ARG;
-    }
-
-    /* extra header information for encrypted key */
-    if (cipher_info != NULL) {
-        size_t cipherInfoStrLen = XSTRLEN((char*)cipher_info);
-        if (cipherInfoStrLen > HEADER_ENCRYPTED_KEY_SIZE - (23+10+2))
-            cipherInfoStrLen = HEADER_ENCRYPTED_KEY_SIZE - (23+10+2);
-
-        XSTRNCAT(header, "Proc-Type: 4,ENCRYPTED\n", 23);
-        XSTRNCAT(header, "DEK-Info: ", 10);
-        XSTRNCAT(header, (char*)cipher_info, cipherInfoStrLen);
-        XSTRNCAT(header, "\n\n", 2);
-    }
+    #endif
+        return err;
+    }
+#endif
 
     headerLen = (int)XSTRLEN(header);
@@ -6693,8 +8880,541 @@
 }
 
-#endif /* WOLFSSL_KEY_GEN || WOLFSSL_CERT_GEN || OPENSSL_EXTRA */
+#endif /* WOLFSSL_DER_TO_PEM */
+
+#ifdef WOLFSSL_PEM_TO_DER
+
+/* Remove PEM header/footer, convert to ASN1, store any encrypted data
+   info->consumed tracks of PEM bytes consumed in case multiple parts */
+int PemToDer(const unsigned char* buff, long longSz, int type,
+              DerBuffer** pDer, void* heap, EncryptedInfo* info, int* eccKey)
+{
+    const char* header      = NULL;
+    const char* footer      = NULL;
+    char*       headerEnd;
+    char*       footerEnd;
+    char*       consumedEnd;
+    char*       bufferEnd   = (char*)(buff + longSz);
+    long        neededSz;
+    int         ret         = 0;
+    int         sz          = (int)longSz;
+    int         encrypted_key = 0;
+    DerBuffer*  der;
+    word32      algId = 0;
+
+    WOLFSSL_ENTER("PemToDer");
+
+    /* get PEM header and footer based on type */
+    ret = wc_PemGetHeaderFooter(type, &header, &footer);
+    if (ret != 0)
+        return ret;
+
+    /* map header if not found for type */
+    for (;;) {
+        headerEnd = XSTRNSTR((char*)buff, header, sz);
+
+        if (headerEnd || type != PRIVATEKEY_TYPE) {
+            break;
+        } else
+        if (header == BEGIN_RSA_PRIV) {
+            header =  BEGIN_PRIV_KEY;       footer = END_PRIV_KEY;
+        } else
+        if (header == BEGIN_PRIV_KEY) {
+            header =  BEGIN_ENC_PRIV_KEY;   footer = END_ENC_PRIV_KEY;
+        } else
+#ifdef HAVE_ECC
+        if (header == BEGIN_ENC_PRIV_KEY) {
+            header =  BEGIN_EC_PRIV;        footer = END_EC_PRIV;
+        } else
+        if (header == BEGIN_EC_PRIV) {
+            header =  BEGIN_DSA_PRIV;       footer = END_DSA_PRIV;
+        } else
+#endif
+#ifdef HAVE_ED25519
+    #ifdef HAVE_ECC
+        if (header == BEGIN_DSA_PRIV)
+    #else
+        if (header == BEGIN_ENC_PRIV_KEY)
+    #endif
+        {
+            header =  BEGIN_EDDSA_PRIV;     footer = END_EDDSA_PRIV;
+        } else
+#endif
+#ifdef HAVE_CRL
+        if (type == CRL_TYPE) {
+            header =  BEGIN_CRL;        footer = END_CRL;
+        } else
+#endif
+        {
+            break;
+        }
+    }
+
+    if (!headerEnd) {
+        WOLFSSL_MSG("Couldn't find PEM header");
+        return ASN_NO_PEM_HEADER;
+    }
+
+    headerEnd += XSTRLEN(header);
+
+    /* eat end of line characters */
+    headerEnd = SkipEndOfLineChars(headerEnd, bufferEnd);
+
+    if (type == PRIVATEKEY_TYPE) {
+        if (eccKey) {
+        #ifdef HAVE_ECC
+            *eccKey = (header == BEGIN_EC_PRIV) ? 1 : 0;
+        #else
+            *eccKey = 0;
+        #endif
+        }
+    }
+
+#ifdef WOLFSSL_ENCRYPTED_KEYS
+    if (info) {
+        ret = wc_EncryptedInfoParse(info, &headerEnd, bufferEnd - headerEnd);
+        if (ret < 0)
+            return ret;
+        if (info->set)
+            encrypted_key = 1;
+    }
+#endif /* WOLFSSL_ENCRYPTED_KEYS */
+
+    /* find footer */
+    footerEnd = XSTRNSTR((char*)buff, footer, sz);
+    if (!footerEnd) {
+        if (info)
+            info->consumed = longSz; /* No more certs if no footer */
+        return BUFFER_E;
+    }
+
+    consumedEnd = footerEnd + XSTRLEN(footer);
+
+    if (consumedEnd < bufferEnd) { /* handle no end of line on last line */
+        /* eat end of line characters */
+        consumedEnd = SkipEndOfLineChars(consumedEnd, bufferEnd);
+        /* skip possible null term */
+        if (consumedEnd < bufferEnd && consumedEnd[0] == '\0')
+            consumedEnd++;
+    }
+
+    if (info)
+        info->consumed = (long)(consumedEnd - (char*)buff);
+
+    /* set up der buffer */
+    neededSz = (long)(footerEnd - headerEnd);
+    if (neededSz > sz || neededSz <= 0)
+        return BUFFER_E;
+
+    ret = AllocDer(pDer, (word32)neededSz, type, heap);
+    if (ret < 0) {
+        return ret;
+    }
+    der = *pDer;
+
+    if (Base64_Decode((byte*)headerEnd, (word32)neededSz,
+                      der->buffer, &der->length) < 0)
+        return BUFFER_E;
+
+    if ((header == BEGIN_PRIV_KEY
+#ifdef HAVE_ECC
+         || header == BEGIN_EC_PRIV
+#endif
+        ) && !encrypted_key)
+    {
+        /* pkcs8 key, convert and adjust length */
+        if ((ret = ToTraditional_ex(der->buffer, der->length, &algId)) > 0) {
+            der->length = ret;
+        }
+        else {
+            /* ignore failure here and assume key is not pkcs8 wrapped */
+        }
+
+        return 0;
+    }
+
+#ifdef WOLFSSL_ENCRYPTED_KEYS
+    if (encrypted_key || header == BEGIN_ENC_PRIV_KEY) {
+        int   passwordSz = NAME_SZ;
+    #ifdef WOLFSSL_SMALL_STACK
+        char* password = NULL;
+    #else
+        char  password[NAME_SZ];
+    #endif
+
+        if (!info || !info->passwd_cb) {
+            WOLFSSL_MSG("No password callback set");
+            return NO_PASSWORD;
+        }
+
+    #ifdef WOLFSSL_SMALL_STACK
+        password = (char*)XMALLOC(passwordSz, heap, DYNAMIC_TYPE_STRING);
+        if (password == NULL)
+            return MEMORY_E;
+    #endif
+
+        /* get password */
+        ret = info->passwd_cb(password, passwordSz, PEM_PASS_READ,
+            info->passwd_userdata);
+        if (ret >= 0) {
+            passwordSz = ret;
+
+            /* convert and adjust length */
+            if (header == BEGIN_ENC_PRIV_KEY) {
+            #ifndef NO_PWDBASED
+                ret = ToTraditionalEnc(der->buffer, der->length,
+                                       password, passwordSz, &algId);
+
+                if (ret >= 0) {
+                    der->length = ret;
+                    if ((algId == ECDSAk) && (eccKey != NULL)) {
+                        *eccKey = 1;
+                    }
+                    ret = 0;
+                }
+            #else
+                ret = NOT_COMPILED_IN;
+            #endif
+            }
+            /* decrypt the key */
+            else {
+                ret = wc_BufferKeyDecrypt(info, der->buffer, der->length,
+                    (byte*)password, passwordSz, WC_MD5);
+            }
+            ForceZero(password, passwordSz);
+        }
+
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(password, heap, DYNAMIC_TYPE_STRING);
+    #endif
+    }
+#endif /* WOLFSSL_ENCRYPTED_KEYS */
+
+    return ret;
+}
+
+int wc_PemToDer(const unsigned char* buff, long longSz, int type,
+              DerBuffer** pDer, void* heap, EncryptedInfo* info, int* eccKey)
+{
+    return PemToDer(buff, longSz, type, pDer, heap, info, eccKey);
+}
+
+
+/* our KeyPemToDer password callback, password in userData */
+static WC_INLINE int OurPasswordCb(char* passwd, int sz, int rw, void* userdata)
+{
+    (void)rw;
+
+    if (userdata == NULL)
+        return 0;
+
+    XSTRNCPY(passwd, (char*)userdata, sz);
+    return min((word32)sz, (word32)XSTRLEN((char*)userdata));
+}
+
+/* Return bytes written to buff or < 0 for error */
+int wc_KeyPemToDer(const unsigned char* pem, int pemSz,
+                        unsigned char* buff, int buffSz, const char* pass)
+{
+    int            eccKey = 0;
+    int            ret;
+    DerBuffer*     der = NULL;
+#ifdef WOLFSSL_SMALL_STACK
+    EncryptedInfo* info = NULL;
+#else
+    EncryptedInfo  info[1];
+#endif
+
+    WOLFSSL_ENTER("wc_KeyPemToDer");
+
+    if (pem == NULL || buff == NULL || buffSz <= 0) {
+        WOLFSSL_MSG("Bad pem der args");
+        return BAD_FUNC_ARG;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), NULL,
+                                   DYNAMIC_TYPE_ENCRYPTEDINFO);
+    if (info == NULL)
+        return MEMORY_E;
+#endif
+
+    XMEMSET(info, 0, sizeof(EncryptedInfo));
+    info->passwd_cb = OurPasswordCb;
+    info->passwd_userdata = (void*)pass;
+
+    ret = PemToDer(pem, pemSz, PRIVATEKEY_TYPE, &der, NULL, info, &eccKey);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO);
+#endif
+
+    if (ret < 0) {
+        WOLFSSL_MSG("Bad Pem To Der");
+    }
+    else {
+        if (der->length <= (word32)buffSz) {
+            XMEMCPY(buff, der->buffer, der->length);
+            ret = der->length;
+        }
+        else {
+            WOLFSSL_MSG("Bad der length");
+            ret = BAD_FUNC_ARG;
+        }
+    }
+
+    FreeDer(&der);
+    return ret;
+}
+
+
+/* Return bytes written to buff or < 0 for error */
+int wc_CertPemToDer(const unsigned char* pem, int pemSz,
+                        unsigned char* buff, int buffSz, int type)
+{
+    int            eccKey = 0;
+    int            ret;
+    DerBuffer*     der = NULL;
+
+    WOLFSSL_ENTER("wc_CertPemToDer");
+
+    if (pem == NULL || buff == NULL || buffSz <= 0) {
+        WOLFSSL_MSG("Bad pem der args");
+        return BAD_FUNC_ARG;
+    }
+
+    if (type != CERT_TYPE && type != CA_TYPE && type != CERTREQ_TYPE) {
+        WOLFSSL_MSG("Bad cert type");
+        return BAD_FUNC_ARG;
+    }
+
+
+    ret = PemToDer(pem, pemSz, type, &der, NULL, NULL, &eccKey);
+    if (ret < 0) {
+        WOLFSSL_MSG("Bad Pem To Der");
+    }
+    else {
+        if (der->length <= (word32)buffSz) {
+            XMEMCPY(buff, der->buffer, der->length);
+            ret = der->length;
+        }
+        else {
+            WOLFSSL_MSG("Bad der length");
+            ret = BAD_FUNC_ARG;
+        }
+    }
+
+    FreeDer(&der);
+    return ret;
+}
+
+#endif /* WOLFSSL_PEM_TO_DER */
+#endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */
+
+
+#ifdef WOLFSSL_PEM_TO_DER
+#if defined(WOLFSSL_CERT_EXT) || defined(WOLFSSL_PUB_PEM_TO_DER)
+/* Return bytes written to buff or < 0 for error */
+int wc_PubKeyPemToDer(const unsigned char* pem, int pemSz,
+                           unsigned char* buff, int buffSz)
+{
+    int ret;
+    DerBuffer* der = NULL;
+
+    WOLFSSL_ENTER("wc_PubKeyPemToDer");
+
+    if (pem == NULL || buff == NULL || buffSz <= 0) {
+        WOLFSSL_MSG("Bad pem der args");
+        return BAD_FUNC_ARG;
+    }
+
+    ret = PemToDer(pem, pemSz, PUBLICKEY_TYPE, &der, NULL, NULL, NULL);
+    if (ret < 0) {
+        WOLFSSL_MSG("Bad Pem To Der");
+    }
+    else {
+        if (der->length <= (word32)buffSz) {
+            XMEMCPY(buff, der->buffer, der->length);
+            ret = der->length;
+        }
+        else {
+            WOLFSSL_MSG("Bad der length");
+            ret = BAD_FUNC_ARG;
+        }
+    }
+
+    FreeDer(&der);
+    return ret;
+}
+#endif /* WOLFSSL_CERT_EXT || WOLFSSL_PUB_PEM_TO_DER */
+#endif /* WOLFSSL_PEM_TO_DER */
+
+#ifndef NO_FILESYSTEM
+
+#ifdef WOLFSSL_CERT_GEN
+/* load pem cert from file into der buffer, return der size or error */
+int wc_PemCertToDer(const char* fileName, unsigned char* derBuf, int derSz)
+{
+#ifdef WOLFSSL_SMALL_STACK
+    byte   staticBuffer[1]; /* force XMALLOC */
+#else
+    byte   staticBuffer[FILE_BUFFER_SIZE];
+#endif
+    byte*  fileBuf = staticBuffer;
+    int    dynamic = 0;
+    int    ret     = 0;
+    long   sz      = 0;
+    XFILE  file;
+    DerBuffer* converted = NULL;
+
+    WOLFSSL_ENTER("wc_PemCertToDer");
+
+    if (fileName == NULL) {
+        ret = BAD_FUNC_ARG;
+    }
+    else {
+        file = XFOPEN(fileName, "rb");
+        if (file == XBADFILE) {
+            ret = BUFFER_E;
+        }
+    }
+
+    if (ret == 0) {
+        if(XFSEEK(file, 0, XSEEK_END) != 0)
+            ret = BUFFER_E;
+        sz = XFTELL(file);
+        XREWIND(file);
+
+        if (sz <= 0) {
+            ret = BUFFER_E;
+        }
+        else if (sz > (long)sizeof(staticBuffer)) {
+        #ifdef WOLFSSL_STATIC_MEMORY
+            WOLFSSL_MSG("File was larger then static buffer");
+            return MEMORY_E;
+        #endif
+            fileBuf = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE);
+            if (fileBuf == NULL)
+                ret = MEMORY_E;
+            else
+                dynamic = 1;
+        }
+
+        if (ret == 0) {
+            if ( (ret = (int)XFREAD(fileBuf, 1, sz, file)) != sz) {
+                ret = BUFFER_E;
+            }
+        #ifdef WOLFSSL_PEM_TO_DER
+            else {
+                ret = PemToDer(fileBuf, sz, CA_TYPE, &converted,  0, NULL,NULL);
+            }
+        #endif
+
+            if (ret == 0) {
+                if (converted->length < (word32)derSz) {
+                    XMEMCPY(derBuf, converted->buffer, converted->length);
+                    ret = converted->length;
+                }
+                else
+                    ret = BUFFER_E;
+            }
+
+            FreeDer(&converted);
+        }
+
+        XFCLOSE(file);
+        if (dynamic)
+            XFREE(fileBuf, NULL, DYNAMIC_TYPE_FILE);
+    }
+
+    return ret;
+}
+#endif /* WOLFSSL_CERT_GEN */
+
+#if defined(WOLFSSL_CERT_EXT) || defined(WOLFSSL_PUB_PEM_TO_DER)
+/* load pem public key from file into der buffer, return der size or error */
+int wc_PemPubKeyToDer(const char* fileName,
+                           unsigned char* derBuf, int derSz)
+{
+#ifdef WOLFSSL_SMALL_STACK
+    byte   staticBuffer[1]; /* force XMALLOC */
+#else
+    byte   staticBuffer[FILE_BUFFER_SIZE];
+#endif
+    byte*  fileBuf = staticBuffer;
+    int    dynamic = 0;
+    int    ret     = 0;
+    long   sz      = 0;
+    XFILE  file;
+    DerBuffer* converted = NULL;
+
+    WOLFSSL_ENTER("wc_PemPubKeyToDer");
+
+    if (fileName == NULL) {
+        ret = BAD_FUNC_ARG;
+    }
+    else {
+        file = XFOPEN(fileName, "rb");
+        if (file == XBADFILE) {
+            ret = BUFFER_E;
+        }
+    }
+
+    if (ret == 0) {
+        if(XFSEEK(file, 0, XSEEK_END) != 0)
+            ret = BUFFER_E;
+        sz = XFTELL(file);
+        XREWIND(file);
+
+        if (sz <= 0) {
+            ret = BUFFER_E;
+        }
+        else if (sz > (long)sizeof(staticBuffer)) {
+        #ifdef WOLFSSL_STATIC_MEMORY
+            WOLFSSL_MSG("File was larger then static buffer");
+            return MEMORY_E;
+        #endif
+            fileBuf = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE);
+            if (fileBuf == NULL)
+                ret = MEMORY_E;
+            else
+                dynamic = 1;
+        }
+        if (ret == 0) {
+            if ( (ret = (int)XFREAD(fileBuf, 1, sz, file)) != sz) {
+                ret = BUFFER_E;
+            }
+        #ifdef WOLFSSL_PEM_TO_DER
+            else {
+                ret = PemToDer(fileBuf, sz, PUBLICKEY_TYPE, &converted,
+                               0, NULL, NULL);
+            }
+        #endif
+
+            if (ret == 0) {
+                if (converted->length < (word32)derSz) {
+                    XMEMCPY(derBuf, converted->buffer, converted->length);
+                    ret = converted->length;
+                }
+                else
+                    ret = BUFFER_E;
+    }
+
+            FreeDer(&converted);
+    }
+
+        XFCLOSE(file);
+        if (dynamic)
+            XFREE(fileBuf, NULL, DYNAMIC_TYPE_FILE);
+    }
+
+    return ret;
+}
+#endif /* WOLFSSL_CERT_EXT || WOLFSSL_PUB_PEM_TO_DER */
+
+#endif /* !NO_FILESYSTEM */
+
 
 #if !defined(NO_RSA) && (defined(WOLFSSL_CERT_GEN) || \
-        (defined(WOLFSSL_KEY_GEN) && !defined(HAVE_USER_RSA)))
+    ((defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA)) && !defined(HAVE_USER_RSA)))
 /* USER RSA ifdef portions used instead of refactor in consideration for
    possible fips build */
@@ -6723,5 +9443,5 @@
     /* n */
 #ifdef WOLFSSL_SMALL_STACK
-    n = (byte*)XMALLOC(MAX_RSA_INT_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    n = (byte*)XMALLOC(MAX_RSA_INT_SZ, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
     if (n == NULL)
         return MEMORY_E;
@@ -6735,5 +9455,5 @@
     if (nSz < 0) {
 #ifdef WOLFSSL_SMALL_STACK
-        XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(n, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
         return nSz;
@@ -6742,8 +9462,8 @@
     /* e */
 #ifdef WOLFSSL_SMALL_STACK
-    e = (byte*)XMALLOC(MAX_RSA_E_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    e = (byte*)XMALLOC(MAX_RSA_E_SZ, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
     if (e == NULL) {
 #ifdef WOLFSSL_SMALL_STACK
-        XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(n, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
         return MEMORY_E;
@@ -6758,6 +9478,6 @@
     if (eSz < 0) {
 #ifdef WOLFSSL_SMALL_STACK
-        XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-        XFREE(e, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(n, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(e, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
         return eSz;
@@ -6769,6 +9489,6 @@
     if ( (seqSz + nSz + eSz) > outLen) {
 #ifdef WOLFSSL_SMALL_STACK
-        XFREE(n,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
-        XFREE(e,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(n,    key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(e,    key->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
         return BUFFER_E;
@@ -6781,8 +9501,8 @@
         byte* algo = NULL;
 
-        algo = (byte*)XMALLOC(MAX_ALGO_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        algo = (byte*)XMALLOC(MAX_ALGO_SZ, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
         if (algo == NULL) {
-            XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-            XFREE(e, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(n, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(e, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
             return MEMORY_E;
         }
@@ -6798,7 +9518,7 @@
         if ( (idx + algoSz + bitStringSz + seqSz + nSz + eSz) > outLen) {
             #ifdef WOLFSSL_SMALL_STACK
-                XFREE(n,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
-                XFREE(e,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
-                XFREE(algo, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(n,    key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(e,    key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(algo, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
             #endif
 
@@ -6813,5 +9533,5 @@
         idx += bitStringSz;
 #ifdef WOLFSSL_SMALL_STACK
-        XFREE(algo, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(algo, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
     }
@@ -6830,7 +9550,86 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    XFREE(n,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
-    XFREE(e,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
+    XFREE(n,    key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(e,    key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return idx;
+}
+
+int RsaPublicKeyDerSize(RsaKey* key, int with_header)
+{
+    byte* dummy = NULL;
+    byte seq[MAX_SEQ_SZ];
+    byte bitString[1 + MAX_LENGTH_SZ + 1];
+    int  nSz;
+    int  eSz;
+    int  seqSz;
+    int  bitStringSz;
+    int  idx;
+
+    if (key == NULL)
+        return BAD_FUNC_ARG;
+
+    /* n */
+    dummy = (byte*)XMALLOC(MAX_RSA_INT_SZ, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (dummy == NULL)
+        return MEMORY_E;
+
+#ifdef HAVE_USER_RSA
+    nSz = SetASNIntRSA(key->n, dummy);
+#else
+    nSz = SetASNIntMP(&key->n, MAX_RSA_INT_SZ, dummy);
+#endif
+    XFREE(dummy, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (nSz < 0) {
+        return nSz;
+    }
+
+    /* e */
+    dummy = (byte*)XMALLOC(MAX_RSA_E_SZ, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (dummy == NULL) {
+        XFREE(dummy, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+
+#ifdef HAVE_USER_RSA
+    eSz = SetASNIntRSA(key->e, dummy);
+#else
+    eSz = SetASNIntMP(&key->e, MAX_RSA_INT_SZ, dummy);
+#endif
+    XFREE(dummy, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (eSz < 0) {
+        return eSz;
+    }
+
+    seqSz  = SetSequence(nSz + eSz, seq);
+
+    /* headers */
+    if (with_header) {
+        int  algoSz;
+        dummy = (byte*)XMALLOC(MAX_RSA_INT_SZ, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        if (dummy == NULL)
+            return MEMORY_E;
+
+        algoSz = SetAlgoID(RSAk, dummy, oidKeyType, 0);
+        bitStringSz  = SetBitString(seqSz + nSz + eSz, 0, bitString);
+
+        idx = SetSequence(nSz + eSz + seqSz + bitStringSz + algoSz, dummy);
+        XFREE(dummy, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+
+        /* algo */
+        idx += algoSz;
+        /* bit string */
+        idx += bitStringSz;
+    }
+    else
+        idx = 0;
+
+    /* seq */
+    idx += seqSz;
+    /* n */
+    idx += nSz;
+    /* e */
+    idx += eSz;
 
     return idx;
@@ -6841,5 +9640,4 @@
 
 #if defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA) && !defined(HAVE_USER_RSA)
-
 
 static mp_int* GetRsaInt(RsaKey* key, int idx)
@@ -6867,5 +9665,5 @@
 
 /* Release Tmp RSA resources */
-static INLINE void FreeTmpRsas(byte** tmps, void* heap)
+static WC_INLINE void FreeTmpRsas(byte** tmps, void* heap)
 {
     int i;
@@ -6929,6 +9727,8 @@
 
     outLen = seqSz + verSz + intTotalLen;
-    if (outLen > (int)inLen)
+    if (outLen > (int)inLen) {
+        FreeTmpRsas(tmps, key->heap);
         return BAD_FUNC_ARG;
+    }
 
     /* write to output */
@@ -6946,6 +9746,7 @@
     return outLen;
 }
-
-
+#endif
+
+#if (defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA)) && !defined(NO_RSA) && !defined(HAVE_USER_RSA)
 /* Convert Rsa Public key to DER format, write to output (inLen), return bytes
    written */
@@ -6955,5 +9756,5 @@
 }
 
-#endif /* WOLFSSL_KEY_GEN && !NO_RSA && !HAVE_USER_RSA */
+#endif /* (WOLFSSL_KEY_GEN || OPENSSL_EXTRA) && !NO_RSA && !HAVE_USER_RSA */
 
 
@@ -6971,72 +9772,50 @@
 int wc_InitCert(Cert* cert)
 {
+#ifdef WOLFSSL_MULTI_ATTRIB
+    int i = 0;
+#endif
     if (cert == NULL) {
         return BAD_FUNC_ARG;
     }
 
+    XMEMSET(cert, 0, sizeof(Cert));
+
     cert->version    = 2;   /* version 3 is hex 2 */
+#ifndef NO_SHA
     cert->sigType    = CTC_SHAwRSA;
+#elif !defined(NO_SHA256)
+    cert->sigType    = CTC_SHA256wRSA;
+#else
+    cert->sigType    = 0;
+#endif
     cert->daysValid  = 500;
     cert->selfSigned = 1;
-    cert->isCA       = 0;
-    cert->bodySz     = 0;
-#ifdef WOLFSSL_ALT_NAMES
-    cert->altNamesSz   = 0;
-    cert->beforeDateSz = 0;
-    cert->afterDateSz  = 0;
-#endif
-#ifdef WOLFSSL_CERT_EXT
-    cert->skidSz = 0;
-    cert->akidSz = 0;
-    cert->keyUsage = 0;
-    cert->extKeyUsage = 0;
-    cert->certPoliciesNb = 0;
-    XMEMSET(cert->akid, 0, CTC_MAX_AKID_SIZE);
-    XMEMSET(cert->skid, 0, CTC_MAX_SKID_SIZE);
-    XMEMSET(cert->certPolicies, 0, CTC_MAX_CERTPOL_NB*CTC_MAX_CERTPOL_SZ);
-#endif
     cert->keyType    = RSA_KEY;
-    XMEMSET(cert->serial, 0, CTC_SERIAL_SIZE);
-    cert->serialSz = 0;
-
-    cert->issuer.country[0] = '\0';
+
     cert->issuer.countryEnc = CTC_PRINTABLE;
-    cert->issuer.state[0] = '\0';
     cert->issuer.stateEnc = CTC_UTF8;
-    cert->issuer.locality[0] = '\0';
     cert->issuer.localityEnc = CTC_UTF8;
-    cert->issuer.sur[0] = '\0';
     cert->issuer.surEnc = CTC_UTF8;
-    cert->issuer.org[0] = '\0';
     cert->issuer.orgEnc = CTC_UTF8;
-    cert->issuer.unit[0] = '\0';
     cert->issuer.unitEnc = CTC_UTF8;
-    cert->issuer.commonName[0] = '\0';
     cert->issuer.commonNameEnc = CTC_UTF8;
-    cert->issuer.email[0] = '\0';
-
-    cert->subject.country[0] = '\0';
+
     cert->subject.countryEnc = CTC_PRINTABLE;
-    cert->subject.state[0] = '\0';
     cert->subject.stateEnc = CTC_UTF8;
-    cert->subject.locality[0] = '\0';
     cert->subject.localityEnc = CTC_UTF8;
-    cert->subject.sur[0] = '\0';
     cert->subject.surEnc = CTC_UTF8;
-    cert->subject.org[0] = '\0';
     cert->subject.orgEnc = CTC_UTF8;
-    cert->subject.unit[0] = '\0';
     cert->subject.unitEnc = CTC_UTF8;
-    cert->subject.commonName[0] = '\0';
     cert->subject.commonNameEnc = CTC_UTF8;
-    cert->subject.email[0] = '\0';
-
-#ifdef WOLFSSL_CERT_REQ
-    cert->challengePw[0] ='\0';
-#endif
+
+#ifdef WOLFSSL_MULTI_ATTRIB
+    for (i = 0; i < CTC_MAX_ATTRIB; i++) {
+        cert->issuer.name[i].type   = CTC_UTF8;
+        cert->subject.name[i].type  = CTC_UTF8;
+    }
+#endif /* WOLFSSL_MULTI_ATTRIB */
+
 #ifdef WOLFSSL_HEAP_TEST
     cert->heap = (void*)WOLFSSL_HEAP_TEST;
-#else
-    cert->heap = NULL;
 #endif
 
@@ -7049,5 +9828,5 @@
     byte size[MAX_LENGTH_SZ];          /* length encoded */
     byte version[MAX_VERSION_SZ];      /* version encoded */
-    byte serial[CTC_SERIAL_SIZE + MAX_LENGTH_SZ]; /* serial number encoded */
+    byte serial[(int)CTC_SERIAL_SIZE + (int)MAX_LENGTH_SZ]; /* serial number encoded */
     byte sigAlgo[MAX_ALGO_SZ];         /* signature algo encoded */
     byte issuer[ASN_NAME_MAX];         /* issuer  encoded */
@@ -7110,5 +9889,6 @@
 #endif /*WOLFSSL_CERT_GEN */
 
-#if defined(HAVE_ECC) && (defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_GEN))
+
+#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT)
 
 /* Write a public ECC key to output */
@@ -7130,15 +9910,16 @@
     byte pub[ECC_BUFSIZE];
 #endif
+    int ret;
 
 #ifdef WOLFSSL_SMALL_STACK
-    pub = (byte*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    pub = (byte*)XMALLOC(ECC_BUFSIZE, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
     if (pub == NULL)
         return MEMORY_E;
 #endif
 
-    int ret = wc_ecc_export_x963(key, pub, &pubSz);
+    ret = wc_ecc_export_x963(key, pub, &pubSz);
     if (ret != 0) {
 #ifdef WOLFSSL_SMALL_STACK
-        XFREE(pub, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(pub, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
         return ret;
@@ -7148,7 +9929,7 @@
     if (with_header) {
 #ifdef WOLFSSL_SMALL_STACK
-        curve = (byte*)XMALLOC(MAX_ALGO_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        curve = (byte*)XMALLOC(MAX_ALGO_SZ, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
         if (curve == NULL) {
-            XFREE(pub, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(pub, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
             return MEMORY_E;
         }
@@ -7157,6 +9938,6 @@
         if (curveSz <= 0) {
 #ifdef WOLFSSL_SMALL_STACK
-            XFREE(curve, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-            XFREE(pub,   NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(curve, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(pub,   key->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
             return curveSz;
@@ -7164,8 +9945,8 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-        algo = (byte*)XMALLOC(MAX_ALGO_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        algo = (byte*)XMALLOC(MAX_ALGO_SZ, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
         if (algo == NULL) {
-            XFREE(curve, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-            XFREE(pub,   NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(curve, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(pub,   key->heap, DYNAMIC_TYPE_TMP_BUFFER);
             return MEMORY_E;
         }
@@ -7195,8 +9976,8 @@
 #ifdef WOLFSSL_SMALL_STACK
     if (with_header) {
-        XFREE(algo,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
-        XFREE(curve, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-    }
-    XFREE(pub,   NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(algo,  key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(curve, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    }
+    XFREE(pub,   key->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
 
@@ -7241,5 +10022,5 @@
     return SetEccPublicKey(output, key, with_AlgCurve);
 }
-#endif /* HAVE_ECC && (WOLFSSL_CERT_GEN || WOLFSSL_KEY_GEN) */
+#endif /* HAVE_ECC && HAVE_ECC_KEY_EXPORT */
 
 #if defined(HAVE_ED25519) && (defined(WOLFSSL_CERT_GEN) || \
@@ -7271,5 +10052,5 @@
     if (ret != 0) {
 #ifdef WOLFSSL_SMALL_STACK
-        XFREE(pub, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(pub, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
         return ret;
@@ -7281,5 +10062,5 @@
         algo = (byte*)XMALLOC(MAX_ALGO_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
         if (algo == NULL) {
-            XFREE(pub,   NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(pub,   key->heap, DYNAMIC_TYPE_TMP_BUFFER);
             return MEMORY_E;
         }
@@ -7351,5 +10132,5 @@
 #ifdef WOLFSSL_CERT_GEN
 
-static INLINE byte itob(int number)
+static WC_INLINE byte itob(int number)
 {
     return (byte)number + 0x30;
@@ -7406,16 +10187,4 @@
 
 
-/* for systems where mktime() doesn't normalize fully */
-static void RebuildTime(time_t* in, struct tm* out)
-{
-    #if defined(FREESCALE_MQX) || defined(FREESCALE_KSDK_MQX)
-        out = localtime_r(in, out);
-    #else
-        (void)in;
-        (void)out;
-    #endif
-}
-
-
 /* Set Date validity from now until now + daysValid
  * return size in bytes written to output, 0 on error */
@@ -7429,9 +10198,9 @@
     int seqSz;
 
-    time_t     ticks;
-    time_t     normalTime;
-    struct tm* now;
+    time_t now;
+    time_t then;
     struct tm* tmpTime = NULL;
-    struct tm  local;
+    struct tm* expandedTime;
+    struct tm localTime;
 
 #if defined(NEED_TMP_TIME)
@@ -7443,44 +10212,43 @@
 #endif
 
-    ticks = XTIME(0);
-    now   = XGMTIME(&ticks, tmpTime);
-
-    if (now == NULL) {
+    now = XTIME(0);
+
+    /* before now */
+    before[0] = ASN_GENERALIZED_TIME;
+    beforeSz  = SetLength(ASN_GEN_TIME_SZ, before + 1) + 1;  /* gen tag */
+
+    /* subtract 1 day of seconds for more compliance */
+    then = now - 86400;
+    expandedTime = XGMTIME(&then, tmpTime);
+    if (expandedTime == NULL) {
         WOLFSSL_MSG("XGMTIME failed");
         return 0;   /* error */
     }
-
-    /* before now */
-    local = *now;
-    before[0] = ASN_GENERALIZED_TIME;
-    beforeSz  = SetLength(ASN_GEN_TIME_SZ, before + 1) + 1;  /* gen tag */
-
-    /* subtract 1 day for more compliance */
-    local.tm_mday -= 1;
-    normalTime = mktime(&local);
-    RebuildTime(&normalTime, &local);
+    localTime = *expandedTime;
 
     /* adjust */
-    local.tm_year += 1900;
-    local.tm_mon  +=    1;
-
-    SetTime(&local, before + beforeSz);
+    localTime.tm_year += 1900;
+    localTime.tm_mon +=    1;
+
+    SetTime(&localTime, before + beforeSz);
     beforeSz += ASN_GEN_TIME_SZ;
 
-    /* after now + daysValid */
-    local = *now;
     after[0] = ASN_GENERALIZED_TIME;
     afterSz  = SetLength(ASN_GEN_TIME_SZ, after + 1) + 1;  /* gen tag */
 
-    /* add daysValid */
-    local.tm_mday += daysValid;
-    normalTime = mktime(&local);
-    RebuildTime(&normalTime, &local);
+    /* add daysValid of seconds */
+    then = now + (daysValid * 86400);
+    expandedTime = XGMTIME(&then, tmpTime);
+    if (expandedTime == NULL) {
+        WOLFSSL_MSG("XGMTIME failed");
+        return 0;   /* error */
+    }
+    localTime = *expandedTime;
 
     /* adjust */
-    local.tm_year += 1900;
-    local.tm_mon  +=    1;
-
-    SetTime(&local, after + afterSz);
+    localTime.tm_year += 1900;
+    localTime.tm_mon  +=    1;
+
+    SetTime(&localTime, after + afterSz);
     afterSz += ASN_GEN_TIME_SZ;
 
@@ -7530,4 +10298,14 @@
 
     case 7:
+       return name->serialDev;
+
+#ifdef WOLFSSL_CERT_EXT
+    case 8:
+       return name->busCat;
+
+    case 9:
+#else
+    case 8:
+#endif
        return name->email;
 
@@ -7563,4 +10341,18 @@
        return name->commonNameEnc;
 
+    case 7:
+       return name->serialDevEnc;
+
+#ifdef WOLFSSL_CERT_EXT
+    case 8:
+       return name->busCatEnc;
+
+    case 9:
+#else
+    case 8:
+#endif
+        /* FALL THROUGH */
+        /* The last index, email name, does not have encoding type.
+           The empty case here is to keep track of it for future reference. */
     default:
        return 0;
@@ -7595,6 +10387,15 @@
 
     case 7:
-       /* email uses different id type */
-       return 0;
+       return ASN_SERIAL_NUMBER;
+
+#ifdef WOLFSSL_CERT_EXT
+    case 8:
+        return ASN_BUS_CAT;
+
+    case 9:
+#else
+    case 8:
+#endif
+        return ASN_EMAIL_NAME;
 
     default:
@@ -7814,5 +10615,5 @@
 
 /* encode Extended Key Usage (RFC 5280 4.2.1.12), return total bytes written */
-static int SetExtKeyUsage(byte* output, word32 outSz, byte input)
+static int SetExtKeyUsage(Cert* cert, byte* output, word32 outSz, byte input)
 {
     int idx = 0, oidListSz = 0, totalSz, ret = 0;
@@ -7851,4 +10652,17 @@
             ret |= SetOjectIdValue(output, outSz, &idx,
                 extExtKeyUsageOcspSignOid, sizeof(extExtKeyUsageOcspSignOid));
+    #ifdef WOLFSSL_EKU_OID
+        /* iterate through OID values */
+        if (input & EXTKEYUSE_USER) {
+            int i, sz;
+            for (i = 0; i < CTC_MAX_EKU_NB; i++) {
+                sz = cert->extKeyUsageOIDSz[i];
+                if (sz > 0) {
+                    ret |= SetOjectIdValue(output, outSz, &idx,
+                        cert->extKeyUsageOID[i], sz);
+                }
+            }
+        }
+    #endif /* WOLFSSL_EKU_OID */
     }
     if (ret != 0)
@@ -7875,4 +10689,5 @@
     idx += oidListSz;
 
+    (void)cert;
     return idx;
 }
@@ -7894,6 +10709,5 @@
         return MEMORY_E;
 
-    XSTRNCPY(str, in, len);
-    str[len] = 0x00;
+    XSTRNCPY(str, in, len+1);
 
     nb_val = 0;
@@ -8033,4 +10847,132 @@
 #endif /* WOLFSL_ALT_NAMES */
 
+/* Encodes one attribute of the name (issuer/subject)
+ *
+ * name     structure to hold result of encoding
+ * nameStr  value to be encoded
+ * nameType type of encoding i.e CTC_UTF8
+ * type     id of attribute i.e ASN_COMMON_NAME
+ *
+ * returns length on success
+ */
+static int wc_EncodeName(EncodedName* name, const char* nameStr, char nameType,
+        byte type)
+{
+    word32 idx = 0;
+
+    if (nameStr) {
+        /* bottom up */
+        byte firstLen[1 + MAX_LENGTH_SZ];
+        byte secondLen[MAX_LENGTH_SZ];
+        byte sequence[MAX_SEQ_SZ];
+        byte set[MAX_SET_SZ];
+
+        int strLen  = (int)XSTRLEN(nameStr);
+        int thisLen = strLen;
+        int firstSz, secondSz, seqSz, setSz;
+
+        if (strLen == 0) { /* no user data for this item */
+            name->used = 0;
+            return 0;
+        }
+
+        /* Restrict country code size */
+        if (ASN_COUNTRY_NAME == type && strLen != CTC_COUNTRY_SIZE) {
+            return ASN_COUNTRY_SIZE_E;
+        }
+
+        secondSz = SetLength(strLen, secondLen);
+        thisLen += secondSz;
+        switch (type) {
+            case ASN_EMAIL_NAME: /* email */
+                thisLen += EMAIL_JOINT_LEN;
+                firstSz  = EMAIL_JOINT_LEN;
+                break;
+
+            case ASN_DOMAIN_COMPONENT:
+                thisLen += PILOT_JOINT_LEN;
+                firstSz  = PILOT_JOINT_LEN;
+                break;
+
+            default:
+                thisLen++;                                 /* str type */
+                thisLen += JOINT_LEN;
+                firstSz  = JOINT_LEN + 1;
+        }
+        thisLen++; /* id  type */
+        firstSz  = SetObjectId(firstSz, firstLen);
+        thisLen += firstSz;
+
+        seqSz = SetSequence(thisLen, sequence);
+        thisLen += seqSz;
+        setSz = SetSet(thisLen, set);
+        thisLen += setSz;
+
+        if (thisLen > (int)sizeof(name->encoded)) {
+            return BUFFER_E;
+        }
+
+        /* store it */
+        idx = 0;
+        /* set */
+        XMEMCPY(name->encoded, set, setSz);
+        idx += setSz;
+        /* seq */
+        XMEMCPY(name->encoded + idx, sequence, seqSz);
+        idx += seqSz;
+        /* asn object id */
+        XMEMCPY(name->encoded + idx, firstLen, firstSz);
+        idx += firstSz;
+        switch (type) {
+            case ASN_EMAIL_NAME:
+                {
+                    const byte EMAIL_OID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+                                       0x01, 0x09, 0x01, 0x16 };
+                    /* email joint id */
+                    XMEMCPY(name->encoded + idx, EMAIL_OID, sizeof(EMAIL_OID));
+                    idx += (int)sizeof(EMAIL_OID);
+                }
+                break;
+
+            case ASN_DOMAIN_COMPONENT:
+                {
+                    const byte PILOT_OID[] = { 0x09, 0x92, 0x26, 0x89,
+                                    0x93, 0xF2, 0x2C, 0x64, 0x01
+                    };
+
+                    XMEMCPY(name->encoded + idx, PILOT_OID,
+                                                     sizeof(PILOT_OID));
+                    idx += (int)sizeof(PILOT_OID);
+                    /* id type */
+                    name->encoded[idx++] = type;
+                    /* str type */
+                    name->encoded[idx++] = nameType;
+                }
+                break;
+
+            default:
+                name->encoded[idx++] = 0x55;
+                name->encoded[idx++] = 0x04;
+                /* id type */
+                name->encoded[idx++] = type;
+                /* str type */
+                name->encoded[idx++] = nameType;
+        }
+        /* second length */
+        XMEMCPY(name->encoded + idx, secondLen, secondSz);
+        idx += secondSz;
+        /* str value */
+        XMEMCPY(name->encoded + idx, nameStr, strLen);
+        idx += strLen;
+
+        name->type = type;
+        name->totalLen = idx;
+        name->used = 1;
+    }
+    else
+        name->used = 0;
+
+    return idx;
+}
 
 /* encode CertName into output, return total bytes written */
@@ -8043,4 +10985,8 @@
     EncodedName  names[NAME_ENTRIES];
 #endif
+#ifdef WOLFSSL_MULTI_ATTRIB
+    EncodedName addNames[CTC_MAX_ATTRIB];
+    int j, type;
+#endif
 
     if (output == NULL || name == NULL)
@@ -8058,51 +11004,24 @@
 
     for (i = 0; i < NAME_ENTRIES; i++) {
+        int ret;
         const char* nameStr = GetOneName(name, i);
-        if (nameStr) {
-            /* bottom up */
-            byte firstLen[1 + MAX_LENGTH_SZ];
-            byte secondLen[MAX_LENGTH_SZ];
-            byte sequence[MAX_SEQ_SZ];
-            byte set[MAX_SET_SZ];
-
-            int email = i == (NAME_ENTRIES - 1) ? 1 : 0;
-            int strLen  = (int)XSTRLEN(nameStr);
-            int thisLen = strLen;
-            int firstSz, secondSz, seqSz, setSz;
-
-            if (strLen == 0) { /* no user data for this item */
-                names[i].used = 0;
-                continue;
-            }
-
-            /* Restrict country code size */
-            if (i == 0 && strLen != CTC_COUNTRY_SIZE) {
+
+        ret = wc_EncodeName(&names[i], nameStr, GetNameType(name, i),
+                          GetNameId(i));
+        if (ret < 0) {
 #ifdef WOLFSSL_SMALL_STACK
                 XFREE(names, NULL, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
-                return ASN_COUNTRY_SIZE_E;
-            }
-
-            secondSz = SetLength(strLen, secondLen);
-            thisLen += secondSz;
-            if (email) {
-                thisLen += EMAIL_JOINT_LEN;
-                thisLen ++;                               /* id type */
-                firstSz  = SetObjectId(EMAIL_JOINT_LEN, firstLen);
-            }
-            else {
-                thisLen++;                                 /* str type */
-                thisLen++;                                 /* id  type */
-                thisLen += JOINT_LEN;
-                firstSz  = SetObjectId(JOINT_LEN + 1, firstLen);
-            }
-            thisLen += firstSz;
-
-            seqSz = SetSequence(thisLen, sequence);
-            thisLen += seqSz;
-            setSz = SetSet(thisLen, set);
-            thisLen += setSz;
-
-            if (thisLen > (int)sizeof(names[i].encoded)) {
+                return BUFFER_E;
+            }
+        totalBytes += ret;
+            }
+#ifdef WOLFSSL_MULTI_ATTRIB
+    for (i = 0; i < CTC_MAX_ATTRIB; i++) {
+        if (name->name[i].sz > 0) {
+            int ret;
+            ret = wc_EncodeName(&addNames[i], name->name[i].value,
+                        name->name[i].type, name->name[i].id);
+            if (ret < 0) {
 #ifdef WOLFSSL_SMALL_STACK
                 XFREE(names, NULL, DYNAMIC_TYPE_TMP_BUFFER);
@@ -8110,47 +11029,11 @@
                 return BUFFER_E;
             }
-
-            /* store it */
-            idx = 0;
-            /* set */
-            XMEMCPY(names[i].encoded, set, setSz);
-            idx += setSz;
-            /* seq */
-            XMEMCPY(names[i].encoded + idx, sequence, seqSz);
-            idx += seqSz;
-            /* asn object id */
-            XMEMCPY(names[i].encoded + idx, firstLen, firstSz);
-            idx += firstSz;
-            if (email) {
-                const byte EMAIL_OID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
-                                           0x01, 0x09, 0x01, 0x16 };
-                /* email joint id */
-                XMEMCPY(names[i].encoded + idx, EMAIL_OID, sizeof(EMAIL_OID));
-                idx += (int)sizeof(EMAIL_OID);
+            totalBytes += ret;
             }
             else {
-                /* joint id */
-                byte bType = GetNameId(i);
-                names[i].encoded[idx++] = 0x55;
-                names[i].encoded[idx++] = 0x04;
-                /* id type */
-                names[i].encoded[idx++] = bType;
-                /* str type */
-                names[i].encoded[idx++] = GetNameType(name, i);
-            }
-            /* second length */
-            XMEMCPY(names[i].encoded + idx, secondLen, secondSz);
-            idx += secondSz;
-            /* str value */
-            XMEMCPY(names[i].encoded + idx, nameStr, strLen);
-            idx += strLen;
-
-            totalBytes += idx;
-            names[i].totalLen = idx;
-            names[i].used = 1;
-        }
-        else
-            names[i].used = 0;
-    }
+            addNames[i].used = 0;
+        }
+    }
+#endif /* WOLFSSL_MULTI_ATTRIB */
 
     /* header */
@@ -8165,4 +11048,44 @@
 
     for (i = 0; i < NAME_ENTRIES; i++) {
+    #ifdef WOLFSSL_MULTI_ATTRIB
+        type = GetNameId(i);
+
+        /* list all DC values before OUs */
+        if (type == ASN_ORGUNIT_NAME) {
+            type = ASN_DOMAIN_COMPONENT;
+            for (j = 0; j < CTC_MAX_ATTRIB; j++) {
+                if (name->name[j].sz > 0 && type == name->name[j].id) {
+                    if (outputSz < (word32)(idx+addNames[j].totalLen)) {
+                    #ifdef WOLFSSL_SMALL_STACK
+                        XFREE(names, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                    #endif
+                        return BUFFER_E;
+                    }
+
+                    XMEMCPY(output + idx, addNames[j].encoded,
+                            addNames[j].totalLen);
+                    idx += addNames[j].totalLen;
+                }
+            }
+            type = ASN_ORGUNIT_NAME;
+        }
+
+        /* write all similar types to the buffer */
+        for (j = 0; j < CTC_MAX_ATTRIB; j++) {
+            if (name->name[j].sz > 0 && type == name->name[j].id) {
+                if (outputSz < (word32)(idx+addNames[j].totalLen)) {
+                #ifdef WOLFSSL_SMALL_STACK
+                    XFREE(names, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                #endif
+                    return BUFFER_E;
+                }
+
+                XMEMCPY(output + idx, addNames[j].encoded,
+                        addNames[j].totalLen);
+                idx += addNames[j].totalLen;
+            }
+        }
+    #endif /* WOLFSSL_MULTI_ATTRIB */
+
         if (names[i].used) {
             if (outputSz < (word32)(idx+names[i].totalLen)) {
@@ -8296,11 +11219,56 @@
 
     /* subject name */
-    der->subjectSz = SetName(der->subject, sizeof(der->subject), &cert->subject);
+#ifdef WOLFSSL_CERT_EXT
+    if (XSTRLEN((const char*)cert->sbjRaw) > 0) {
+        /* Use the raw subject */
+        int idx;
+
+        der->subjectSz = min(sizeof(der->subject),
+                (word32)XSTRLEN((const char*)cert->sbjRaw));
+        /* header */
+        idx = SetSequence(der->subjectSz, der->subject);
+        if (der->subjectSz + idx > (int)sizeof(der->subject)) {
+            return SUBJECT_E;
+        }
+
+        XMEMCPY((char*)der->subject + idx, (const char*)cert->sbjRaw,
+                der->subjectSz);
+        der->subjectSz += idx;
+    }
+    else
+#endif
+    {
+        /* Use the name structure */
+        der->subjectSz = SetName(der->subject, sizeof(der->subject),
+                &cert->subject);
+    }
     if (der->subjectSz <= 0)
         return SUBJECT_E;
 
     /* issuer name */
-    der->issuerSz = SetName(der->issuer, sizeof(der->issuer), cert->selfSigned ?
-             &cert->subject : &cert->issuer);
+#ifdef WOLFSSL_CERT_EXT
+    if (XSTRLEN((const char*)cert->issRaw) > 0) {
+        /* Use the raw issuer */
+        int idx;
+
+        der->issuerSz = min(sizeof(der->issuer),
+                (word32)XSTRLEN((const char*)cert->issRaw));
+        /* header */
+        idx = SetSequence(der->issuerSz, der->issuer);
+        if (der->issuerSz + idx > (int)sizeof(der->issuer)) {
+            return ISSUER_E;
+        }
+
+        XMEMCPY((char*)der->issuer + idx, (const char*)cert->issRaw,
+                der->issuerSz);
+        der->issuerSz += idx;
+    }
+    else
+#endif
+    {
+        /* Use the name structure */
+        der->issuerSz = SetName(der->issuer, sizeof(der->issuer),
+                cert->selfSigned ? &cert->subject : &cert->issuer);
+    }
     if (der->issuerSz <= 0)
         return ISSUER_E;
@@ -8338,5 +11306,5 @@
     if (cert->skidSz) {
         /* check the provided SKID size */
-        if (cert->skidSz > (int)sizeof(der->skid))
+        if (cert->skidSz > (int)min(CTC_MAX_SKID_SIZE, sizeof(der->skid)))
             return SKID_E;
 
@@ -8356,5 +11324,5 @@
     if (cert->akidSz) {
         /* check the provided AKID size */
-        if (cert->akidSz > (int)sizeof(der->akid))
+        if (cert->akidSz > (int)min(CTC_MAX_AKID_SIZE, sizeof(der->akid)))
             return AKID_E;
 
@@ -8383,5 +11351,5 @@
     /* Extended Key Usage */
     if (cert->extKeyUsage != 0){
-        der->extKeyUsageSz = SetExtKeyUsage(der->extKeyUsage,
+        der->extKeyUsageSz = SetExtKeyUsage(cert, der->extKeyUsage,
                                 sizeof(der->extKeyUsage), cert->extKeyUsage);
         if (der->extKeyUsageSz <= 0)
@@ -8687,5 +11655,5 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    der = (DerCert*)XMALLOC(sizeof(DerCert), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    der = (DerCert*)XMALLOC(sizeof(DerCert), cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
     if (der == NULL)
         return MEMORY_E;
@@ -8702,5 +11670,5 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(der, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
 
@@ -8741,5 +11709,5 @@
                   const byte* ntruKey, word16 keySz, WC_RNG* rng)
 {
-    return MakeAnyCert(cert, derBuffer, derSz, NULL, NULL, rng, ntruKey, keySz);
+    return MakeAnyCert(cert, derBuffer, derSz, NULL, NULL, rng, ntruKey, keySz, NULL);
 }
 
@@ -8889,5 +11857,5 @@
     if (cert->skidSz) {
         /* check the provided SKID size */
-        if (cert->skidSz > (int)sizeof(der->skid))
+        if (cert->skidSz > (int)min(CTC_MAX_SKID_SIZE, sizeof(der->skid)))
             return SKID_E;
 
@@ -8916,5 +11884,5 @@
     /* Extended Key Usage */
     if (cert->extKeyUsage != 0){
-        der->extKeyUsageSz = SetExtKeyUsage(der->extKeyUsage,
+        der->extKeyUsageSz = SetExtKeyUsage(cert, der->extKeyUsage,
                                 sizeof(der->extKeyUsage), cert->extKeyUsage);
         if (der->extKeyUsageSz <= 0)
@@ -9041,5 +12009,6 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    der = (DerCert*)XMALLOC(sizeof(DerCert), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    der = (DerCert*)XMALLOC(sizeof(DerCert), cert->heap,
+                                                    DYNAMIC_TYPE_TMP_BUFFER);
     if (der == NULL)
         return MEMORY_E;
@@ -9056,5 +12025,5 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(der, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
 
@@ -9140,6 +12109,9 @@
     sigSz = MakeSignature(certSignCtx, buffer, requestSz, certSignCtx->sig,
         MAX_ENCODED_SIG_SZ, rsaKey, eccKey, ed25519Key, rng, sType, heap);
-    if (sigSz == WC_PENDING_E)
+    if (sigSz == WC_PENDING_E) {
+        /* Not free'ing certSignCtx->sig here because it could still be in use
+         * with async operations. */
         return sigSz;
+    }
 
     if (sigSz >= 0) {
@@ -9147,5 +12119,6 @@
             sigSz = BUFFER_E;
         else
-            sigSz = AddSignature(buffer, requestSz, certSignCtx->sig, sigSz, sType);
+            sigSz = AddSignature(buffer, requestSz, certSignCtx->sig, sigSz,
+                                 sType);
     }
 
@@ -9196,4 +12169,16 @@
 
 #ifdef WOLFSSL_CERT_EXT
+
+/* Get raw subject from cert, which may contain OIDs not parsed by Decode.
+   The raw subject pointer will only be valid while "cert" is valid. */
+int wc_GetSubjectRaw(byte **subjectRaw, Cert *cert)
+{
+    int rc = BAD_FUNC_ARG;
+    if ((subjectRaw != NULL) && (cert != NULL)) {
+        *subjectRaw = cert->sbjRaw;
+        rc = 0;
+    }
+    return rc;
+}
 
 /* Set KID from public key */
@@ -9252,27 +12237,14 @@
 
     /* Compute SKID by hashing public key */
-#ifdef NO_SHA
     if (kid_type == SKID_TYPE) {
-        ret = wc_Sha256Hash(buffer, bufferSz, cert->skid);
-        cert->skidSz = WC_SHA256_DIGEST_SIZE;
+        ret = CalcHashId(buffer, bufferSz, cert->skid);
+        cert->skidSz = KEYID_SIZE;
     }
     else if (kid_type == AKID_TYPE) {
-        ret = wc_Sha256Hash(buffer, bufferSz, cert->akid);
-        cert->akidSz = WC_SHA256_DIGEST_SIZE;
+        ret = CalcHashId(buffer, bufferSz, cert->akid);
+        cert->akidSz = KEYID_SIZE;
     }
     else
         ret = BAD_FUNC_ARG;
-#else /* NO_SHA */
-    if (kid_type == SKID_TYPE) {
-        ret = wc_ShaHash(buffer, bufferSz, cert->skid);
-        cert->skidSz = WC_SHA_DIGEST_SIZE;
-    }
-    else if (kid_type == AKID_TYPE) {
-        ret = wc_ShaHash(buffer, bufferSz, cert->akid);
-        cert->akidSz = WC_SHA_DIGEST_SIZE;
-    }
-    else
-        ret = BAD_FUNC_ARG;
-#endif /* NO_SHA */
 
     XFREE(buffer, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
@@ -9337,5 +12309,5 @@
 
 
-#ifndef NO_FILESYSTEM
+#if !defined(NO_FILESYSTEM) && !defined(NO_ASN_CRYPT)
 
 /* Set SKID from public key file in PEM */
@@ -9357,5 +12329,5 @@
     }
 
-    derSz = wolfSSL_PemPubKeyToDer(file, der, MAX_PUBLIC_KEY_SZ);
+    derSz = wc_PemPubKeyToDer(file, der, MAX_PUBLIC_KEY_SZ);
     if (derSz <= 0)
     {
@@ -9413,4 +12385,5 @@
             XFREE(der, cert->heap, DYNAMIC_TYPE_CERT);
             wc_ecc_free(eckey);
+            XFREE(eckey, cert->heap, DYNAMIC_TYPE_ECC);
             return PUBLIC_KEY_E;
         }
@@ -9436,5 +12409,5 @@
 }
 
-#endif /* NO_FILESYSTEM */
+#endif /* !NO_FILESYSTEM && !NO_ASN_CRYPT */
 
 /* Set AKID from certificate contains in buffer (DER encoded) */
@@ -9454,5 +12427,5 @@
 #ifdef WOLFSSL_SMALL_STACK
     decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert),
-                                    NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                                    cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
     if (decoded == NULL)
         return MEMORY_E;
@@ -9460,10 +12433,10 @@
 
     /* decode certificate and get SKID that will be AKID of current cert */
-    InitDecodedCert(decoded, (byte*)der, derSz, NULL);
+    InitDecodedCert(decoded, der, derSz, NULL);
     ret = ParseCert(decoded, CERT_TYPE, NO_VERIFY, 0);
     if (ret != 0) {
         FreeDecodedCert(decoded);
         #ifdef WOLFSSL_SMALL_STACK
-            XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(decoded, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
         #endif
         return ret;
@@ -9474,5 +12447,5 @@
         FreeDecodedCert(decoded);
         #ifdef WOLFSSL_SMALL_STACK
-            XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(decoded, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
         #endif
         return ASN_NO_SKID;
@@ -9483,5 +12456,5 @@
         FreeDecodedCert(decoded);
         #ifdef WOLFSSL_SMALL_STACK
-            XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(decoded, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
         #endif
         return MEMORY_E;
@@ -9494,5 +12467,5 @@
     FreeDecodedCert(decoded);
     #ifdef WOLFSSL_SMALL_STACK
-        XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(decoded, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
     #endif
 
@@ -9519,5 +12492,5 @@
     }
 
-    derSz = wolfSSL_PemCertToDer(file, der, EIGHTK_BUF);
+    derSz = wc_PemCertToDer(file, der, EIGHTK_BUF);
     if (derSz <= 0)
     {
@@ -9532,5 +12505,5 @@
 }
 
-#endif /* NO_FILESYSTEM */
+#endif /* !NO_FILESYSTEM */
 
 /* Set KeyUsage from human readable string */
@@ -9546,10 +12519,10 @@
     cert->keyUsage = 0;
 
-    str = (char*)XMALLOC(XSTRLEN(value)+1, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    len = (word32)XSTRLEN(value);
+    str = (char*)XMALLOC(len+1, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
     if (str == NULL)
         return MEMORY_E;
 
-    XMEMSET(str, 0, XSTRLEN(value)+1);
-    XSTRNCPY(str, value, XSTRLEN(value));
+    XSTRNCPY(str, value, len+1);
 
     /* parse value, and set corresponding Key Usage value */
@@ -9605,10 +12578,10 @@
     cert->extKeyUsage = 0;
 
-    str = (char*)XMALLOC(XSTRLEN(value)+1, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    len = (word32)XSTRLEN(value);
+    str = (char*)XMALLOC(len+1, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
     if (str == NULL)
         return MEMORY_E;
 
-    XMEMSET(str, 0, XSTRLEN(value)+1);
-    XSTRNCPY(str, value, XSTRLEN(value));
+    XSTRNCPY(str, value, len+1);
 
     /* parse value, and set corresponding Key Usage value */
@@ -9647,4 +12620,36 @@
     return ret;
 }
+
+#ifdef WOLFSSL_EKU_OID
+/*
+ * cert structure to set EKU oid in
+ * oid  the oid in byte representation
+ * sz   size of oid buffer
+ * idx  index of array to place oid
+ *
+ * returns 0 on success
+ */
+int wc_SetExtKeyUsageOID(Cert *cert, const char *in, word32 sz, byte idx,
+        void* heap)
+{
+    byte oid[MAX_OID_SZ];
+    word32 oidSz = MAX_OID_SZ;
+
+    if (idx >= CTC_MAX_EKU_NB || sz >= CTC_MAX_EKU_OID_SZ) {
+        WOLFSSL_MSG("Either idx or sz was too large");
+        return BAD_FUNC_ARG;
+    }
+
+    if (EncodePolicyOID(oid, &oidSz, in, heap) != 0) {
+        return BUFFER_E;
+    }
+
+    XMEMCPY(cert->extKeyUsageOID[idx], oid, oidSz);
+    cert->extKeyUsageOIDSz[idx] = oidSz;
+    cert->extKeyUsage |= EXTKEYUSE_USER;
+
+    return 0;
+}
+#endif /* WOLFSSL_EKU_OID */
 #endif /* WOLFSSL_CERT_EXT */
 
@@ -9666,5 +12671,5 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
+    decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), cert->heap,
                                                        DYNAMIC_TYPE_TMP_BUFFER);
     if (decoded == NULL)
@@ -9672,5 +12677,5 @@
 #endif
 
-    InitDecodedCert(decoded, (byte*)der, derSz, NULL);
+    InitDecodedCert(decoded, der, derSz, NULL);
     ret = ParseCertRelative(decoded, CA_TYPE, NO_VERIFY, 0);
 
@@ -9740,5 +12745,5 @@
     FreeDecodedCert(decoded);
 #ifdef WOLFSSL_SMALL_STACK
-    XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(decoded, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
 
@@ -9762,5 +12767,5 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
+    decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), cert->heap,
                                                        DYNAMIC_TYPE_TMP_BUFFER);
     if (decoded == NULL)
@@ -9768,5 +12773,5 @@
 #endif
 
-    InitDecodedCert(decoded, (byte*)der, derSz, NULL);
+    InitDecodedCert(decoded, der, derSz, NULL);
     ret = ParseCertRelative(decoded, CA_TYPE, NO_VERIFY, 0);
 
@@ -9794,5 +12799,5 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(decoded, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
 
@@ -9822,5 +12827,5 @@
 #endif
 
-    InitDecodedCert(decoded, (byte*)der, derSz, NULL);
+    InitDecodedCert(decoded, der, derSz, NULL);
     ret = ParseCertRelative(decoded, CA_TYPE, NO_VERIFY, 0);
 
@@ -9833,5 +12838,5 @@
                                                          : CTC_NAME_SIZE - 1;
             XSTRNCPY(cn->commonName, decoded->subjectCN, CTC_NAME_SIZE);
-            cn->commonName[sz] = 0;
+            cn->commonName[sz] = '\0';
             cn->commonNameEnc = decoded->subjectCNEnc;
         }
@@ -9840,5 +12845,5 @@
                                                         : CTC_NAME_SIZE - 1;
             XSTRNCPY(cn->country, decoded->subjectC, CTC_NAME_SIZE);
-            cn->country[sz] = 0;
+            cn->country[sz] = '\0';
             cn->countryEnc = decoded->subjectCEnc;
         }
@@ -9847,5 +12852,5 @@
                                                          : CTC_NAME_SIZE - 1;
             XSTRNCPY(cn->state, decoded->subjectST, CTC_NAME_SIZE);
-            cn->state[sz] = 0;
+            cn->state[sz] = '\0';
             cn->stateEnc = decoded->subjectSTEnc;
         }
@@ -9854,5 +12859,5 @@
                                                         : CTC_NAME_SIZE - 1;
             XSTRNCPY(cn->locality, decoded->subjectL, CTC_NAME_SIZE);
-            cn->locality[sz] = 0;
+            cn->locality[sz] = '\0';
             cn->localityEnc = decoded->subjectLEnc;
         }
@@ -9861,5 +12866,5 @@
                                                         : CTC_NAME_SIZE - 1;
             XSTRNCPY(cn->org, decoded->subjectO, CTC_NAME_SIZE);
-            cn->org[sz] = 0;
+            cn->org[sz] = '\0';
             cn->orgEnc = decoded->subjectOEnc;
         }
@@ -9868,5 +12873,5 @@
                                                          : CTC_NAME_SIZE - 1;
             XSTRNCPY(cn->unit, decoded->subjectOU, CTC_NAME_SIZE);
-            cn->unit[sz] = 0;
+            cn->unit[sz] = '\0';
             cn->unitEnc = decoded->subjectOUEnc;
         }
@@ -9875,12 +12880,42 @@
                                                          : CTC_NAME_SIZE - 1;
             XSTRNCPY(cn->sur, decoded->subjectSN, CTC_NAME_SIZE);
-            cn->sur[sz] = 0;
+            cn->sur[sz] = '\0';
             cn->surEnc = decoded->subjectSNEnc;
         }
+        if (decoded->subjectSND) {
+            sz = (decoded->subjectSNDLen < CTC_NAME_SIZE) ? decoded->subjectSNDLen
+                                                         : CTC_NAME_SIZE - 1;
+            XSTRNCPY(cn->serialDev, decoded->subjectSND, CTC_NAME_SIZE);
+            cn->serialDev[sz] = '\0';
+            cn->serialDevEnc = decoded->subjectSNDEnc;
+        }
+    #ifdef WOLFSSL_CERT_EXT
+        if (decoded->subjectBC) {
+            sz = (decoded->subjectBCLen < CTC_NAME_SIZE) ? decoded->subjectBCLen
+                                                         : CTC_NAME_SIZE - 1;
+            XSTRNCPY(cn->busCat, decoded->subjectBC, CTC_NAME_SIZE);
+            cn->busCat[sz] = '\0';
+            cn->busCatEnc = decoded->subjectBCEnc;
+        }
+        if (decoded->subjectJC) {
+            sz = (decoded->subjectJCLen < CTC_NAME_SIZE) ? decoded->subjectJCLen
+                                                         : CTC_NAME_SIZE - 1;
+            XSTRNCPY(cn->joiC, decoded->subjectJC, CTC_NAME_SIZE);
+            cn->joiC[sz] = '\0';
+            cn->joiCEnc = decoded->subjectJCEnc;
+        }
+        if (decoded->subjectJS) {
+            sz = (decoded->subjectJSLen < CTC_NAME_SIZE) ? decoded->subjectJSLen
+                                                         : CTC_NAME_SIZE - 1;
+            XSTRNCPY(cn->joiSt, decoded->subjectJS, CTC_NAME_SIZE);
+            cn->joiSt[sz] = '\0';
+            cn->joiStEnc = decoded->subjectJSEnc;
+        }
+    #endif
         if (decoded->subjectEmail) {
             sz = (decoded->subjectEmailLen < CTC_NAME_SIZE)
                ?  decoded->subjectEmailLen : CTC_NAME_SIZE - 1;
             XSTRNCPY(cn->email, decoded->subjectEmail, CTC_NAME_SIZE);
-            cn->email[sz] = 0;
+            cn->email[sz] = '\0';
         }
     }
@@ -9895,4 +12930,109 @@
 }
 
+#ifdef WOLFSSL_CERT_EXT
+/* Set raw subject from der buffer, return 0 on success */
+static int SetSubjectRawFromCert(byte* sbjRaw, const byte* der, int derSz)
+{
+    int ret;
+#ifdef WOLFSSL_SMALL_STACK
+    DecodedCert* decoded;
+#else
+    DecodedCert decoded[1];
+#endif
+
+    if ((derSz < 0) || (sbjRaw == NULL)) {
+        return BAD_FUNC_ARG;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+    if (decoded == NULL) {
+        return MEMORY_E;
+    }
+#endif
+
+    InitDecodedCert(decoded, der, derSz, NULL);
+    ret = ParseCertRelative(decoded, CA_TYPE, NO_VERIFY, 0);
+
+    if (ret < 0) {
+        WOLFSSL_MSG("ParseCertRelative error");
+    }
+#ifndef IGNORE_NAME_CONSTRAINT
+    else {
+        if ((decoded->subjectRaw) &&
+            (decoded->subjectRawLen <= (int)sizeof(CertName))) {
+            XMEMCPY(sbjRaw, decoded->subjectRaw, decoded->subjectRawLen);
+        }
+        }
+#else
+    else {
+        /* Fields are not accessible */
+        ret = -1;
+        WOLFSSL_MSG("IGNORE_NAME_CONSTRAINT excludes raw subject");
+    }
+#endif
+
+    FreeDecodedCert(decoded);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret < 0 ? ret : 0;
+}
+
+/* Set raw issuer from der buffer, return 0 on success */
+static int SetIssuerRawFromCert(byte* issuerRaw, const byte* der, int derSz)
+{
+    int ret;
+#ifdef WOLFSSL_SMALL_STACK
+    DecodedCert* decoded;
+#else
+    DecodedCert decoded[1];
+#endif
+
+    if ((derSz < 0) || (issuerRaw == NULL)) {
+        return BAD_FUNC_ARG;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+    if (decoded == NULL) {
+        return MEMORY_E;
+    }
+#endif
+
+    InitDecodedCert(decoded, der, derSz, NULL);
+    ret = ParseCertRelative(decoded, CA_TYPE, NO_VERIFY, 0);
+
+    if (ret < 0) {
+        WOLFSSL_MSG("ParseCertRelative error");
+    }
+#ifndef IGNORE_NAME_CONSTRAINT
+    else {
+        if ((decoded->issuerRaw) &&
+            (decoded->issuerRawLen <= (int)sizeof(CertName))) {
+            XMEMCPY(issuerRaw, decoded->issuerRaw, decoded->issuerRawLen);
+        }
+    }
+#else
+    else {
+        /* Fields are not accessible */
+        ret = -1;
+        WOLFSSL_MSG("IGNORE_NAME_CONSTRAINT excludes raw issuer");
+    }
+#endif
+
+    FreeDecodedCert(decoded);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret < 0 ? ret : 0;
+}
+#endif /* WOLFSSL_CERT_EXT */
 
 #ifndef NO_FILESYSTEM
@@ -9903,11 +13043,16 @@
     int         ret;
     int         derSz;
-    byte*       der = (byte*)XMALLOC(EIGHTK_BUF, cert->heap, DYNAMIC_TYPE_CERT);
-
+    byte*       der;
+
+    if (cert == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    der = (byte*)XMALLOC(EIGHTK_BUF, cert->heap, DYNAMIC_TYPE_CERT);
     if (der == NULL) {
         WOLFSSL_MSG("wc_SetIssuer OOF Problem");
         return MEMORY_E;
     }
-    derSz = wolfSSL_PemCertToDer(issuerFile, der, EIGHTK_BUF);
+    derSz = wc_PemCertToDer(issuerFile, der, EIGHTK_BUF);
     cert->selfSigned = 0;
     ret = SetNameFromCert(&cert->issuer, der, derSz);
@@ -9923,11 +13068,17 @@
     int         ret;
     int         derSz;
-    byte*       der = (byte*)XMALLOC(EIGHTK_BUF, cert->heap, DYNAMIC_TYPE_CERT);
-
+    byte*       der;
+
+    if (cert == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    der = (byte*)XMALLOC(EIGHTK_BUF, cert->heap, DYNAMIC_TYPE_CERT);
     if (der == NULL) {
         WOLFSSL_MSG("wc_SetSubject OOF Problem");
         return MEMORY_E;
     }
-    derSz = wolfSSL_PemCertToDer(subjectFile, der, EIGHTK_BUF);
+
+    derSz = wc_PemCertToDer(subjectFile, der, EIGHTK_BUF);
     ret = SetNameFromCert(&cert->subject, der, derSz);
     XFREE(der, cert->heap, DYNAMIC_TYPE_CERT);
@@ -9936,19 +13087,23 @@
 }
 
-
 #ifdef WOLFSSL_ALT_NAMES
 
-/* Set atl names from file in PEM */
+/* Set alt names from file in PEM */
 int wc_SetAltNames(Cert* cert, const char* file)
 {
     int         ret;
     int         derSz;
-    byte*       der = (byte*)XMALLOC(EIGHTK_BUF, cert->heap, DYNAMIC_TYPE_CERT);
-
+    byte*       der;
+
+    if (cert == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    der = (byte*)XMALLOC(EIGHTK_BUF, cert->heap, DYNAMIC_TYPE_CERT);
     if (der == NULL) {
         WOLFSSL_MSG("wc_SetAltNames OOF Problem");
         return MEMORY_E;
     }
-    derSz = wolfSSL_PemCertToDer(file, der, EIGHTK_BUF);
+    derSz = wc_PemCertToDer(file, der, EIGHTK_BUF);
     ret = SetAltNamesFromCert(cert, der, derSz);
     XFREE(der, cert->heap, DYNAMIC_TYPE_CERT);
@@ -9959,20 +13114,55 @@
 #endif /* WOLFSSL_ALT_NAMES */
 
-#endif /* NO_FILESYSTEM */
+#endif /* !NO_FILESYSTEM */
 
 /* Set cert issuer from DER buffer */
 int wc_SetIssuerBuffer(Cert* cert, const byte* der, int derSz)
 {
+    if (cert == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
     cert->selfSigned = 0;
     return SetNameFromCert(&cert->issuer, der, derSz);
 }
 
-
 /* Set cert subject from DER buffer */
 int wc_SetSubjectBuffer(Cert* cert, const byte* der, int derSz)
 {
+    if (cert == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
     return SetNameFromCert(&cert->subject, der, derSz);
 }
-
+#ifdef WOLFSSL_CERT_EXT
+/* Set cert raw subject from DER buffer */
+int wc_SetSubjectRaw(Cert* cert, const byte* der, int derSz)
+{
+    int ret;
+
+    if (cert == NULL) {
+        ret = BAD_FUNC_ARG;
+    }
+    else {
+        ret = SetSubjectRawFromCert(cert->sbjRaw, der, derSz);
+    }
+    return ret;
+}
+
+/* Set cert raw issuer from DER buffer */
+int wc_SetIssuerRaw(Cert* cert, const byte* der, int derSz)
+{
+    int ret;
+
+    if (cert == NULL) {
+        ret = BAD_FUNC_ARG;
+    }
+    else {
+        ret = SetIssuerRawFromCert(cert->issRaw, der, derSz);
+    }
+    return ret;
+}
+#endif
 
 #ifdef WOLFSSL_ALT_NAMES
@@ -10088,4 +13278,7 @@
         return ASN_PARSE_E;
 
+    if (*inOutIdx >= inSz)
+        return ASN_PARSE_E;
+
     b = input[*inOutIdx];
     *inOutIdx += 1;
@@ -10102,11 +13295,11 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    priv = (byte*)XMALLOC(ECC_MAXSIZE+1, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    priv = (byte*)XMALLOC(ECC_MAXSIZE+1, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
     if (priv == NULL)
         return MEMORY_E;
 
-    pub = (byte*)XMALLOC(2*(ECC_MAXSIZE+1), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    pub = (byte*)XMALLOC(2*(ECC_MAXSIZE+1), key->heap, DYNAMIC_TYPE_TMP_BUFFER);
     if (pub == NULL) {
-        XFREE(priv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(priv, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
         return MEMORY_E;
     }
@@ -10175,6 +13368,6 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    XFREE(priv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-    XFREE(pub,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(priv, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(pub,  key->heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
 
@@ -10182,4 +13375,47 @@
 }
 
+
+#ifdef WOLFSSL_CUSTOM_CURVES
+static void ByteToHex(byte n, char* str)
+{
+    static const char hexChar[] = { '0', '1', '2', '3', '4', '5', '6', '7',
+                                    '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+    str[0] = hexChar[n >> 4];
+    str[1] = hexChar[n & 0xf];
+}
+
+/* returns 0 on success */
+static int ASNToHexString(const byte* input, word32* inOutIdx, char** out,
+                          word32 inSz, void* heap, int heapType)
+{
+    int len;
+    int i;
+    char* str;
+
+    if (*inOutIdx >= inSz) {
+        return BUFFER_E;
+    }
+
+    if (input[*inOutIdx] == ASN_INTEGER) {
+        if (GetASNInt(input, inOutIdx, &len, inSz) < 0)
+            return ASN_PARSE_E;
+    }
+    else {
+        if (GetOctetString(input, inOutIdx, &len, inSz) < 0)
+            return ASN_PARSE_E;
+    }
+
+    str = (char*)XMALLOC(len * 2 + 1, heap, heapType);
+    for (i=0; i<len; i++)
+        ByteToHex(input[*inOutIdx + i], str + i*2);
+    str[len*2] = '\0';
+
+    *inOutIdx += len;
+    *out = str;
+
+    return 0;
+}
+#endif /* WOLFSSL_CUSTOM_CURVES */
 
 int wc_EccPublicKeyDecode(const byte* input, word32* inOutIdx,
@@ -10188,7 +13424,6 @@
     int    length;
     int    ret;
-#ifdef ECC_CHECK_PUBLIC_KEY_OID
+    int    curve_id = ECC_CURVE_DEF;
     word32 oidSum;
-#endif
 
     if (input == NULL || inOutIdx == NULL || key == NULL || inSz == 0)
@@ -10205,32 +13440,144 @@
         return ret;
 
+    if (*inOutIdx >= inSz) {
+        return BUFFER_E;
+    }
+
+    if (input[*inOutIdx] == (ASN_SEQUENCE | ASN_CONSTRUCTED)) {
+#ifdef WOLFSSL_CUSTOM_CURVES
+        ecc_set_type* curve;
+        int len;
+        char* point;
+
+        ret = 0;
+
+        curve = (ecc_set_type*)XMALLOC(sizeof(*curve), key->heap,
+                                                       DYNAMIC_TYPE_ECC_BUFFER);
+        if (curve == NULL)
+            ret = MEMORY_E;
+
+        if (ret == 0) {
+            XMEMSET(curve, 0, sizeof(*curve));
+            curve->name = "Custom";
+            curve->id = ECC_CURVE_CUSTOM;
+
+            if (GetSequence(input, inOutIdx, &length, inSz) < 0)
+                ret = ASN_PARSE_E;
+        }
+
+        if (ret == 0) {
+            GetInteger7Bit(input, inOutIdx, inSz);
+            if (GetSequence(input, inOutIdx, &length, inSz) < 0)
+                ret = ASN_PARSE_E;
+        }
+        if (ret == 0) {
+            SkipObjectId(input, inOutIdx, inSz);
+            ret = ASNToHexString(input, inOutIdx, (char**)&curve->prime, inSz,
+                                            key->heap, DYNAMIC_TYPE_ECC_BUFFER);
+        }
+        if (ret == 0) {
+            curve->size = (int)XSTRLEN(curve->prime) / 2;
+
+            if (GetSequence(input, inOutIdx, &length, inSz) < 0)
+                ret = ASN_PARSE_E;
+        }
+        if (ret == 0) {
+            ret = ASNToHexString(input, inOutIdx, (char**)&curve->Af, inSz,
+                                            key->heap, DYNAMIC_TYPE_ECC_BUFFER);
+        }
+        if (ret == 0) {
+            ret = ASNToHexString(input, inOutIdx, (char**)&curve->Bf, inSz,
+                                            key->heap, DYNAMIC_TYPE_ECC_BUFFER);
+        }
+        if (ret == 0) {
+            if (*inOutIdx < inSz && input[*inOutIdx] == ASN_BIT_STRING) {
+                len = 0;
+                ret = GetASNHeader(input, ASN_BIT_STRING, inOutIdx, &len, inSz);
+                *inOutIdx += len;
+            }
+        }
+        if (ret == 0) {
+            ret = ASNToHexString(input, inOutIdx, (char**)&point, inSz,
+                                            key->heap, DYNAMIC_TYPE_ECC_BUFFER);
+
+            /* sanity check that point buffer is not smaller than the expected
+             * size to hold ( 0 4 || Gx || Gy )
+             * where Gx and Gy are each the size of curve->size * 2 */
+            if (ret == 0 && (int)XSTRLEN(point) < (curve->size * 4) + 2) {
+                XFREE(point, key->heap, DYNAMIC_TYPE_ECC_BUFFER);
+                ret = BUFFER_E;
+            }
+        }
+        if (ret == 0) {
+            curve->Gx = (const char*)XMALLOC(curve->size * 2 + 2, key->heap,
+                                                       DYNAMIC_TYPE_ECC_BUFFER);
+            curve->Gy = (const char*)XMALLOC(curve->size * 2 + 2, key->heap,
+                                                       DYNAMIC_TYPE_ECC_BUFFER);
+            if (curve->Gx == NULL || curve->Gy == NULL) {
+                XFREE(point, key->heap, DYNAMIC_TYPE_ECC_BUFFER);
+                ret = MEMORY_E;
+            }
+        }
+        if (ret == 0) {
+            XMEMCPY((char*)curve->Gx, point + 2, curve->size * 2);
+            XMEMCPY((char*)curve->Gy, point + curve->size * 2 + 2,
+                                                               curve->size * 2);
+            ((char*)curve->Gx)[curve->size * 2] = '\0';
+            ((char*)curve->Gy)[curve->size * 2] = '\0';
+            XFREE(point, key->heap, DYNAMIC_TYPE_ECC_BUFFER);
+            ret = ASNToHexString(input, inOutIdx, (char**)&curve->order, inSz,
+                                            key->heap, DYNAMIC_TYPE_ECC_BUFFER);
+        }
+        if (ret == 0) {
+            curve->cofactor = GetInteger7Bit(input, inOutIdx, inSz);
+
+            curve->oid = NULL;
+            curve->oidSz = 0;
+            curve->oidSum = 0;
+
+            if (wc_ecc_set_custom_curve(key, curve) < 0) {
+                ret = ASN_PARSE_E;
+            }
+            key->deallocSet = 1;
+            curve = NULL;
+        }
+        if (curve != NULL)
+            wc_ecc_free_curve(curve, key->heap);
+
+        if (ret < 0)
+            return ret;
+#else
+        return ASN_PARSE_E;
+#endif /* WOLFSSL_CUSTOM_CURVES */
+    }
+    else {
     /* ecc params information */
-#ifdef ECC_CHECK_PUBLIC_KEY_OID
     ret = GetObjectId(input, inOutIdx, &oidSum, oidIgnoreType, inSz);
     if (ret != 0)
         return ret;
-    if (CheckCurve(oidSum) < 0)
+
+        /* get curve id */
+        curve_id = wc_ecc_get_oid(oidSum, NULL, 0);
+        if (curve_id < 0)
         return ECC_CURVE_OID_E;
-#else
-    ret = SkipObjectId(input, inOutIdx, inSz);
+    }
+
+    /* key header */
+    ret = CheckBitString(input, inOutIdx, &length, inSz, 1, NULL);
     if (ret != 0)
         return ret;
-#endif
-
-    /* key header */
-    ret = CheckBitString(input, inOutIdx, NULL, inSz, 1, NULL);
-    if (ret != 0)
-        return ret;
 
     /* This is the raw point data compressed or uncompressed. */
-    if (wc_ecc_import_x963(input + *inOutIdx, inSz - *inOutIdx, key) != 0)
+    if (wc_ecc_import_x963_ex(input + *inOutIdx, inSz - *inOutIdx, key,
+                                                            curve_id) != 0) {
         return ASN_ECC_KEY_E;
+}
+
+    *inOutIdx += length;
 
     return 0;
 }
 
-
-#ifdef WOLFSSL_KEY_GEN
-
+#if defined(HAVE_ECC_KEY_EXPORT) && !defined(NO_ASN_CRYPT)
 /* build DER formatted ECC key, include optional public key if requested,
  * return length on success, negative on error */
@@ -10350,5 +13697,4 @@
 }
 
-
 /* Write a Private ecc key, including public to DER format,
  * length on success else < 0 */
@@ -10366,6 +13712,74 @@
 }
 
-#endif /* WOLFSSL_KEY_GEN */
-
+/* Write only private ecc key to unencrypted PKCS#8 format.
+ *
+ * If output is NULL, places required PKCS#8 buffer size in outLen and
+ * returns LENGTH_ONLY_E.
+ *
+ * return length on success else < 0 */
+int wc_EccPrivateKeyToPKCS8(ecc_key* key, byte* output, word32* outLen)
+{
+    int ret, tmpDerSz;
+    int algoID = 0;
+    word32 oidSz = 0;
+    word32 pkcs8Sz = 0;
+    const byte* curveOID = NULL;
+    byte* tmpDer = NULL;
+
+    if (key == NULL || outLen == NULL)
+        return BAD_FUNC_ARG;
+
+    /* set algoID, get curve OID */
+    algoID = ECDSAk;
+    ret = wc_ecc_get_oid(key->dp->oidSum, &curveOID, &oidSz);
+    if (ret < 0)
+        return ret;
+
+    /* temp buffer for plain DER key */
+    tmpDer = (byte*)XMALLOC(ECC_BUFSIZE, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (tmpDer == NULL)
+        return MEMORY_E;
+
+    XMEMSET(tmpDer, 0, ECC_BUFSIZE);
+
+    tmpDerSz = wc_BuildEccKeyDer(key, tmpDer, ECC_BUFSIZE, 0);
+    if (tmpDerSz < 0) {
+        XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        return tmpDerSz;
+    }
+
+    /* get pkcs8 expected output size */
+    ret = wc_CreatePKCS8Key(NULL, &pkcs8Sz, tmpDer, tmpDerSz, algoID,
+                            curveOID, oidSz);
+    if (ret != LENGTH_ONLY_E) {
+        XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        return ret;
+    }
+
+    if (output == NULL) {
+        XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        *outLen = pkcs8Sz;
+        return LENGTH_ONLY_E;
+
+    } else if (*outLen < pkcs8Sz) {
+        XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        WOLFSSL_MSG("Input buffer too small for ECC PKCS#8 key");
+        return BUFFER_E;
+    }
+
+    ret = wc_CreatePKCS8Key(output, &pkcs8Sz, tmpDer, tmpDerSz,
+                            algoID, curveOID, oidSz);
+    if (ret < 0) {
+        XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        return ret;
+    }
+
+    XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+
+    *outLen = ret;
+    return ret;
+}
+
+#endif /* HAVE_ECC_KEY_EXPORT && !NO_ASN_CRYPT */
 #endif  /* HAVE_ECC */
 
@@ -10384,6 +13798,5 @@
         return BAD_FUNC_ARG;
 
-    if (GetSequence(input, inOutIdx, &length, inSz) < 0)
-        return ASN_PARSE_E;
+    if (GetSequence(input, inOutIdx, &length, inSz) >= 0) {
     endKeyIdx = *inOutIdx + length;
 
@@ -10405,6 +13818,16 @@
     if (GetOctetString(input, inOutIdx, &privSz, inSz) < 0)
         return ASN_PARSE_E;
+
+        priv = input + *inOutIdx;
+        *inOutIdx += privSz;
+    }
+    else {
+        if (GetOctetString(input, inOutIdx, &privSz, inSz) < 0)
+            return ASN_PARSE_E;
+
     priv = input + *inOutIdx;
     *inOutIdx += privSz;
+        endKeyIdx = *inOutIdx;
+    }
 
     if (endKeyIdx == (int)*inOutIdx) {
@@ -10435,7 +13858,4 @@
     int    length;
     int    ret;
-#ifdef ECC_CHECK_PUBLIC_KEY_OID
-    word32 oidSum;
-#endif
 
     if (input == NULL || inOutIdx == NULL || key == NULL || inSz == 0)
@@ -10548,26 +13968,19 @@
                         byte* format, int maxIdx)
 {
-    int    length;
+    int    ret, length;
+    const byte *datePtr = NULL;
 
     WOLFSSL_ENTER("GetBasicDate");
 
-    *format = source[*idx];
-    *idx += 1;
-    if (*format != ASN_UTC_TIME && *format != ASN_GENERALIZED_TIME)
-        return ASN_TIME_E;
-
-    if (GetLength(source, idx, &length, maxIdx) < 0)
-        return ASN_PARSE_E;
-
-    if (length > MAX_DATE_SIZE || length < MIN_DATE_SIZE)
-        return ASN_DATE_SZ_E;
-
-    XMEMCPY(date, &source[*idx], length);
-    *idx += length;
+    ret = GetDateInfo(source, idx, &datePtr, format, &length, maxIdx);
+    if (ret < 0)
+        return ret;
+
+    XMEMCPY(date, datePtr, length);
 
     return 0;
 }
 
-#endif
+#endif /* HAVE_OCSP || HAVE_CRL */
 
 
@@ -10667,5 +14080,5 @@
     }
 
-#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
     cs->thisDateAsn = source + idx;
 #endif
@@ -10688,5 +14101,5 @@
         if (GetLength(source, &idx, &length, size) < 0)
             return ASN_PARSE_E;
-#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
         cs->nextDateAsn = source + idx;
 #endif
@@ -10937,7 +14350,10 @@
             else {
                 WOLFSSL_MSG("\tOCSP Responder key usage check failed");
-
+    #ifdef OPENSSL_EXTRA
+                resp->verifyError = OCSP_BAD_ISSUER;
+    #else
                 FreeDecodedCert(&cert);
                 return BAD_OCSP_RESPONDER;
+    #endif
             }
         }
@@ -11207,5 +14623,5 @@
 
         if (cert->extAuthInfoSz != 0 && cert->extAuthInfo != NULL) {
-            req->url = (byte*)XMALLOC(cert->extAuthInfoSz, req->heap,
+            req->url = (byte*)XMALLOC(cert->extAuthInfoSz + 1, req->heap,
                                                      DYNAMIC_TYPE_OCSP_REQUEST);
             if (req->url == NULL) {
@@ -11216,4 +14632,5 @@
             XMEMCPY(req->url, cert->extAuthInfo, cert->extAuthInfoSz);
             req->urlSz = cert->extAuthInfoSz;
+            req->url[req->urlSz] = 0;
         }
     }
@@ -11249,7 +14666,9 @@
         if (req->serial)
             XFREE(req->serial, req->heap, DYNAMIC_TYPE_OCSP_REQUEST);
+        req->serial = NULL;
 
         if (req->url)
             XFREE(req->url, req->heap, DYNAMIC_TYPE_OCSP_REQUEST);
+        req->url = NULL;
     }
 }
@@ -11323,5 +14742,5 @@
 }
 
-#endif
+#endif /* HAVE_OCSP */
 
 
@@ -11353,9 +14772,5 @@
         return ASN_PARSE_E;
 
-#ifdef NO_SHA
-    ret = wc_Sha256Hash(source + dummy, length + *idx - dummy, hash);
-#else
-    ret = wc_ShaHash(source + dummy, length + *idx - dummy, hash);
-#endif
+    ret = CalcHashId(source + dummy, length + *idx - dummy, hash);
 
     *idx += length;
@@ -11404,5 +14819,5 @@
                       int maxIdx)
 {
-    int    len;
+    int    ret, len;
     word32 end;
     byte   b;
@@ -11434,19 +14849,10 @@
     dcrl->totalCerts++;
 
-
     /* get date */
-    b = buff[*idx];
-    *idx += 1;
-
-    if (b != ASN_UTC_TIME && b != ASN_GENERALIZED_TIME) {
+    ret = GetDateInfo(buff, idx, NULL, &b, NULL, maxIdx);
+    if (ret < 0) {
         WOLFSSL_MSG("Expecting Date");
-        return ASN_PARSE_E;
-    }
-
-    if (GetLength(buff, idx, &len, maxIdx) < 0)
-        return ASN_PARSE_E;
-
-    /* skip for now */
-    *idx += len;
+        return ret;
+    }
 
     if (*idx != end)  /* skip extensions */
@@ -11610,4 +15016,89 @@
 #endif /* HAVE_CRL */
 
+
+
+#ifdef WOLFSSL_CERT_PIV
+
+int wc_ParseCertPIV(wc_CertPIV* piv, const byte* buf, word32 totalSz)
+{
+    int length = 0;
+    word32 idx = 0;
+
+    WOLFSSL_ENTER("wc_ParseCertPIV");
+
+    if (piv == NULL || buf == NULL || totalSz == 0)
+        return BAD_FUNC_ARG;
+
+    XMEMSET(piv, 0, sizeof(wc_CertPIV));
+
+    /* Detect Identiv PIV (with 0x0A, 0x0B and 0x0C sections) */
+    /* Certificate (0A 82 05FA) */
+    if (GetASNHeader(buf, ASN_PIV_CERT, &idx, &length, totalSz) >= 0) {
+        /* Identiv Type PIV card */
+        piv->isIdentiv = 1;
+
+        piv->cert =   &buf[idx];
+        piv->certSz = length;
+        idx += length;
+
+        /* Nonce (0B 14) */
+        if (GetASNHeader(buf, ASN_PIV_NONCE, &idx, &length, totalSz) >= 0) {
+            piv->nonce =   &buf[idx];
+            piv->nonceSz = length;
+            idx += length;
+        }
+
+        /* Signed Nonce (0C 82 0100) */
+        if (GetASNHeader(buf, ASN_PIV_SIGNED_NONCE, &idx, &length, totalSz) >= 0) {
+            piv->signedNonce =   &buf[idx];
+            piv->signedNonceSz = length;
+            idx += length;
+        }
+
+        idx = 0;
+        buf = piv->cert;
+        totalSz = piv->certSz;
+    }
+
+    /* Certificate Buffer Total Size (53 82 05F6) */
+    if (GetASNHeader(buf, ASN_APPLICATION | ASN_PRINTABLE_STRING, &idx,
+                                                   &length, totalSz) < 0) {
+        return ASN_PARSE_E;
+    }
+    /* PIV Certificate (70 82 05ED) */
+    if (GetASNHeader(buf, ASN_PIV_TAG_CERT, &idx, &length,
+                                                         totalSz) < 0) {
+        return ASN_PARSE_E;
+    }
+
+    /* Capture certificate buffer pointer and length */
+    piv->cert =   &buf[idx];
+    piv->certSz = length;
+    idx += length;
+
+    /* PIV Certificate Info (71 01 00) */
+    if (GetASNHeader(buf, ASN_PIV_TAG_CERT_INFO, &idx, &length,
+                                                        totalSz) >= 0) {
+        if (length >= 1) {
+            piv->compression = (buf[idx] & ASN_PIV_CERT_INFO_COMPRESSED);
+            piv->isX509 =      (buf[idx] & ASN_PIV_CERT_INFO_ISX509);
+        }
+        idx += length;
+    }
+
+    /* PIV Error Detection (FE 00) */
+    if (GetASNHeader(buf, ASN_PIV_TAG_ERR_DET, &idx, &length,
+                                                        totalSz) >= 0) {
+        piv->certErrDet =   &buf[idx];
+        piv->certErrDetSz = length;
+        idx += length;
+    }
+
+    return 0;
+}
+
+#endif /* WOLFSSL_CERT_PIV */
+
+
 #undef ERROR_OUT
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/blake2b.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/blake2b.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/blake2b.c	(revision 372)
@@ -71,5 +71,5 @@
 
 
-static INLINE int blake2b_set_lastnode( blake2b_state *S )
+static WC_INLINE int blake2b_set_lastnode( blake2b_state *S )
 {
   S->f[1] = ~0ULL;
@@ -78,5 +78,5 @@
 
 /* Some helper functions, not necessarily useful */
-static INLINE int blake2b_set_lastblock( blake2b_state *S )
+static WC_INLINE int blake2b_set_lastblock( blake2b_state *S )
 {
   if( S->last_node ) blake2b_set_lastnode( S );
@@ -86,5 +86,5 @@
 }
 
-static INLINE int blake2b_increment_counter( blake2b_state *S, const word64
+static WC_INLINE int blake2b_increment_counter( blake2b_state *S, const word64
                                              inc )
 {
@@ -94,5 +94,5 @@
 }
 
-static INLINE int blake2b_init0( blake2b_state *S )
+static WC_INLINE int blake2b_init0( blake2b_state *S )
 {
   int i;
@@ -423,4 +423,7 @@
 int wc_InitBlake2b(Blake2b* b2b, word32 digestSz)
 {
+    if (b2b == NULL){
+        return -1;
+    }
     b2b->digestSz = digestSz;
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/camellia.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/camellia.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/camellia.c	(revision 372)
@@ -1599,8 +1599,9 @@
 int wc_CamelliaCbcEncrypt(Camellia* cam, byte* out, const byte* in, word32 sz)
 {
+    word32 blocks;
     if (cam == NULL || out == NULL || in == NULL) {
         return BAD_FUNC_ARG;
     }
-    word32 blocks = sz / CAMELLIA_BLOCK_SIZE;
+    blocks = sz / CAMELLIA_BLOCK_SIZE;
 
     while (blocks--) {
@@ -1620,8 +1621,9 @@
 int wc_CamelliaCbcDecrypt(Camellia* cam, byte* out, const byte* in, word32 sz)
 {
+    word32 blocks;
     if (cam == NULL || out == NULL || in == NULL) {
         return BAD_FUNC_ARG;
     }
-    word32 blocks = sz / CAMELLIA_BLOCK_SIZE;
+    blocks = sz / CAMELLIA_BLOCK_SIZE;
 
     while (blocks--) {
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/coding.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/coding.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/coding.c	(revision 372)
@@ -37,5 +37,7 @@
     BAD         = 0xFF,  /* invalid encoding */
     PAD         = '=',
-    PEM_LINE_SZ = 64
+    PEM_LINE_SZ = 64,
+    BASE64_MIN  = 0x2B,
+    BASE16_MIN  = 0x30,
 };
 
@@ -60,5 +62,5 @@
     word32 j = 0;
     word32 plainSz = inLen - ((inLen + (PEM_LINE_SZ - 1)) / PEM_LINE_SZ );
-    const byte maxIdx = (byte)sizeof(base64Decode) + 0x2B - 1;
+    const byte maxIdx = (byte)sizeof(base64Decode) + BASE64_MIN - 1;
 
     plainSz = (plainSz * 3 + 3) / 4;
@@ -82,5 +84,5 @@
             pad4 = 1;
 
-        if (e1 < 0x2B || e2 < 0x2B || e3 < 0x2B || e4 < 0x2B) {
+        if (e1 < BASE64_MIN || e2 < BASE64_MIN || e3 < BASE64_MIN || e4 < BASE64_MIN) {
             WOLFSSL_MSG("Bad Base64 Decode data, too small");
             return ASN_INPUT_E;
@@ -92,8 +94,8 @@
         }
 
-        e1 = base64Decode[e1 - 0x2B];
-        e2 = base64Decode[e2 - 0x2B];
-        e3 = (e3 == PAD) ? 0 : base64Decode[e3 - 0x2B];
-        e4 = (e4 == PAD) ? 0 : base64Decode[e4 - 0x2B];
+        e1 = base64Decode[e1 - BASE64_MIN];
+        e2 = base64Decode[e2 - BASE64_MIN];
+        e3 = (e3 == PAD) ? 0 : base64Decode[e3 - BASE64_MIN];
+        e4 = (e4 == PAD) ? 0 : base64Decode[e4 - BASE64_MIN];
 
         b1 = (byte)((e1 << 2) | (e2 >> 4));
@@ -345,9 +347,8 @@
 }
 
-#endif  /* defined(WOLFSSL_BASE64_ENCODE) */
-
-
-#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) || defined(HAVE_FIPS) \
-                           || defined(HAVE_ECC_CDH)
+#endif /* WOLFSSL_BASE64_ENCODE */
+
+
+#ifdef WOLFSSL_BASE16
 
 static
@@ -371,5 +372,5 @@
 
     if (inLen == 1 && *outLen && in) {
-        byte b = in[inIdx++] - 0x30;  /* 0 starts at 0x30 */
+        byte b = in[inIdx++] - BASE16_MIN;  /* 0 starts at 0x30 */
 
         /* sanity check */
@@ -395,6 +396,6 @@
 
     while (inLen) {
-        byte b  = in[inIdx++] - 0x30;  /* 0 starts at 0x30 */
-        byte b2 = in[inIdx++] - 0x30;
+        byte b  = in[inIdx++] - BASE16_MIN;  /* 0 starts at 0x30 */
+        byte b2 = in[inIdx++] - BASE16_MIN;
 
         /* sanity checks */
@@ -455,5 +456,5 @@
 }
 
-#endif /* (OPENSSL_EXTRA) || (HAVE_WEBSERVER) || (HAVE_FIPS) */
-
-#endif /* NO_CODING */
+#endif /* WOLFSSL_BASE16 */
+
+#endif /* !NO_CODING */
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/des3.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/des3.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/des3.c	(revision 372)
@@ -32,8 +32,22 @@
 #ifndef NO_DES3
 
+#if defined(HAVE_FIPS) && \
+	defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+
+    /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+    #define FIPS_NO_WRAPPERS
+
+    #ifdef USE_WINDOWS_API
+        #pragma code_seg(".fipsA$i")
+        #pragma const_seg(".fipsB$i")
+    #endif
+#endif
+
 #include <wolfssl/wolfcrypt/des3.h>
 
 /* fips wrapper calls, user can call direct */
-#ifdef HAVE_FIPS
+#if defined(HAVE_FIPS) && \
+    (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))
+
     int wc_Des_SetKey(Des* des, const byte* key, const byte* iv, int dir)
     {
@@ -108,5 +122,5 @@
     }
 
-#else /* build without fips */
+#else /* else build without fips, or for FIPS v2 */
 
 
@@ -1287,5 +1301,5 @@
     };
 
-    static INLINE void IPERM(word32* left, word32* right)
+    static WC_INLINE void IPERM(word32* left, word32* right)
     {
         word32 work;
@@ -1313,5 +1327,5 @@
     }
 
-    static INLINE void FPERM(word32* left, word32* right)
+    static WC_INLINE void FPERM(word32* left, word32* right)
     {
         word32 work;
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/dh.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/dh.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/dh.c	(revision 372)
@@ -29,4 +29,16 @@
 #ifndef NO_DH
 
+#if defined(HAVE_FIPS) && \
+	defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+
+    /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+    #define FIPS_NO_WRAPPERS
+
+    #ifdef USE_WINDOWS_API
+        #pragma code_seg(".fipsA$m")
+        #pragma const_seg(".fipsB$m")
+    #endif
+#endif
+
 #include <wolfssl/wolfcrypt/dh.h>
 #include <wolfssl/wolfcrypt/error-crypt.h>
@@ -43,4 +55,15 @@
     #include <wolfcrypt/src/misc.c>
 #endif
+
+
+/*
+Possible DH enable options:
+ * NO_RSA:              Overall control of DH                 default: on (not defined)
+ * WOLFSSL_OLD_PRIME_CHECK: Disables the new prime number check. It does not
+                        directly effect this file, but it does speed up DH
+                        removing the testing. It is not recommended to
+                        disable the prime checking.           default: off
+
+*/
 
 
@@ -89,8 +112,47 @@
 };
 static const byte dh_ffdhe2048_g[] = { 0x02 };
+#ifdef HAVE_FFDHE_Q
+static const byte dh_ffdhe2048_q[] = {
+    0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xD6, 0xFC, 0x2A, 0x2C, 0x51, 0x5D, 0xA5, 0x4D,
+    0x57, 0xEE, 0x2B, 0x10, 0x13, 0x9E, 0x9E, 0x78,
+    0xEC, 0x5C, 0xE2, 0xC1, 0xE7, 0x16, 0x9B, 0x4A,
+    0xD4, 0xF0, 0x9B, 0x20, 0x8A, 0x32, 0x19, 0xFD,
+    0xE6, 0x49, 0xCE, 0xE7, 0x12, 0x4D, 0x9F, 0x7C,
+    0xBE, 0x97, 0xF1, 0xB1, 0xB1, 0x86, 0x3A, 0xEC,
+    0x7B, 0x40, 0xD9, 0x01, 0x57, 0x62, 0x30, 0xBD,
+    0x69, 0xEF, 0x8F, 0x6A, 0xEA, 0xFE, 0xB2, 0xB0,
+    0x92, 0x19, 0xFA, 0x8F, 0xAF, 0x83, 0x37, 0x68,
+    0x42, 0xB1, 0xB2, 0xAA, 0x9E, 0xF6, 0x8D, 0x79,
+    0xDA, 0xAB, 0x89, 0xAF, 0x3F, 0xAB, 0xE4, 0x9A,
+    0xCC, 0x27, 0x86, 0x38, 0x70, 0x73, 0x45, 0xBB,
+    0xF1, 0x53, 0x44, 0xED, 0x79, 0xF7, 0xF4, 0x39,
+    0x0E, 0xF8, 0xAC, 0x50, 0x9B, 0x56, 0xF3, 0x9A,
+    0x98, 0x56, 0x65, 0x27, 0xA4, 0x1D, 0x3C, 0xBD,
+    0x5E, 0x05, 0x58, 0xC1, 0x59, 0x92, 0x7D, 0xB0,
+    0xE8, 0x84, 0x54, 0xA5, 0xD9, 0x64, 0x71, 0xFD,
+    0xDC, 0xB5, 0x6D, 0x5B, 0xB0, 0x6B, 0xFA, 0x34,
+    0x0E, 0xA7, 0xA1, 0x51, 0xEF, 0x1C, 0xA6, 0xFA,
+    0x57, 0x2B, 0x76, 0xF3, 0xB1, 0xB9, 0x5D, 0x8C,
+    0x85, 0x83, 0xD3, 0xE4, 0x77, 0x05, 0x36, 0xB8,
+    0x4F, 0x01, 0x7E, 0x70, 0xE6, 0xFB, 0xF1, 0x76,
+    0x60, 0x1A, 0x02, 0x66, 0x94, 0x1A, 0x17, 0xB0,
+    0xC8, 0xB9, 0x7F, 0x4E, 0x74, 0xC2, 0xC1, 0xFF,
+    0xC7, 0x27, 0x89, 0x19, 0x77, 0x79, 0x40, 0xC1,
+    0xE1, 0xFF, 0x1D, 0x8D, 0xA6, 0x37, 0xD6, 0xB9,
+    0x9D, 0xDA, 0xFE, 0x5E, 0x17, 0x61, 0x10, 0x02,
+    0xE2, 0xC7, 0x78, 0xC1, 0xBE, 0x8B, 0x41, 0xD9,
+    0x63, 0x79, 0xA5, 0x13, 0x60, 0xD9, 0x77, 0xFD,
+    0x44, 0x35, 0xA1, 0x1C, 0x30, 0x94, 0x2E, 0x4B,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+#endif /* HAVE_FFDHE_Q */
 
 const DhParams* wc_Dh_ffdhe2048_Get(void)
 {
     static const DhParams ffdhe2048 = {
+        #ifdef HAVE_FFDHE_Q
+            dh_ffdhe2048_q, sizeof(dh_ffdhe2048_q),
+        #endif /* HAVE_FFDHE_Q */
         dh_ffdhe2048_p, sizeof(dh_ffdhe2048_p),
         dh_ffdhe2048_g, sizeof(dh_ffdhe2048_g)
@@ -152,8 +214,63 @@
 };
 static const byte dh_ffdhe3072_g[] = { 0x02 };
+#ifdef HAVE_FFDHE_Q
+static const byte dh_ffdhe3072_q[] = {
+    0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xD6, 0xFC, 0x2A, 0x2C, 0x51, 0x5D, 0xA5, 0x4D,
+    0x57, 0xEE, 0x2B, 0x10, 0x13, 0x9E, 0x9E, 0x78,
+    0xEC, 0x5C, 0xE2, 0xC1, 0xE7, 0x16, 0x9B, 0x4A,
+    0xD4, 0xF0, 0x9B, 0x20, 0x8A, 0x32, 0x19, 0xFD,
+    0xE6, 0x49, 0xCE, 0xE7, 0x12, 0x4D, 0x9F, 0x7C,
+    0xBE, 0x97, 0xF1, 0xB1, 0xB1, 0x86, 0x3A, 0xEC,
+    0x7B, 0x40, 0xD9, 0x01, 0x57, 0x62, 0x30, 0xBD,
+    0x69, 0xEF, 0x8F, 0x6A, 0xEA, 0xFE, 0xB2, 0xB0,
+    0x92, 0x19, 0xFA, 0x8F, 0xAF, 0x83, 0x37, 0x68,
+    0x42, 0xB1, 0xB2, 0xAA, 0x9E, 0xF6, 0x8D, 0x79,
+    0xDA, 0xAB, 0x89, 0xAF, 0x3F, 0xAB, 0xE4, 0x9A,
+    0xCC, 0x27, 0x86, 0x38, 0x70, 0x73, 0x45, 0xBB,
+    0xF1, 0x53, 0x44, 0xED, 0x79, 0xF7, 0xF4, 0x39,
+    0x0E, 0xF8, 0xAC, 0x50, 0x9B, 0x56, 0xF3, 0x9A,
+    0x98, 0x56, 0x65, 0x27, 0xA4, 0x1D, 0x3C, 0xBD,
+    0x5E, 0x05, 0x58, 0xC1, 0x59, 0x92, 0x7D, 0xB0,
+    0xE8, 0x84, 0x54, 0xA5, 0xD9, 0x64, 0x71, 0xFD,
+    0xDC, 0xB5, 0x6D, 0x5B, 0xB0, 0x6B, 0xFA, 0x34,
+    0x0E, 0xA7, 0xA1, 0x51, 0xEF, 0x1C, 0xA6, 0xFA,
+    0x57, 0x2B, 0x76, 0xF3, 0xB1, 0xB9, 0x5D, 0x8C,
+    0x85, 0x83, 0xD3, 0xE4, 0x77, 0x05, 0x36, 0xB8,
+    0x4F, 0x01, 0x7E, 0x70, 0xE6, 0xFB, 0xF1, 0x76,
+    0x60, 0x1A, 0x02, 0x66, 0x94, 0x1A, 0x17, 0xB0,
+    0xC8, 0xB9, 0x7F, 0x4E, 0x74, 0xC2, 0xC1, 0xFF,
+    0xC7, 0x27, 0x89, 0x19, 0x77, 0x79, 0x40, 0xC1,
+    0xE1, 0xFF, 0x1D, 0x8D, 0xA6, 0x37, 0xD6, 0xB9,
+    0x9D, 0xDA, 0xFE, 0x5E, 0x17, 0x61, 0x10, 0x02,
+    0xE2, 0xC7, 0x78, 0xC1, 0xBE, 0x8B, 0x41, 0xD9,
+    0x63, 0x79, 0xA5, 0x13, 0x60, 0xD9, 0x77, 0xFD,
+    0x44, 0x35, 0xA1, 0x1C, 0x30, 0x8F, 0xE7, 0xEE,
+    0x6F, 0x1A, 0xAD, 0x9D, 0xB2, 0x8C, 0x81, 0xAD,
+    0xDE, 0x1A, 0x7A, 0x6F, 0x7C, 0xCE, 0x01, 0x1C,
+    0x30, 0xDA, 0x37, 0xE4, 0xEB, 0x73, 0x64, 0x83,
+    0xBD, 0x6C, 0x8E, 0x93, 0x48, 0xFB, 0xFB, 0xF7,
+    0x2C, 0xC6, 0x58, 0x7D, 0x60, 0xC3, 0x6C, 0x8E,
+    0x57, 0x7F, 0x09, 0x84, 0xC2, 0x89, 0xC9, 0x38,
+    0x5A, 0x09, 0x86, 0x49, 0xDE, 0x21, 0xBC, 0xA2,
+    0x7A, 0x7E, 0xA2, 0x29, 0x71, 0x6B, 0xA6, 0xE9,
+    0xB2, 0x79, 0x71, 0x0F, 0x38, 0xFA, 0xA5, 0xFF,
+    0xAE, 0x57, 0x41, 0x55, 0xCE, 0x4E, 0xFB, 0x4F,
+    0x74, 0x36, 0x95, 0xE2, 0x91, 0x1B, 0x1D, 0x06,
+    0xD5, 0xE2, 0x90, 0xCB, 0xCD, 0x86, 0xF5, 0x6D,
+    0x0E, 0xDF, 0xCD, 0x21, 0x6A, 0xE2, 0x24, 0x27,
+    0x05, 0x5E, 0x68, 0x35, 0xFD, 0x29, 0xEE, 0xF7,
+    0x9E, 0x0D, 0x90, 0x77, 0x1F, 0xEA, 0xCE, 0xBE,
+    0x12, 0xF2, 0x0E, 0x95, 0xB3, 0x63, 0x17, 0x1B,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+#endif /* HAVE_FFDHE_Q */
 
 const DhParams* wc_Dh_ffdhe3072_Get(void)
 {
     static const DhParams ffdhe3072 = {
+        #ifdef HAVE_FFDHE_Q
+            dh_ffdhe3072_q, sizeof(dh_ffdhe3072_q),
+        #endif /* HAVE_FFDHE_Q */
         dh_ffdhe3072_p, sizeof(dh_ffdhe3072_p),
         dh_ffdhe3072_g, sizeof(dh_ffdhe3072_g)
@@ -231,8 +348,79 @@
 };
 static const byte dh_ffdhe4096_g[] = { 0x02 };
+#ifdef HAVE_FFDHE_Q
+static const byte dh_ffdhe4096_q[] = {
+    0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xD6, 0xFC, 0x2A, 0x2C, 0x51, 0x5D, 0xA5, 0x4D,
+    0x57, 0xEE, 0x2B, 0x10, 0x13, 0x9E, 0x9E, 0x78,
+    0xEC, 0x5C, 0xE2, 0xC1, 0xE7, 0x16, 0x9B, 0x4A,
+    0xD4, 0xF0, 0x9B, 0x20, 0x8A, 0x32, 0x19, 0xFD,
+    0xE6, 0x49, 0xCE, 0xE7, 0x12, 0x4D, 0x9F, 0x7C,
+    0xBE, 0x97, 0xF1, 0xB1, 0xB1, 0x86, 0x3A, 0xEC,
+    0x7B, 0x40, 0xD9, 0x01, 0x57, 0x62, 0x30, 0xBD,
+    0x69, 0xEF, 0x8F, 0x6A, 0xEA, 0xFE, 0xB2, 0xB0,
+    0x92, 0x19, 0xFA, 0x8F, 0xAF, 0x83, 0x37, 0x68,
+    0x42, 0xB1, 0xB2, 0xAA, 0x9E, 0xF6, 0x8D, 0x79,
+    0xDA, 0xAB, 0x89, 0xAF, 0x3F, 0xAB, 0xE4, 0x9A,
+    0xCC, 0x27, 0x86, 0x38, 0x70, 0x73, 0x45, 0xBB,
+    0xF1, 0x53, 0x44, 0xED, 0x79, 0xF7, 0xF4, 0x39,
+    0x0E, 0xF8, 0xAC, 0x50, 0x9B, 0x56, 0xF3, 0x9A,
+    0x98, 0x56, 0x65, 0x27, 0xA4, 0x1D, 0x3C, 0xBD,
+    0x5E, 0x05, 0x58, 0xC1, 0x59, 0x92, 0x7D, 0xB0,
+    0xE8, 0x84, 0x54, 0xA5, 0xD9, 0x64, 0x71, 0xFD,
+    0xDC, 0xB5, 0x6D, 0x5B, 0xB0, 0x6B, 0xFA, 0x34,
+    0x0E, 0xA7, 0xA1, 0x51, 0xEF, 0x1C, 0xA6, 0xFA,
+    0x57, 0x2B, 0x76, 0xF3, 0xB1, 0xB9, 0x5D, 0x8C,
+    0x85, 0x83, 0xD3, 0xE4, 0x77, 0x05, 0x36, 0xB8,
+    0x4F, 0x01, 0x7E, 0x70, 0xE6, 0xFB, 0xF1, 0x76,
+    0x60, 0x1A, 0x02, 0x66, 0x94, 0x1A, 0x17, 0xB0,
+    0xC8, 0xB9, 0x7F, 0x4E, 0x74, 0xC2, 0xC1, 0xFF,
+    0xC7, 0x27, 0x89, 0x19, 0x77, 0x79, 0x40, 0xC1,
+    0xE1, 0xFF, 0x1D, 0x8D, 0xA6, 0x37, 0xD6, 0xB9,
+    0x9D, 0xDA, 0xFE, 0x5E, 0x17, 0x61, 0x10, 0x02,
+    0xE2, 0xC7, 0x78, 0xC1, 0xBE, 0x8B, 0x41, 0xD9,
+    0x63, 0x79, 0xA5, 0x13, 0x60, 0xD9, 0x77, 0xFD,
+    0x44, 0x35, 0xA1, 0x1C, 0x30, 0x8F, 0xE7, 0xEE,
+    0x6F, 0x1A, 0xAD, 0x9D, 0xB2, 0x8C, 0x81, 0xAD,
+    0xDE, 0x1A, 0x7A, 0x6F, 0x7C, 0xCE, 0x01, 0x1C,
+    0x30, 0xDA, 0x37, 0xE4, 0xEB, 0x73, 0x64, 0x83,
+    0xBD, 0x6C, 0x8E, 0x93, 0x48, 0xFB, 0xFB, 0xF7,
+    0x2C, 0xC6, 0x58, 0x7D, 0x60, 0xC3, 0x6C, 0x8E,
+    0x57, 0x7F, 0x09, 0x84, 0xC2, 0x89, 0xC9, 0x38,
+    0x5A, 0x09, 0x86, 0x49, 0xDE, 0x21, 0xBC, 0xA2,
+    0x7A, 0x7E, 0xA2, 0x29, 0x71, 0x6B, 0xA6, 0xE9,
+    0xB2, 0x79, 0x71, 0x0F, 0x38, 0xFA, 0xA5, 0xFF,
+    0xAE, 0x57, 0x41, 0x55, 0xCE, 0x4E, 0xFB, 0x4F,
+    0x74, 0x36, 0x95, 0xE2, 0x91, 0x1B, 0x1D, 0x06,
+    0xD5, 0xE2, 0x90, 0xCB, 0xCD, 0x86, 0xF5, 0x6D,
+    0x0E, 0xDF, 0xCD, 0x21, 0x6A, 0xE2, 0x24, 0x27,
+    0x05, 0x5E, 0x68, 0x35, 0xFD, 0x29, 0xEE, 0xF7,
+    0x9E, 0x0D, 0x90, 0x77, 0x1F, 0xEA, 0xCE, 0xBE,
+    0x12, 0xF2, 0x0E, 0x95, 0xB3, 0x4F, 0x0F, 0x78,
+    0xB7, 0x37, 0xA9, 0x61, 0x8B, 0x26, 0xFA, 0x7D,
+    0xBC, 0x98, 0x74, 0xF2, 0x72, 0xC4, 0x2B, 0xDB,
+    0x56, 0x3E, 0xAF, 0xA1, 0x6B, 0x4F, 0xB6, 0x8C,
+    0x3B, 0xB1, 0xE7, 0x8E, 0xAA, 0x81, 0xA0, 0x02,
+    0x43, 0xFA, 0xAD, 0xD2, 0xBF, 0x18, 0xE6, 0x3D,
+    0x38, 0x9A, 0xE4, 0x43, 0x77, 0xDA, 0x18, 0xC5,
+    0x76, 0xB5, 0x0F, 0x00, 0x96, 0xCF, 0x34, 0x19,
+    0x54, 0x83, 0xB0, 0x05, 0x48, 0xC0, 0x98, 0x62,
+    0x36, 0xE3, 0xBC, 0x7C, 0xB8, 0xD6, 0x80, 0x1C,
+    0x04, 0x94, 0xCC, 0xD1, 0x99, 0xE5, 0xC5, 0xBD,
+    0x0D, 0x0E, 0xDC, 0x9E, 0xB8, 0xA0, 0x00, 0x1E,
+    0x15, 0x27, 0x67, 0x54, 0xFC, 0xC6, 0x85, 0x66,
+    0x05, 0x41, 0x48, 0xE6, 0xE7, 0x64, 0xBE, 0xE7,
+    0xC7, 0x64, 0xDA, 0xAD, 0x3F, 0xC4, 0x52, 0x35,
+    0xA6, 0xDA, 0xD4, 0x28, 0xFA, 0x20, 0xC1, 0x70,
+    0xE3, 0x45, 0x00, 0x3F, 0x2F, 0x32, 0xAF, 0xB5,
+    0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+#endif /* HAVE_FFDHE_Q */
 
 const DhParams* wc_Dh_ffdhe4096_Get(void)
 {
     static const DhParams ffdhe4096 = {
+        #ifdef HAVE_FFDHE_Q
+            dh_ffdhe4096_q, sizeof(dh_ffdhe4096_q),
+        #endif /* HAVE_FFDHE_Q */
         dh_ffdhe4096_p, sizeof(dh_ffdhe4096_p),
         dh_ffdhe4096_g, sizeof(dh_ffdhe4096_g)
@@ -342,8 +530,111 @@
 };
 static const byte dh_ffdhe6144_g[] = { 0x02 };
+#ifdef HAVE_FFDHE_Q
+static const byte dh_ffdhe6144_q[] = {
+    0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xD6, 0xFC, 0x2A, 0x2C, 0x51, 0x5D, 0xA5, 0x4D,
+    0x57, 0xEE, 0x2B, 0x10, 0x13, 0x9E, 0x9E, 0x78,
+    0xEC, 0x5C, 0xE2, 0xC1, 0xE7, 0x16, 0x9B, 0x4A,
+    0xD4, 0xF0, 0x9B, 0x20, 0x8A, 0x32, 0x19, 0xFD,
+    0xE6, 0x49, 0xCE, 0xE7, 0x12, 0x4D, 0x9F, 0x7C,
+    0xBE, 0x97, 0xF1, 0xB1, 0xB1, 0x86, 0x3A, 0xEC,
+    0x7B, 0x40, 0xD9, 0x01, 0x57, 0x62, 0x30, 0xBD,
+    0x69, 0xEF, 0x8F, 0x6A, 0xEA, 0xFE, 0xB2, 0xB0,
+    0x92, 0x19, 0xFA, 0x8F, 0xAF, 0x83, 0x37, 0x68,
+    0x42, 0xB1, 0xB2, 0xAA, 0x9E, 0xF6, 0x8D, 0x79,
+    0xDA, 0xAB, 0x89, 0xAF, 0x3F, 0xAB, 0xE4, 0x9A,
+    0xCC, 0x27, 0x86, 0x38, 0x70, 0x73, 0x45, 0xBB,
+    0xF1, 0x53, 0x44, 0xED, 0x79, 0xF7, 0xF4, 0x39,
+    0x0E, 0xF8, 0xAC, 0x50, 0x9B, 0x56, 0xF3, 0x9A,
+    0x98, 0x56, 0x65, 0x27, 0xA4, 0x1D, 0x3C, 0xBD,
+    0x5E, 0x05, 0x58, 0xC1, 0x59, 0x92, 0x7D, 0xB0,
+    0xE8, 0x84, 0x54, 0xA5, 0xD9, 0x64, 0x71, 0xFD,
+    0xDC, 0xB5, 0x6D, 0x5B, 0xB0, 0x6B, 0xFA, 0x34,
+    0x0E, 0xA7, 0xA1, 0x51, 0xEF, 0x1C, 0xA6, 0xFA,
+    0x57, 0x2B, 0x76, 0xF3, 0xB1, 0xB9, 0x5D, 0x8C,
+    0x85, 0x83, 0xD3, 0xE4, 0x77, 0x05, 0x36, 0xB8,
+    0x4F, 0x01, 0x7E, 0x70, 0xE6, 0xFB, 0xF1, 0x76,
+    0x60, 0x1A, 0x02, 0x66, 0x94, 0x1A, 0x17, 0xB0,
+    0xC8, 0xB9, 0x7F, 0x4E, 0x74, 0xC2, 0xC1, 0xFF,
+    0xC7, 0x27, 0x89, 0x19, 0x77, 0x79, 0x40, 0xC1,
+    0xE1, 0xFF, 0x1D, 0x8D, 0xA6, 0x37, 0xD6, 0xB9,
+    0x9D, 0xDA, 0xFE, 0x5E, 0x17, 0x61, 0x10, 0x02,
+    0xE2, 0xC7, 0x78, 0xC1, 0xBE, 0x8B, 0x41, 0xD9,
+    0x63, 0x79, 0xA5, 0x13, 0x60, 0xD9, 0x77, 0xFD,
+    0x44, 0x35, 0xA1, 0x1C, 0x30, 0x8F, 0xE7, 0xEE,
+    0x6F, 0x1A, 0xAD, 0x9D, 0xB2, 0x8C, 0x81, 0xAD,
+    0xDE, 0x1A, 0x7A, 0x6F, 0x7C, 0xCE, 0x01, 0x1C,
+    0x30, 0xDA, 0x37, 0xE4, 0xEB, 0x73, 0x64, 0x83,
+    0xBD, 0x6C, 0x8E, 0x93, 0x48, 0xFB, 0xFB, 0xF7,
+    0x2C, 0xC6, 0x58, 0x7D, 0x60, 0xC3, 0x6C, 0x8E,
+    0x57, 0x7F, 0x09, 0x84, 0xC2, 0x89, 0xC9, 0x38,
+    0x5A, 0x09, 0x86, 0x49, 0xDE, 0x21, 0xBC, 0xA2,
+    0x7A, 0x7E, 0xA2, 0x29, 0x71, 0x6B, 0xA6, 0xE9,
+    0xB2, 0x79, 0x71, 0x0F, 0x38, 0xFA, 0xA5, 0xFF,
+    0xAE, 0x57, 0x41, 0x55, 0xCE, 0x4E, 0xFB, 0x4F,
+    0x74, 0x36, 0x95, 0xE2, 0x91, 0x1B, 0x1D, 0x06,
+    0xD5, 0xE2, 0x90, 0xCB, 0xCD, 0x86, 0xF5, 0x6D,
+    0x0E, 0xDF, 0xCD, 0x21, 0x6A, 0xE2, 0x24, 0x27,
+    0x05, 0x5E, 0x68, 0x35, 0xFD, 0x29, 0xEE, 0xF7,
+    0x9E, 0x0D, 0x90, 0x77, 0x1F, 0xEA, 0xCE, 0xBE,
+    0x12, 0xF2, 0x0E, 0x95, 0xB3, 0x4F, 0x0F, 0x78,
+    0xB7, 0x37, 0xA9, 0x61, 0x8B, 0x26, 0xFA, 0x7D,
+    0xBC, 0x98, 0x74, 0xF2, 0x72, 0xC4, 0x2B, 0xDB,
+    0x56, 0x3E, 0xAF, 0xA1, 0x6B, 0x4F, 0xB6, 0x8C,
+    0x3B, 0xB1, 0xE7, 0x8E, 0xAA, 0x81, 0xA0, 0x02,
+    0x43, 0xFA, 0xAD, 0xD2, 0xBF, 0x18, 0xE6, 0x3D,
+    0x38, 0x9A, 0xE4, 0x43, 0x77, 0xDA, 0x18, 0xC5,
+    0x76, 0xB5, 0x0F, 0x00, 0x96, 0xCF, 0x34, 0x19,
+    0x54, 0x83, 0xB0, 0x05, 0x48, 0xC0, 0x98, 0x62,
+    0x36, 0xE3, 0xBC, 0x7C, 0xB8, 0xD6, 0x80, 0x1C,
+    0x04, 0x94, 0xCC, 0xD1, 0x99, 0xE5, 0xC5, 0xBD,
+    0x0D, 0x0E, 0xDC, 0x9E, 0xB8, 0xA0, 0x00, 0x1E,
+    0x15, 0x27, 0x67, 0x54, 0xFC, 0xC6, 0x85, 0x66,
+    0x05, 0x41, 0x48, 0xE6, 0xE7, 0x64, 0xBE, 0xE7,
+    0xC7, 0x64, 0xDA, 0xAD, 0x3F, 0xC4, 0x52, 0x35,
+    0xA6, 0xDA, 0xD4, 0x28, 0xFA, 0x20, 0xC1, 0x70,
+    0xE3, 0x45, 0x00, 0x3F, 0x2F, 0x06, 0xEC, 0x81,
+    0x05, 0xFE, 0xB2, 0x5B, 0x22, 0x81, 0xB6, 0x3D,
+    0x27, 0x33, 0xBE, 0x96, 0x1C, 0x29, 0x95, 0x1D,
+    0x11, 0xDD, 0x22, 0x21, 0x65, 0x7A, 0x9F, 0x53,
+    0x1D, 0xDA, 0x2A, 0x19, 0x4D, 0xBB, 0x12, 0x64,
+    0x48, 0xBD, 0xEE, 0xB2, 0x58, 0xE0, 0x7E, 0xA6,
+    0x59, 0xC7, 0x46, 0x19, 0xA6, 0x38, 0x0E, 0x1D,
+    0x66, 0xD6, 0x83, 0x2B, 0xFE, 0x67, 0xF6, 0x38,
+    0xCD, 0x8F, 0xAE, 0x1F, 0x27, 0x23, 0x02, 0x0F,
+    0x9C, 0x40, 0xA3, 0xFD, 0xA6, 0x7E, 0xDA, 0x3B,
+    0xD2, 0x92, 0x38, 0xFB, 0xD4, 0xD4, 0xB4, 0x88,
+    0x5C, 0x2A, 0x99, 0x17, 0x6D, 0xB1, 0xA0, 0x6C,
+    0x50, 0x07, 0x78, 0x49, 0x1A, 0x82, 0x88, 0xF1,
+    0x85, 0x5F, 0x60, 0xFF, 0xFC, 0xF1, 0xD1, 0x37,
+    0x3F, 0xD9, 0x4F, 0xC6, 0x0C, 0x18, 0x11, 0xE1,
+    0xAC, 0x3F, 0x1C, 0x6D, 0x00, 0x3B, 0xEC, 0xDA,
+    0x3B, 0x1F, 0x27, 0x25, 0xCA, 0x59, 0x5D, 0xE0,
+    0xCA, 0x63, 0x32, 0x8F, 0x3B, 0xE5, 0x7C, 0xC9,
+    0x77, 0x55, 0x60, 0x11, 0x95, 0x14, 0x0D, 0xFB,
+    0x59, 0xD3, 0x9C, 0xE0, 0x91, 0x30, 0x8B, 0x41,
+    0x05, 0x74, 0x6D, 0xAC, 0x23, 0xD3, 0x3E, 0x5F,
+    0x7C, 0xE4, 0x84, 0x8D, 0xA3, 0x16, 0xA9, 0xC6,
+    0x6B, 0x95, 0x81, 0xBA, 0x35, 0x73, 0xBF, 0xAF,
+    0x31, 0x14, 0x96, 0x18, 0x8A, 0xB1, 0x54, 0x23,
+    0x28, 0x2E, 0xE4, 0x16, 0xDC, 0x2A, 0x19, 0xC5,
+    0x72, 0x4F, 0xA9, 0x1A, 0xE4, 0xAD, 0xC8, 0x8B,
+    0xC6, 0x67, 0x96, 0xEA, 0xE5, 0x67, 0x7A, 0x01,
+    0xF6, 0x4E, 0x8C, 0x08, 0x63, 0x13, 0x95, 0x82,
+    0x2D, 0x9D, 0xB8, 0xFC, 0xEE, 0x35, 0xC0, 0x6B,
+    0x1F, 0xEE, 0xA5, 0x47, 0x4D, 0x6D, 0x8F, 0x34,
+    0xB1, 0x53, 0x4A, 0x93, 0x6A, 0x18, 0xB0, 0xE0,
+    0xD2, 0x0E, 0xAB, 0x86, 0xBC, 0x9C, 0x6D, 0x6A,
+    0x52, 0x07, 0x19, 0x4E, 0x68, 0x72, 0x07, 0x32,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+#endif /* HAVE_FFDHE_Q */
 
 const DhParams* wc_Dh_ffdhe6144_Get(void)
 {
     static const DhParams ffdhe6144 = {
+        #ifdef HAVE_FFDHE_Q
+            dh_ffdhe6144_q, sizeof(dh_ffdhe6144_q),
+        #endif /* HAVE_FFDHE_Q */
         dh_ffdhe6144_p, sizeof(dh_ffdhe6144_p),
         dh_ffdhe6144_g, sizeof(dh_ffdhe6144_g)
@@ -485,8 +776,143 @@
 };
 static const byte dh_ffdhe8192_g[] = { 0x02 };
+#ifdef HAVE_FFDHE_Q
+static const byte dh_ffdhe8192_q[] = {
+    0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xD6, 0xFC, 0x2A, 0x2C, 0x51, 0x5D, 0xA5, 0x4D,
+    0x57, 0xEE, 0x2B, 0x10, 0x13, 0x9E, 0x9E, 0x78,
+    0xEC, 0x5C, 0xE2, 0xC1, 0xE7, 0x16, 0x9B, 0x4A,
+    0xD4, 0xF0, 0x9B, 0x20, 0x8A, 0x32, 0x19, 0xFD,
+    0xE6, 0x49, 0xCE, 0xE7, 0x12, 0x4D, 0x9F, 0x7C,
+    0xBE, 0x97, 0xF1, 0xB1, 0xB1, 0x86, 0x3A, 0xEC,
+    0x7B, 0x40, 0xD9, 0x01, 0x57, 0x62, 0x30, 0xBD,
+    0x69, 0xEF, 0x8F, 0x6A, 0xEA, 0xFE, 0xB2, 0xB0,
+    0x92, 0x19, 0xFA, 0x8F, 0xAF, 0x83, 0x37, 0x68,
+    0x42, 0xB1, 0xB2, 0xAA, 0x9E, 0xF6, 0x8D, 0x79,
+    0xDA, 0xAB, 0x89, 0xAF, 0x3F, 0xAB, 0xE4, 0x9A,
+    0xCC, 0x27, 0x86, 0x38, 0x70, 0x73, 0x45, 0xBB,
+    0xF1, 0x53, 0x44, 0xED, 0x79, 0xF7, 0xF4, 0x39,
+    0x0E, 0xF8, 0xAC, 0x50, 0x9B, 0x56, 0xF3, 0x9A,
+    0x98, 0x56, 0x65, 0x27, 0xA4, 0x1D, 0x3C, 0xBD,
+    0x5E, 0x05, 0x58, 0xC1, 0x59, 0x92, 0x7D, 0xB0,
+    0xE8, 0x84, 0x54, 0xA5, 0xD9, 0x64, 0x71, 0xFD,
+    0xDC, 0xB5, 0x6D, 0x5B, 0xB0, 0x6B, 0xFA, 0x34,
+    0x0E, 0xA7, 0xA1, 0x51, 0xEF, 0x1C, 0xA6, 0xFA,
+    0x57, 0x2B, 0x76, 0xF3, 0xB1, 0xB9, 0x5D, 0x8C,
+    0x85, 0x83, 0xD3, 0xE4, 0x77, 0x05, 0x36, 0xB8,
+    0x4F, 0x01, 0x7E, 0x70, 0xE6, 0xFB, 0xF1, 0x76,
+    0x60, 0x1A, 0x02, 0x66, 0x94, 0x1A, 0x17, 0xB0,
+    0xC8, 0xB9, 0x7F, 0x4E, 0x74, 0xC2, 0xC1, 0xFF,
+    0xC7, 0x27, 0x89, 0x19, 0x77, 0x79, 0x40, 0xC1,
+    0xE1, 0xFF, 0x1D, 0x8D, 0xA6, 0x37, 0xD6, 0xB9,
+    0x9D, 0xDA, 0xFE, 0x5E, 0x17, 0x61, 0x10, 0x02,
+    0xE2, 0xC7, 0x78, 0xC1, 0xBE, 0x8B, 0x41, 0xD9,
+    0x63, 0x79, 0xA5, 0x13, 0x60, 0xD9, 0x77, 0xFD,
+    0x44, 0x35, 0xA1, 0x1C, 0x30, 0x8F, 0xE7, 0xEE,
+    0x6F, 0x1A, 0xAD, 0x9D, 0xB2, 0x8C, 0x81, 0xAD,
+    0xDE, 0x1A, 0x7A, 0x6F, 0x7C, 0xCE, 0x01, 0x1C,
+    0x30, 0xDA, 0x37, 0xE4, 0xEB, 0x73, 0x64, 0x83,
+    0xBD, 0x6C, 0x8E, 0x93, 0x48, 0xFB, 0xFB, 0xF7,
+    0x2C, 0xC6, 0x58, 0x7D, 0x60, 0xC3, 0x6C, 0x8E,
+    0x57, 0x7F, 0x09, 0x84, 0xC2, 0x89, 0xC9, 0x38,
+    0x5A, 0x09, 0x86, 0x49, 0xDE, 0x21, 0xBC, 0xA2,
+    0x7A, 0x7E, 0xA2, 0x29, 0x71, 0x6B, 0xA6, 0xE9,
+    0xB2, 0x79, 0x71, 0x0F, 0x38, 0xFA, 0xA5, 0xFF,
+    0xAE, 0x57, 0x41, 0x55, 0xCE, 0x4E, 0xFB, 0x4F,
+    0x74, 0x36, 0x95, 0xE2, 0x91, 0x1B, 0x1D, 0x06,
+    0xD5, 0xE2, 0x90, 0xCB, 0xCD, 0x86, 0xF5, 0x6D,
+    0x0E, 0xDF, 0xCD, 0x21, 0x6A, 0xE2, 0x24, 0x27,
+    0x05, 0x5E, 0x68, 0x35, 0xFD, 0x29, 0xEE, 0xF7,
+    0x9E, 0x0D, 0x90, 0x77, 0x1F, 0xEA, 0xCE, 0xBE,
+    0x12, 0xF2, 0x0E, 0x95, 0xB3, 0x4F, 0x0F, 0x78,
+    0xB7, 0x37, 0xA9, 0x61, 0x8B, 0x26, 0xFA, 0x7D,
+    0xBC, 0x98, 0x74, 0xF2, 0x72, 0xC4, 0x2B, 0xDB,
+    0x56, 0x3E, 0xAF, 0xA1, 0x6B, 0x4F, 0xB6, 0x8C,
+    0x3B, 0xB1, 0xE7, 0x8E, 0xAA, 0x81, 0xA0, 0x02,
+    0x43, 0xFA, 0xAD, 0xD2, 0xBF, 0x18, 0xE6, 0x3D,
+    0x38, 0x9A, 0xE4, 0x43, 0x77, 0xDA, 0x18, 0xC5,
+    0x76, 0xB5, 0x0F, 0x00, 0x96, 0xCF, 0x34, 0x19,
+    0x54, 0x83, 0xB0, 0x05, 0x48, 0xC0, 0x98, 0x62,
+    0x36, 0xE3, 0xBC, 0x7C, 0xB8, 0xD6, 0x80, 0x1C,
+    0x04, 0x94, 0xCC, 0xD1, 0x99, 0xE5, 0xC5, 0xBD,
+    0x0D, 0x0E, 0xDC, 0x9E, 0xB8, 0xA0, 0x00, 0x1E,
+    0x15, 0x27, 0x67, 0x54, 0xFC, 0xC6, 0x85, 0x66,
+    0x05, 0x41, 0x48, 0xE6, 0xE7, 0x64, 0xBE, 0xE7,
+    0xC7, 0x64, 0xDA, 0xAD, 0x3F, 0xC4, 0x52, 0x35,
+    0xA6, 0xDA, 0xD4, 0x28, 0xFA, 0x20, 0xC1, 0x70,
+    0xE3, 0x45, 0x00, 0x3F, 0x2F, 0x06, 0xEC, 0x81,
+    0x05, 0xFE, 0xB2, 0x5B, 0x22, 0x81, 0xB6, 0x3D,
+    0x27, 0x33, 0xBE, 0x96, 0x1C, 0x29, 0x95, 0x1D,
+    0x11, 0xDD, 0x22, 0x21, 0x65, 0x7A, 0x9F, 0x53,
+    0x1D, 0xDA, 0x2A, 0x19, 0x4D, 0xBB, 0x12, 0x64,
+    0x48, 0xBD, 0xEE, 0xB2, 0x58, 0xE0, 0x7E, 0xA6,
+    0x59, 0xC7, 0x46, 0x19, 0xA6, 0x38, 0x0E, 0x1D,
+    0x66, 0xD6, 0x83, 0x2B, 0xFE, 0x67, 0xF6, 0x38,
+    0xCD, 0x8F, 0xAE, 0x1F, 0x27, 0x23, 0x02, 0x0F,
+    0x9C, 0x40, 0xA3, 0xFD, 0xA6, 0x7E, 0xDA, 0x3B,
+    0xD2, 0x92, 0x38, 0xFB, 0xD4, 0xD4, 0xB4, 0x88,
+    0x5C, 0x2A, 0x99, 0x17, 0x6D, 0xB1, 0xA0, 0x6C,
+    0x50, 0x07, 0x78, 0x49, 0x1A, 0x82, 0x88, 0xF1,
+    0x85, 0x5F, 0x60, 0xFF, 0xFC, 0xF1, 0xD1, 0x37,
+    0x3F, 0xD9, 0x4F, 0xC6, 0x0C, 0x18, 0x11, 0xE1,
+    0xAC, 0x3F, 0x1C, 0x6D, 0x00, 0x3B, 0xEC, 0xDA,
+    0x3B, 0x1F, 0x27, 0x25, 0xCA, 0x59, 0x5D, 0xE0,
+    0xCA, 0x63, 0x32, 0x8F, 0x3B, 0xE5, 0x7C, 0xC9,
+    0x77, 0x55, 0x60, 0x11, 0x95, 0x14, 0x0D, 0xFB,
+    0x59, 0xD3, 0x9C, 0xE0, 0x91, 0x30, 0x8B, 0x41,
+    0x05, 0x74, 0x6D, 0xAC, 0x23, 0xD3, 0x3E, 0x5F,
+    0x7C, 0xE4, 0x84, 0x8D, 0xA3, 0x16, 0xA9, 0xC6,
+    0x6B, 0x95, 0x81, 0xBA, 0x35, 0x73, 0xBF, 0xAF,
+    0x31, 0x14, 0x96, 0x18, 0x8A, 0xB1, 0x54, 0x23,
+    0x28, 0x2E, 0xE4, 0x16, 0xDC, 0x2A, 0x19, 0xC5,
+    0x72, 0x4F, 0xA9, 0x1A, 0xE4, 0xAD, 0xC8, 0x8B,
+    0xC6, 0x67, 0x96, 0xEA, 0xE5, 0x67, 0x7A, 0x01,
+    0xF6, 0x4E, 0x8C, 0x08, 0x63, 0x13, 0x95, 0x82,
+    0x2D, 0x9D, 0xB8, 0xFC, 0xEE, 0x35, 0xC0, 0x6B,
+    0x1F, 0xEE, 0xA5, 0x47, 0x4D, 0x6D, 0x8F, 0x34,
+    0xB1, 0x53, 0x4A, 0x93, 0x6A, 0x18, 0xB0, 0xE0,
+    0xD2, 0x0E, 0xAB, 0x86, 0xBC, 0x9C, 0x6D, 0x6A,
+    0x52, 0x07, 0x19, 0x4E, 0x67, 0xFA, 0x35, 0x55,
+    0x1B, 0x56, 0x80, 0x26, 0x7B, 0x00, 0x64, 0x1C,
+    0x0F, 0x21, 0x2D, 0x18, 0xEC, 0xA8, 0xD7, 0x32,
+    0x7E, 0xD9, 0x1F, 0xE7, 0x64, 0xA8, 0x4E, 0xA1,
+    0xB4, 0x3F, 0xF5, 0xB4, 0xF6, 0xE8, 0xE6, 0x2F,
+    0x05, 0xC6, 0x61, 0xDE, 0xFB, 0x25, 0x88, 0x77,
+    0xC3, 0x5B, 0x18, 0xA1, 0x51, 0xD5, 0xC4, 0x14,
+    0xAA, 0xAD, 0x97, 0xBA, 0x3E, 0x49, 0x93, 0x32,
+    0xE5, 0x96, 0x07, 0x8E, 0x60, 0x0D, 0xEB, 0x81,
+    0x14, 0x9C, 0x44, 0x1C, 0xE9, 0x57, 0x82, 0xF2,
+    0x2A, 0x28, 0x25, 0x63, 0xC5, 0xBA, 0xC1, 0x41,
+    0x14, 0x23, 0x60, 0x5D, 0x1A, 0xE1, 0xAF, 0xAE,
+    0x2C, 0x8B, 0x06, 0x60, 0x23, 0x7E, 0xC1, 0x28,
+    0xAA, 0x0F, 0xE3, 0x46, 0x4E, 0x43, 0x58, 0x11,
+    0x5D, 0xB8, 0x4C, 0xC3, 0xB5, 0x23, 0x07, 0x3A,
+    0x28, 0xD4, 0x54, 0x98, 0x84, 0xB8, 0x1F, 0xF7,
+    0x0E, 0x10, 0xBF, 0x36, 0x1C, 0x13, 0x72, 0x96,
+    0x28, 0xD5, 0x34, 0x8F, 0x07, 0x21, 0x1E, 0x7E,
+    0x4C, 0xF4, 0xF1, 0x8B, 0x28, 0x60, 0x90, 0xBD,
+    0xB1, 0x24, 0x0B, 0x66, 0xD6, 0xCD, 0x4A, 0xFC,
+    0xEA, 0xDC, 0x00, 0xCA, 0x44, 0x6C, 0xE0, 0x50,
+    0x50, 0xFF, 0x18, 0x3A, 0xD2, 0xBB, 0xF1, 0x18,
+    0xC1, 0xFC, 0x0E, 0xA5, 0x1F, 0x97, 0xD2, 0x2B,
+    0x8F, 0x7E, 0x46, 0x70, 0x5D, 0x45, 0x27, 0xF4,
+    0x5B, 0x42, 0xAE, 0xFF, 0x39, 0x58, 0x53, 0x37,
+    0x6F, 0x69, 0x7D, 0xD5, 0xFD, 0xF2, 0xC5, 0x18,
+    0x7D, 0x7D, 0x5F, 0x0E, 0x2E, 0xB8, 0xD4, 0x3F,
+    0x17, 0xBA, 0x0F, 0x7C, 0x60, 0xFF, 0x43, 0x7F,
+    0x53, 0x5D, 0xFE, 0xF2, 0x98, 0x33, 0xBF, 0x86,
+    0xCB, 0xE8, 0x8E, 0xA4, 0xFB, 0xD4, 0x22, 0x1E,
+    0x84, 0x11, 0x72, 0x83, 0x54, 0xFA, 0x30, 0xA7,
+    0x00, 0x8F, 0x15, 0x4A, 0x41, 0xC7, 0xFC, 0x46,
+    0x6B, 0x46, 0x45, 0xDB, 0xE2, 0xE3, 0x21, 0x26,
+    0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+#endif /* HAVE_FFDHE_Q */
 
 const DhParams* wc_Dh_ffdhe8192_Get(void)
 {
     static const DhParams ffdhe8192 = {
+        #ifdef HAVE_FFDHE_Q
+            dh_ffdhe8192_q, sizeof(dh_ffdhe8192_q),
+        #endif /* HAVE_FFDHE_Q */
         dh_ffdhe8192_p, sizeof(dh_ffdhe8192_p),
         dh_ffdhe8192_g, sizeof(dh_ffdhe8192_g)
@@ -505,5 +931,5 @@
     key->heap = heap; /* for XMALLOC/XFREE in future */
 
-    if (mp_init_multi(&key->p, &key->g, NULL, NULL, NULL, NULL) != MP_OKAY)
+    if (mp_init_multi(&key->p, &key->g, &key->q, NULL, NULL, NULL) != MP_OKAY)
         return MEMORY_E;
 
@@ -525,9 +951,10 @@
 
 
-void wc_FreeDhKey(DhKey* key)
+int wc_FreeDhKey(DhKey* key)
 {
     if (key) {
         mp_clear(&key->p);
         mp_clear(&key->g);
+        mp_clear(&key->q);
 
     #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_DH)
@@ -535,7 +962,9 @@
     #endif
     }
-}
-
-
+    return 0;
+}
+
+
+#ifndef WC_NO_RNG
 /* if defined to not use floating point values do not compile in */
 #ifndef WOLFSSL_DH_CONST
@@ -568,11 +997,187 @@
 
 
-static int GeneratePrivateDh(DhKey* key, WC_RNG* rng, byte* priv, word32* privSz)
-{
+#ifndef WOLFSSL_NO_DH186
+/* validate that (L,N) match allowed sizes from SP 800-56A, Section 5.5.1.1.
+ * modLen - represents L, the size of p in bits
+ * divLen - represents N, the size of q in bits
+ * return 0 on success, -1 on error */
+static int CheckDhLN(int modLen, int divLen)
+{
+    int ret = -1;
+
+    switch (modLen) {
+        /* FA */
+        case 1024:
+            if (divLen == 160)
+                ret = 0;
+            break;
+        /* FB, FC */
+        case 2048:
+            if (divLen == 224 || divLen == 256)
+                ret = 0;
+            break;
+        default:
+            break;
+    }
+
+    return ret;
+}
+
+
+/* Create DH private key
+ *
+ * Based on NIST FIPS 186-4,
+ * "B.1.1 Key Pair Generation Using Extra Random Bits"
+ *
+ * dh     - pointer to initialized DhKey structure, needs to have dh->q
+ * rng    - pointer to initialized WC_RNG structure
+ * priv   - output location for generated private key
+ * privSz - IN/OUT, size of priv buffer, size of generated private key
+ *
+ * return 0 on success, negative on error */
+static int GeneratePrivateDh186(DhKey* key, WC_RNG* rng, byte* priv,
+                                word32* privSz)
+{
+    byte* cBuf;
+    int qSz, pSz, cSz, err;
+#ifdef WOLFSSL_SMALL_STACK
+    mp_int* tmpQ = NULL;
+    mp_int* tmpX = NULL;
+#else
+    mp_int tmpQ[1], tmpX[1];
+#endif
+
+    /* Parameters validated in calling functions. */
+
+    if (mp_iszero(&key->q) == MP_YES) {
+        WOLFSSL_MSG("DH q parameter needed for FIPS 186-4 key generation");
+        return BAD_FUNC_ARG;
+    }
+
+    qSz = mp_unsigned_bin_size(&key->q);
+    pSz = mp_unsigned_bin_size(&key->p);
+
+    /* verify (L,N) pair bit lengths */
+    if (CheckDhLN(pSz * WOLFSSL_BIT_SIZE, qSz * WOLFSSL_BIT_SIZE) != 0) {
+        WOLFSSL_MSG("DH param sizes do not match SP 800-56A requirements");
+        return BAD_FUNC_ARG;
+    }
+
+    /* generate extra 64 bits so that bias from mod function is negligible */
+    cSz = qSz + (64 / WOLFSSL_BIT_SIZE);
+    cBuf = (byte*)XMALLOC(cSz, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (cBuf == NULL) {
+        return MEMORY_E;
+    }
+#ifdef WOLFSSL_SMALL_STACK
+    tmpQ = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
+    if (tmpQ == NULL) {
+        XFREE(cBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+    tmpX = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
+    if (tmpX == NULL) {
+        XFREE(cBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(tmpQ, key->heap, DYNAMIC_TYPE_DH);
+        return MEMORY_E;
+    }
+#endif
+
+
+    if ((err = mp_init_multi(tmpX, tmpQ, NULL, NULL, NULL, NULL))
+                   != MP_OKAY) {
+        XFREE(cBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(tmpQ, key->heap, DYNAMIC_TYPE_DH);
+        XFREE(tmpX, key->heap, DYNAMIC_TYPE_DH);
+#endif
+        return err;
+    }
+
+    do {
+        /* generate N+64 bits (c) from RBG into tmpX, making sure positive.
+         * Hash_DRBG uses SHA-256 which matches maximum
+         * requested_security_strength of (L,N) */
+        err = wc_RNG_GenerateBlock(rng, cBuf, cSz);
+        if (err == MP_OKAY)
+            err = mp_read_unsigned_bin(tmpX, cBuf, cSz);
+        if (err != MP_OKAY) {
+            mp_clear(tmpX);
+            mp_clear(tmpQ);
+            XFREE(cBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(tmpQ, key->heap, DYNAMIC_TYPE_DH);
+            XFREE(tmpX, key->heap, DYNAMIC_TYPE_DH);
+#endif
+            return err;
+        }
+    } while (mp_cmp_d(tmpX, 1) != MP_GT);
+
+    ForceZero(cBuf, cSz);
+    XFREE(cBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+
+    /* tmpQ = q - 1 */
+    if (err == MP_OKAY)
+        err = mp_copy(&key->q, tmpQ);
+
+    if (err == MP_OKAY)
+        err = mp_sub_d(tmpQ, 1, tmpQ);
+
+    /* x = c mod (q-1), tmpX holds c */
+    if (err == MP_OKAY)
+        err = mp_mod(tmpX, tmpQ, tmpX);
+
+    /* x = c mod (q-1) + 1 */
+    if (err == MP_OKAY)
+        err = mp_add_d(tmpX, 1, tmpX);
+
+    /* copy tmpX into priv */
+    if (err == MP_OKAY) {
+        pSz = mp_unsigned_bin_size(tmpX);
+        if (pSz > (int)*privSz) {
+            WOLFSSL_MSG("DH private key output buffer too small");
+            err = BAD_FUNC_ARG;
+        } else {
+            *privSz = pSz;
+            err = mp_to_unsigned_bin(tmpX, priv);
+        }
+    }
+
+    mp_forcezero(tmpX);
+    mp_clear(tmpX);
+    mp_clear(tmpQ);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(tmpQ, key->heap, DYNAMIC_TYPE_DH);
+    XFREE(tmpX, key->heap, DYNAMIC_TYPE_DH);
+#endif
+
+    return err;
+}
+#endif /* WOLFSSL_NO_DH186 */
+#endif /* !WC_NO_RNG */
+
+static int GeneratePrivateDh(DhKey* key, WC_RNG* rng, byte* priv,
+                             word32* privSz)
+{
+#ifndef WC_NO_RNG
     int ret = 0;
-    word32 sz = mp_unsigned_bin_size(&key->p);
+    word32 sz = 0;
+
+#ifndef WOLFSSL_NO_DH186
+    if (mp_iszero(&key->q) == MP_NO) {
+
+        /* q param available, use NIST FIPS 186-4, "B.1.1 Key Pair
+         * Generation Using Extra Random Bits" */
+        ret = GeneratePrivateDh186(key, rng, priv, privSz);
+
+    } else
+#endif
+    {
+
+        sz = mp_unsigned_bin_size(&key->p);
 
     /* Table of predetermined values from the operation
-       2 * DiscreteLogWorkFactor(sz * WOLFSSL_BIT_SIZE) / WOLFSSL_BIT_SIZE + 1
+           2 * DiscreteLogWorkFactor(sz * WOLFSSL_BIT_SIZE) /
+           WOLFSSL_BIT_SIZE + 1
        Sizes in table checked against RFC 3526
      */
@@ -604,6 +1209,14 @@
         *privSz = sz;
     }
+    }
 
     return ret;
+#else
+    (void)key;
+    (void)rng;
+    (void)priv;
+    (void)privSz;
+    return NOT_COMPILED_IN;
+#endif /* WC_NO_RNG */
 }
 
@@ -613,6 +1226,13 @@
 {
     int ret = 0;
-    mp_int x;
-    mp_int y;
+#ifndef WOLFSSL_SP_MATH
+#ifdef WOLFSSL_SMALL_STACK
+    mp_int* x = NULL;
+    mp_int* y = NULL;
+#else
+    mp_int x[1];
+    mp_int y[1];
+#endif
+#endif
 
 #ifdef WOLFSSL_HAVE_SP_DH
@@ -627,21 +1247,44 @@
 #endif
 
-    if (mp_init_multi(&x, &y, 0, 0, 0, 0) != MP_OKAY)
+#ifndef WOLFSSL_SP_MATH
+#ifdef WOLFSSL_SMALL_STACK
+    x = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
+    if (x == NULL)
+        return MEMORY_E;
+    y = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
+    if (y == NULL) {
+        XFREE(x, key->heap, DYNAMIC_TYPE_DH);
+        return MEMORY_E;
+    }
+#endif
+    if (mp_init_multi(x, y, 0, 0, 0, 0) != MP_OKAY) {
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(y, key->heap, DYNAMIC_TYPE_DH);
+        XFREE(x, key->heap, DYNAMIC_TYPE_DH);
+    #endif
         return MP_INIT_E;
-
-    if (mp_read_unsigned_bin(&x, priv, privSz) != MP_OKAY)
+    }
+
+    if (mp_read_unsigned_bin(x, priv, privSz) != MP_OKAY)
         ret = MP_READ_E;
 
-    if (ret == 0 && mp_exptmod(&key->g, &x, &key->p, &y) != MP_OKAY)
+    if (ret == 0 && mp_exptmod(&key->g, x, &key->p, y) != MP_OKAY)
         ret = MP_EXPTMOD_E;
 
-    if (ret == 0 && mp_to_unsigned_bin(&y, pub) != MP_OKAY)
+    if (ret == 0 && mp_to_unsigned_bin(y, pub) != MP_OKAY)
         ret = MP_TO_E;
 
     if (ret == 0)
-        *pubSz = mp_unsigned_bin_size(&y);
-
-    mp_clear(&y);
-    mp_clear(&x);
+        *pubSz = mp_unsigned_bin_size(y);
+
+    mp_clear(y);
+    mp_clear(x);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(y, key->heap, DYNAMIC_TYPE_DH);
+    XFREE(x, key->heap, DYNAMIC_TYPE_DH);
+#endif
+#else
+    ret = WC_KEY_SIZE_E;
+#endif
 
     return ret;
@@ -723,4 +1366,147 @@
 
 
+/* Check DH Public Key for invalid numbers, optionally allowing
+ * the public key to be checked against the large prime (q).
+ * Check per process in SP 800-56Ar3, section 5.6.2.3.1.
+ *
+ * key     DH key group parameters.
+ * pub     Public Key.
+ * pubSz   Public Key size.
+ * prime   Large prime (q), optionally NULL to skip check
+ * primeSz Size of large prime
+ *
+ *  returns 0 on success or error code
+ */
+int wc_DhCheckPubKey_ex(DhKey* key, const byte* pub, word32 pubSz,
+                        const byte* prime, word32 primeSz)
+{
+    int ret = 0;
+#ifdef WOLFSSL_SMALL_STACK
+    mp_int* y = NULL;
+    mp_int* p = NULL;
+    mp_int* q = NULL;
+#else
+    mp_int y[1];
+    mp_int p[1];
+    mp_int q[1];
+#endif
+
+    if (key == NULL || pub == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    y = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
+    if (y == NULL)
+        return MEMORY_E;
+    p = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
+    if (p == NULL) {
+        XFREE(y, key->heap, DYNAMIC_TYPE_DH);
+        return MEMORY_E;
+    }
+    q = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
+    if (q == NULL) {
+        XFREE(p, key->heap, DYNAMIC_TYPE_DH);
+        XFREE(y, key->heap, DYNAMIC_TYPE_DH);
+        return MEMORY_E;
+    }
+#endif
+
+    if (mp_init_multi(y, p, q, NULL, NULL, NULL) != MP_OKAY) {
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(q, key->heap, DYNAMIC_TYPE_DH);
+        XFREE(p, key->heap, DYNAMIC_TYPE_DH);
+        XFREE(y, key->heap, DYNAMIC_TYPE_DH);
+    #endif
+        return MP_INIT_E;
+    }
+
+    if (mp_read_unsigned_bin(y, pub, pubSz) != MP_OKAY) {
+        ret = MP_READ_E;
+    }
+
+    if (ret == 0 && prime != NULL) {
+        if (mp_read_unsigned_bin(q, prime, primeSz) != MP_OKAY)
+            ret = MP_READ_E;
+
+    } else if (mp_iszero(&key->q) == MP_NO) {
+        /* use q available in DhKey */
+        if (mp_copy(&key->q, q) != MP_OKAY)
+            ret = MP_INIT_E;
+    }
+
+    /* SP 800-56Ar3, section 5.6.2.3.1, process step 1 */
+    /* pub (y) should not be 0 or 1 */
+    if (ret == 0 && mp_cmp_d(y, 2) == MP_LT) {
+        ret = MP_CMP_E;
+    }
+
+    /* pub (y) shouldn't be greater than or equal to p - 1 */
+    if (ret == 0 && mp_copy(&key->p, p) != MP_OKAY) {
+        ret = MP_INIT_E;
+    }
+    if (ret == 0 && mp_sub_d(p, 2, p) != MP_OKAY) {
+        ret = MP_SUB_E;
+    }
+    if (ret == 0 && mp_cmp(y, p) == MP_GT) {
+        ret = MP_CMP_E;
+    }
+
+    if (ret == 0 && (prime != NULL || (mp_iszero(&key->q) == MP_NO) )) {
+
+        /* restore key->p into p */
+        if (mp_copy(&key->p, p) != MP_OKAY)
+            ret = MP_INIT_E;
+    }
+
+    if (ret == 0 && prime != NULL) {
+#ifdef WOLFSSL_HAVE_SP_DH
+#ifndef WOLFSSL_SP_NO_2048
+        if (mp_count_bits(&key->p) == 2048) {
+            ret = sp_ModExp_2048(y, q, p, y);
+            if (ret != 0)
+                ret = MP_EXPTMOD_E;
+        }
+        else
+#endif
+#ifndef WOLFSSL_SP_NO_3072
+        if (mp_count_bits(&key->p) == 3072) {
+            ret = sp_ModExp_3072(y, q, p, y);
+            if (ret != 0)
+                ret = MP_EXPTMOD_E;
+        }
+        else
+#endif
+#endif
+
+        {
+    /* SP 800-56Ar3, section 5.6.2.3.1, process step 2 */
+#ifndef WOLFSSL_SP_MATH
+            /* calculate (y^q) mod(p), store back into y */
+            if (ret == 0 && mp_exptmod(y, q, p, y) != MP_OKAY)
+                ret = MP_EXPTMOD_E;
+#else
+            ret = WC_KEY_SIZE_E;
+#endif
+        }
+
+        /* verify above == 1 */
+        if (ret == 0 && mp_cmp_d(y, 1) != MP_EQ)
+            ret = MP_CMP_E;
+    }
+
+    mp_clear(y);
+    mp_clear(p);
+    mp_clear(q);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(q, key->heap, DYNAMIC_TYPE_DH);
+    XFREE(p, key->heap, DYNAMIC_TYPE_DH);
+    XFREE(y, key->heap, DYNAMIC_TYPE_DH);
+#endif
+
+    return ret;
+}
+
+
 /* Check DH Public Key for invalid numbers
  *
@@ -733,39 +1519,228 @@
 int wc_DhCheckPubKey(DhKey* key, const byte* pub, word32 pubSz)
 {
+    return wc_DhCheckPubKey_ex(key, pub, pubSz, NULL, 0);
+}
+
+
+/* Check DH Private Key for invalid numbers, optionally allowing
+ * the private key to be checked against the large prime (q).
+ * Check per process in SP 800-56Ar3, section 5.6.2.1.2.
+ *
+ * key     DH key group parameters.
+ * priv    Private Key.
+ * privSz  Private Key size.
+ * prime   Large prime (q), optionally NULL to skip check
+ * primeSz Size of large prime
+ *
+ *  returns 0 on success or error code
+ */
+int wc_DhCheckPrivKey_ex(DhKey* key, const byte* priv, word32 privSz,
+                         const byte* prime, word32 primeSz)
+{
     int ret = 0;
-
-    mp_int x;
-    mp_int y;
-
-    if (key == NULL || pub == NULL) {
+#ifdef WOLFSSL_SMALL_STACK
+    mp_int* x = NULL;
+    mp_int* q = NULL;
+#else
+    mp_int x[1];
+    mp_int q[1];
+#endif
+
+    if (key == NULL || priv == NULL) {
         return BAD_FUNC_ARG;
     }
 
-    if (mp_init_multi(&x, &y, NULL, NULL, NULL, NULL) != MP_OKAY) {
+#ifdef WOLFSSL_SMALL_STACK
+    x = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
+    if (x == NULL)
+        return MEMORY_E;
+    q = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
+    if (q == NULL) {
+        XFREE(x, key->heap, DYNAMIC_TYPE_DH);
+        return MEMORY_E;
+    }
+#endif
+
+    if (mp_init_multi(x, q, NULL, NULL, NULL, NULL) != MP_OKAY) {
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(q, key->heap, DYNAMIC_TYPE_DH);
+        XFREE(x, key->heap, DYNAMIC_TYPE_DH);
+    #endif
         return MP_INIT_E;
     }
 
-    if (mp_read_unsigned_bin(&x, pub, pubSz) != MP_OKAY) {
+    if (mp_read_unsigned_bin(x, priv, privSz) != MP_OKAY) {
         ret = MP_READ_E;
     }
 
-    /* pub should not be 0 or 1 */
-    if (ret == 0 && mp_cmp_d(&x, 2) == MP_LT) {
+    if (ret == 0) {
+        if (prime != NULL) {
+            if (mp_read_unsigned_bin(q, prime, primeSz) != MP_OKAY)
+                ret = MP_READ_E;
+        }
+        else if (mp_iszero(&key->q) == MP_NO) {
+            /* use q available in DhKey */
+            if (mp_copy(&key->q, q) != MP_OKAY)
+                ret = MP_INIT_E;
+        }
+    }
+
+    /* priv (x) should not be 0 */
+    if (ret == 0) {
+        if (mp_cmp_d(x, 0) == MP_EQ)
         ret = MP_CMP_E;
     }
 
-    /* pub shouldn't be greater than or equal to p - 1 */
-    if (ret == 0 && mp_copy(&key->p, &y) != MP_OKAY) {
+    if (ret == 0) {
+        if (mp_iszero(q) == MP_NO) {
+            /* priv (x) shouldn't be greater than q - 1 */
+            if (ret == 0) {
+                if (mp_copy(&key->q, q) != MP_OKAY)
         ret = MP_INIT_E;
     }
-    if (ret == 0 && mp_sub_d(&y, 2, &y) != MP_OKAY) {
+            if (ret == 0) {
+                if (mp_sub_d(q, 1, q) != MP_OKAY)
         ret = MP_SUB_E;
     }
-    if (ret == 0 && mp_cmp(&x, &y) == MP_GT) {
+            if (ret == 0) {
+                if (mp_cmp(x, q) == MP_GT)
+                    ret = DH_CHECK_PRIV_E;
+            }
+        }
+    }
+
+    mp_clear(x);
+    mp_clear(q);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(q, key->heap, DYNAMIC_TYPE_DH);
+    XFREE(x, key->heap, DYNAMIC_TYPE_DH);
+#endif
+
+    return ret;
+}
+
+
+/* Check DH Private Key for invalid numbers
+ *
+ * key    DH key group parameters.
+ * priv   Private Key.
+ * privSz Private Key size.
+ *
+ *  returns 0 on success or error code
+ */
+int wc_DhCheckPrivKey(DhKey* key, const byte* priv, word32 privSz)
+{
+    return wc_DhCheckPrivKey_ex(key, priv, privSz, NULL, 0);
+}
+
+
+/* Check DH Keys for pair-wise consistency per process in
+ * SP 800-56Ar3, section 5.6.2.1.4, method (b) for FFC.
+ *
+ * key    DH key group parameters.
+ * pub    Public Key.
+ * pubSz  Public Key size.
+ * priv   Private Key.
+ * privSz Private Key size.
+ *
+ *  returns 0 on success or error code
+ */
+int wc_DhCheckKeyPair(DhKey* key, const byte* pub, word32 pubSz,
+                      const byte* priv, word32 privSz)
+{
+#ifdef WOLFSSL_SMALL_STACK
+    mp_int* publicKey = NULL;
+    mp_int* privateKey = NULL;
+    mp_int* checkKey = NULL;
+#else
+    mp_int publicKey[1];
+    mp_int privateKey[1];
+    mp_int checkKey[1];
+#endif
+    int ret = 0;
+
+    if (key == NULL || pub == NULL || priv == NULL)
+        return BAD_FUNC_ARG;
+
+#ifdef WOLFSSL_SMALL_STACK
+    publicKey = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
+    if (publicKey == NULL)
+        return MEMORY_E;
+    privateKey = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
+    if (privateKey == NULL) {
+        XFREE(publicKey, key->heap, DYNAMIC_TYPE_DH);
+        return MEMORY_E;
+    }
+    checkKey = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
+    if (checkKey == NULL) {
+        XFREE(privateKey, key->heap, DYNAMIC_TYPE_DH);
+        XFREE(publicKey, key->heap, DYNAMIC_TYPE_DH);
+        return MEMORY_E;
+    }
+#endif
+
+    if (mp_init_multi(publicKey, privateKey, checkKey,
+                      NULL, NULL, NULL) != MP_OKAY) {
+
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(privateKey, key->heap, DYNAMIC_TYPE_DH);
+        XFREE(publicKey, key->heap, DYNAMIC_TYPE_DH);
+        XFREE(checkKey, key->heap, DYNAMIC_TYPE_DH);
+    #endif
+        return MP_INIT_E;
+    }
+
+    /* Load the private and public keys into big integers. */
+    if (mp_read_unsigned_bin(publicKey, pub, pubSz) != MP_OKAY ||
+        mp_read_unsigned_bin(privateKey, priv, privSz) != MP_OKAY) {
+
+        ret = MP_READ_E;
+    }
+
+    /* Calculate checkKey = g^privateKey mod p */
+    if (ret == 0) {
+#ifdef WOLFSSL_HAVE_SP_DH
+#ifndef WOLFSSL_SP_NO_2048
+        if (mp_count_bits(&key->p) == 2048) {
+            ret = sp_ModExp_2048(&key->g, privateKey, &key->p, checkKey);
+            if (ret != 0)
+                ret = MP_EXPTMOD_E;
+        }
+        else
+#endif
+#ifndef WOLFSSL_SP_NO_3072
+        if (mp_count_bits(&key->p) == 3072) {
+            ret = sp_ModExp_3072(&key->g, privateKey, &key->p, checkKey);
+            if (ret != 0)
+                ret = MP_EXPTMOD_E;
+        }
+        else
+#endif
+#endif
+        {
+#ifndef WOLFSSL_SP_MATH
+            if (mp_exptmod(&key->g, privateKey, &key->p, checkKey) != MP_OKAY)
+                ret = MP_EXPTMOD_E;
+#else
+            ret = WC_KEY_SIZE_E;
+#endif
+        }
+    }
+
+    /* Compare the calculated public key to the supplied check value. */
+    if (ret == 0) {
+        if (mp_cmp(checkKey, publicKey) != MP_EQ)
         ret = MP_CMP_E;
     }
 
-    mp_clear(&y);
-    mp_clear(&x);
+    mp_forcezero(privateKey);
+    mp_clear(privateKey);
+    mp_clear(publicKey);
+    mp_clear(checkKey);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(checkKey, key->heap, DYNAMIC_TYPE_DH);
+    XFREE(privateKey, key->heap, DYNAMIC_TYPE_DH);
+    XFREE(publicKey, key->heap, DYNAMIC_TYPE_DH);
+#endif
 
     return ret;
@@ -801,7 +1776,23 @@
 {
     int ret = 0;
-    mp_int x;
-    mp_int y;
-    mp_int z;
+#ifdef WOLFSSL_SMALL_STACK
+    mp_int* y = NULL;
+#ifndef WOLFSSL_SP_MATH
+    mp_int* x = NULL;
+    mp_int* z = NULL;
+#endif
+#else
+    mp_int y[1];
+#ifndef WOLFSSL_SP_MATH
+    mp_int x[1];
+    mp_int z[1];
+#endif
+#endif
+
+#ifdef WOLFSSL_VALIDATE_FFC_IMPORT
+    if (wc_DhCheckPrivKey(key, priv, privSz) != 0) {
+        WOLFSSL_MSG("wc_DhAgree wc_DhCheckPrivKey failed");
+        return DH_CHECK_PRIV_E;
+    }
 
     if (wc_DhCheckPubKey(key, otherPub, pubSz) != 0) {
@@ -809,18 +1800,45 @@
         return DH_CHECK_PUB_E;
     }
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+    y = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
+    if (y == NULL)
+        return MEMORY_E;
+#ifndef WOLFSSL_SP_MATH
+    x = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
+    if (x == NULL) {
+        XFREE(y, key->heap, DYNAMIC_TYPE_DH);
+        return MEMORY_E;
+    }
+    z = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
+    if (z == NULL) {
+        XFREE(x, key->heap, DYNAMIC_TYPE_DH);
+        XFREE(y, key->heap, DYNAMIC_TYPE_DH);
+        return MEMORY_E;
+    }
+#endif
+#endif
 
 #ifdef WOLFSSL_HAVE_SP_DH
 #ifndef WOLFSSL_SP_NO_2048
     if (mp_count_bits(&key->p) == 2048) {
-        if (mp_init(&y) != MP_OKAY)
+        if (mp_init(y) != MP_OKAY)
             return MP_INIT_E;
 
-        if (ret == 0 && mp_read_unsigned_bin(&y, otherPub, pubSz) != MP_OKAY)
+        if (ret == 0 && mp_read_unsigned_bin(y, otherPub, pubSz) != MP_OKAY)
             ret = MP_READ_E;
 
         if (ret == 0)
-            ret = sp_DhExp_2048(&y, priv, privSz, &key->p, agree, agreeSz);
-
-        mp_clear(&y);
+            ret = sp_DhExp_2048(y, priv, privSz, &key->p, agree, agreeSz);
+
+        mp_clear(y);
+    #ifdef WOLFSSL_SMALL_STACK
+    #ifndef WOLFSSL_SP_MATH
+        XFREE(z, key->heap, DYNAMIC_TYPE_DH);
+        XFREE(x, key->heap, DYNAMIC_TYPE_DH);
+    #endif
+        XFREE(y, key->heap, DYNAMIC_TYPE_DH);
+    #endif
         return ret;
     }
@@ -828,14 +1846,21 @@
 #ifndef WOLFSSL_SP_NO_3072
     if (mp_count_bits(&key->p) == 3072) {
-        if (mp_init(&y) != MP_OKAY)
+        if (mp_init(y) != MP_OKAY)
             return MP_INIT_E;
 
-        if (ret == 0 && mp_read_unsigned_bin(&y, otherPub, pubSz) != MP_OKAY)
+        if (ret == 0 && mp_read_unsigned_bin(y, otherPub, pubSz) != MP_OKAY)
             ret = MP_READ_E;
 
         if (ret == 0)
-            ret = sp_DhExp_3072(&y, priv, privSz, &key->p, agree, agreeSz);
-
-        mp_clear(&y);
+            ret = sp_DhExp_3072(y, priv, privSz, &key->p, agree, agreeSz);
+
+        mp_clear(y);
+    #ifdef WOLFSSL_SMALL_STACK
+    #ifndef WOLFSSL_SP_MATH
+        XFREE(z, key->heap, DYNAMIC_TYPE_DH);
+        XFREE(x, key->heap, DYNAMIC_TYPE_DH);
+    #endif
+        XFREE(y, key->heap, DYNAMIC_TYPE_DH);
+    #endif
         return ret;
     }
@@ -843,25 +1868,45 @@
 #endif
 
-    if (mp_init_multi(&x, &y, &z, 0, 0, 0) != MP_OKAY)
+#ifndef WOLFSSL_SP_MATH
+    if (mp_init_multi(x, y, z, 0, 0, 0) != MP_OKAY) {
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(z, key->heap, DYNAMIC_TYPE_DH);
+        XFREE(x, key->heap, DYNAMIC_TYPE_DH);
+        XFREE(y, key->heap, DYNAMIC_TYPE_DH);
+    #endif
         return MP_INIT_E;
-
-    if (mp_read_unsigned_bin(&x, priv, privSz) != MP_OKAY)
+    }
+
+    if (mp_read_unsigned_bin(x, priv, privSz) != MP_OKAY)
         ret = MP_READ_E;
 
-    if (ret == 0 && mp_read_unsigned_bin(&y, otherPub, pubSz) != MP_OKAY)
+    if (ret == 0 && mp_read_unsigned_bin(y, otherPub, pubSz) != MP_OKAY)
         ret = MP_READ_E;
 
-    if (ret == 0 && mp_exptmod(&y, &x, &key->p, &z) != MP_OKAY)
+    if (ret == 0 && mp_exptmod(y, x, &key->p, z) != MP_OKAY)
         ret = MP_EXPTMOD_E;
 
-    if (ret == 0 && mp_to_unsigned_bin(&z, agree) != MP_OKAY)
+    /* make sure z is not one (SP800-56A, 5.7.1.1) */
+    if (ret == 0 && (mp_cmp_d(z, 1) == MP_EQ))
+        ret = MP_VAL;
+
+    if (ret == 0 && mp_to_unsigned_bin(z, agree) != MP_OKAY)
         ret = MP_TO_E;
 
     if (ret == 0)
-        *agreeSz = mp_unsigned_bin_size(&z);
-
-    mp_clear(&z);
-    mp_clear(&y);
-    mp_forcezero(&x);
+        *agreeSz = mp_unsigned_bin_size(z);
+
+    mp_clear(z);
+    mp_clear(y);
+    mp_forcezero(x);
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+#ifndef WOLFSSL_SP_MATH
+    XFREE(z, key->heap, DYNAMIC_TYPE_DH);
+    XFREE(x, key->heap, DYNAMIC_TYPE_DH);
+#endif
+    XFREE(y, key->heap, DYNAMIC_TYPE_DH);
+#endif
 
     return ret;
@@ -926,40 +1971,359 @@
 
 
+static int _DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g,
+                   word32 gSz, const byte* q, word32 qSz, int trusted,
+                   WC_RNG* rng)
+{
+    int ret = 0;
+    mp_int* keyP = NULL;
+    mp_int* keyG = NULL;
+    mp_int* keyQ = NULL;
+
+    if (key == NULL || p == NULL || g == NULL || pSz == 0 || gSz == 0) {
+        ret = BAD_FUNC_ARG;
+    }
+
+    if (ret == 0) {
+    /* may have leading 0 */
+    if (p[0] == 0) {
+        pSz--; p++;
+    }
+
+    if (g[0] == 0) {
+        gSz--; g++;
+    }
+
+        if (q != NULL) {
+            if (q[0] == 0) {
+                qSz--; q++;
+            }
+        }
+
+    if (mp_init(&key->p) != MP_OKAY)
+            ret = MP_INIT_E;
+    }
+
+    if (ret == 0) {
+        if (mp_read_unsigned_bin(&key->p, p, pSz) != MP_OKAY)
+            ret = ASN_DH_KEY_E;
+        else
+            keyP = &key->p;
+    }
+
+#ifndef WOLFSSL_SP_MATH
+    if (ret == 0 && !trusted) {
+        int isPrime = 0;
+        if (rng != NULL)
+            ret = mp_prime_is_prime_ex(keyP, 8, &isPrime, rng);
+        else
+            ret = mp_prime_is_prime(keyP, 8, &isPrime);
+
+        if (ret == 0 && isPrime == 0)
+            ret = DH_CHECK_PUB_E;
+    }
+#else
+    (void)trusted;
+    (void)rng;
+#endif
+
+    if (ret == 0 && mp_init(&key->g) != MP_OKAY)
+        ret = MP_INIT_E;
+    if (ret == 0) {
+        if (mp_read_unsigned_bin(&key->g, g, gSz) != MP_OKAY)
+            ret = ASN_DH_KEY_E;
+        else
+            keyG = &key->g;
+    }
+
+    if (ret == 0 && q != NULL) {
+        if (mp_init(&key->q) != MP_OKAY)
+            ret = MP_INIT_E;
+    }
+    if (ret == 0 && q != NULL) {
+        if (mp_read_unsigned_bin(&key->q, q, qSz) != MP_OKAY)
+            ret = MP_INIT_E;
+        else
+            keyQ = &key->q;
+}
+
+    if (ret != 0 && key != NULL) {
+        if (keyQ)
+            mp_clear(keyQ);
+        if (keyG)
+            mp_clear(keyG);
+        if (keyP)
+            mp_clear(keyP);
+    }
+
+    return ret;
+}
+
+
+int wc_DhSetCheckKey(DhKey* key, const byte* p, word32 pSz, const byte* g,
+                   word32 gSz, const byte* q, word32 qSz, int trusted,
+                   WC_RNG* rng)
+{
+    return _DhSetKey(key, p, pSz, g, gSz, q, qSz, trusted, rng);
+}
+
+
+int wc_DhSetKey_ex(DhKey* key, const byte* p, word32 pSz, const byte* g,
+                   word32 gSz, const byte* q, word32 qSz)
+{
+    return _DhSetKey(key, p, pSz, g, gSz, q, qSz, 1, NULL);
+}
+
+
 /* not in asn anymore since no actual asn types used */
 int wc_DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g,
                 word32 gSz)
 {
-    if (key == NULL || p == NULL || g == NULL || pSz == 0 || gSz == 0) {
-        return BAD_FUNC_ARG;
-    }
-
-    /* may have leading 0 */
-    if (p[0] == 0) {
-        pSz--; p++;
-    }
-
-    if (g[0] == 0) {
-        gSz--; g++;
-    }
-
-    if (mp_init(&key->p) != MP_OKAY)
-        return MP_INIT_E;
-    if (mp_read_unsigned_bin(&key->p, p, pSz) != 0) {
-        mp_clear(&key->p);
-        return ASN_DH_KEY_E;
-    }
-
-    if (mp_init(&key->g) != MP_OKAY) {
-        mp_clear(&key->p);
-        return MP_INIT_E;
-    }
-    if (mp_read_unsigned_bin(&key->g, g, gSz) != 0) {
-        mp_clear(&key->g);
-        mp_clear(&key->p);
-        return ASN_DH_KEY_E;
-    }
-
-    return 0;
-}
+    return _DhSetKey(key, p, pSz, g, gSz, NULL, 0, 1, NULL);
+}
+
+
+#ifdef WOLFSSL_KEY_GEN
+
+/* modulus_size in bits */
+int wc_DhGenerateParams(WC_RNG *rng, int modSz, DhKey *dh)
+{
+    mp_int  tmp, tmp2;
+    int     groupSz = 0, bufSz = 0,
+            primeCheckCount = 0,
+            primeCheck = MP_NO,
+            ret = 0;
+    unsigned char *buf = NULL;
+
+    if (rng == NULL || dh == NULL)
+        ret = BAD_FUNC_ARG;
+
+    /* set group size in bytes from modulus size
+     * FIPS 186-4 defines valid values (1024, 160) (2048, 256) (3072, 256)
+     */
+    if (ret == 0) {
+        switch (modSz) {
+            case 1024:
+                groupSz = 20;
+                break;
+            case 2048:
+            case 3072:
+                groupSz = 32;
+                break;
+            default:
+                ret = BAD_FUNC_ARG;
+                break;
+        }
+    }
+
+    if (ret == 0) {
+        /* modulus size in bytes */
+        modSz /= WOLFSSL_BIT_SIZE;
+        bufSz = modSz - groupSz;
+
+        /* allocate ram */
+        buf = (unsigned char *)XMALLOC(bufSz,
+                                       dh->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        if (buf == NULL)
+            ret = MEMORY_E;
+    }
+
+    /* make a random string that will be multplied against q */
+    if (ret == 0)
+        ret = wc_RNG_GenerateBlock(rng, buf, bufSz);
+
+    if (ret == 0) {
+        /* force magnitude */
+        buf[0] |= 0xC0;
+        /* force even */
+        buf[bufSz - 1] &= ~1;
+
+        if (mp_init_multi(&tmp, &tmp2, &dh->p, &dh->q, &dh->g, 0)
+                != MP_OKAY) {
+            ret = MP_INIT_E;
+        }
+    }
+
+    if (ret == 0) {
+        if (mp_read_unsigned_bin(&tmp2, buf, bufSz) != MP_OKAY)
+            ret = MP_READ_E;
+    }
+
+    /* make our prime q */
+    if (ret == 0) {
+        if (mp_rand_prime(&dh->q, groupSz, rng, NULL) != MP_OKAY)
+            ret = PRIME_GEN_E;
+    }
+
+    /* p = random * q */
+    if (ret == 0) {
+        if (mp_mul(&dh->q, &tmp2, &dh->p) != MP_OKAY)
+            ret = MP_MUL_E;
+    }
+
+    /* p = random * q + 1, so q is a prime divisor of p-1 */
+    if (ret == 0) {
+        if (mp_add_d(&dh->p, 1, &dh->p) != MP_OKAY)
+            ret = MP_ADD_E;
+    }
+
+    /* tmp = 2q  */
+    if (ret == 0) {
+        if (mp_add(&dh->q, &dh->q, &tmp) != MP_OKAY)
+            ret = MP_ADD_E;
+    }
+
+    /* loop until p is prime */
+    if (ret == 0) {
+        do {
+            if (mp_prime_is_prime_ex(&dh->p, 8, &primeCheck, rng) != MP_OKAY)
+                ret = PRIME_GEN_E;
+
+            if (primeCheck != MP_YES) {
+                /* p += 2q */
+                if (mp_add(&tmp, &dh->p, &dh->p) != MP_OKAY)
+                    ret = MP_ADD_E;
+                else
+                    primeCheckCount++;
+            }
+        } while (ret == 0 && primeCheck == MP_NO);
+    }
+
+    /* tmp2 += (2*loop_check_prime)
+     * to have p = (q * tmp2) + 1 prime
+     */
+    if (primeCheckCount) {
+        if (mp_add_d(&tmp2, 2 * primeCheckCount, &tmp2) != MP_OKAY)
+            ret = MP_ADD_E;
+    }
+
+    /* find a value g for which g^tmp2 != 1 */
+    if (mp_set(&dh->g, 1) != MP_OKAY)
+        ret = MP_ZERO_E;
+
+    if (ret == 0) {
+        do {
+            if (mp_add_d(&dh->g, 1, &dh->g) != MP_OKAY)
+                ret = MP_ADD_E;
+            else if (mp_exptmod(&dh->g, &tmp2, &dh->p, &tmp) != MP_OKAY)
+                ret = MP_EXPTMOD_E;
+        } while (ret == 0 && mp_cmp_d(&tmp, 1) == MP_EQ);
+    }
+
+    /* at this point tmp generates a group of order q mod p */
+    mp_exch(&tmp, &dh->g);
+
+    /* clear the parameters if there was an error */
+    if (ret != 0) {
+        mp_clear(&dh->q);
+        mp_clear(&dh->p);
+        mp_clear(&dh->g);
+    }
+
+    ForceZero(buf, bufSz);
+    XFREE(buf, dh->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    mp_clear(&tmp);
+    mp_clear(&tmp2);
+
+    return ret;
+}
+
+
+/* Export raw DH parameters from DhKey structure
+ *
+ * dh   - pointer to initialized DhKey structure
+ * p    - output location for DH (p) parameter
+ * pSz  - [IN/OUT] size of output buffer for p, size of p
+ * q    - output location for DH (q) parameter
+ * qSz  - [IN/OUT] size of output buffer for q, size of q
+ * g    - output location for DH (g) parameter
+ * gSz  - [IN/OUT] size of output buffer for g, size of g
+ *
+ * If p, q, and g pointers are all passed in as NULL, the function
+ * will set pSz, qSz, and gSz to the required output buffer sizes for p,
+ * q, and g. In this case, the function will return LENGTH_ONLY_E.
+ *
+ * returns 0 on success, negative upon failure
+ */
+int wc_DhExportParamsRaw(DhKey* dh, byte* p, word32* pSz,
+                         byte* q, word32* qSz, byte* g, word32* gSz)
+{
+    int ret = 0;
+    word32 pLen = 0, qLen = 0, gLen = 0;
+
+    if (dh == NULL || pSz == NULL || qSz == NULL || gSz == NULL)
+        ret = BAD_FUNC_ARG;
+
+    /* get required output buffer sizes */
+    if (ret == 0) {
+        pLen = mp_unsigned_bin_size(&dh->p);
+        qLen = mp_unsigned_bin_size(&dh->q);
+        gLen = mp_unsigned_bin_size(&dh->g);
+
+        /* return buffer sizes and LENGTH_ONLY_E if buffers are NULL */
+        if (p == NULL && q == NULL && g == NULL) {
+            *pSz = pLen;
+            *qSz = qLen;
+            *gSz = gLen;
+            ret = LENGTH_ONLY_E;
+        }
+    }
+
+    if (ret == 0) {
+        if (p == NULL || q == NULL || g == NULL)
+            ret = BAD_FUNC_ARG;
+    }
+
+    /* export p */
+    if (ret == 0) {
+        if (*pSz < pLen) {
+            WOLFSSL_MSG("Output buffer for DH p parameter too small, "
+                        "required size placed into pSz");
+            *pSz = pLen;
+            ret = BUFFER_E;
+        }
+    }
+
+    if (ret == 0) {
+        *pSz = pLen;
+        if (mp_to_unsigned_bin(&dh->p, p) != MP_OKAY)
+            ret = MP_TO_E;
+    }
+
+    /* export q */
+    if (ret == 0) {
+        if (*qSz < qLen) {
+            WOLFSSL_MSG("Output buffer for DH q parameter too small, "
+                        "required size placed into qSz");
+            *qSz = qLen;
+            ret = BUFFER_E;
+        }
+    }
+
+    if (ret == 0) {
+        *qSz = qLen;
+        if (mp_to_unsigned_bin(&dh->q, q) != MP_OKAY)
+            ret = MP_TO_E;
+    }
+
+    /* export g */
+    if (ret == 0) {
+        if (*gSz < gLen) {
+            WOLFSSL_MSG("Output buffer for DH g parameter too small, "
+                        "required size placed into gSz");
+            *gSz = gLen;
+            ret = BUFFER_E;
+        }
+    }
+
+    if (ret == 0) {
+        *gSz = gLen;
+        if (mp_to_unsigned_bin(&dh->g, g) != MP_OKAY)
+            ret = MP_TO_E;
+    }
+
+    return ret;
+}
+
+#endif /* WOLFSSL_KEY_GEN */
 
 #endif /* NO_DH */
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/dsa.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/dsa.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/dsa.c	(revision 372)
@@ -98,65 +98,130 @@
 }
 
+
+/* validate that (L,N) match allowed sizes from FIPS 186-4, Section 4.2.
+ * modLen - represents L, the size of p (prime modulus) in bits
+ * divLen - represents N, the size of q (prime divisor) in bits
+ * return 0 on success, -1 on error */
+static int CheckDsaLN(int modLen, int divLen)
+{
+    int ret = -1;
+
+    switch (modLen) {
+        case 1024:
+            if (divLen == 160)
+                ret = 0;
+            break;
+        case 2048:
+            if (divLen == 224 || divLen == 256)
+                ret = 0;
+            break;
+        case 3072:
+            if (divLen == 256)
+                ret = 0;
+            break;
+        default:
+            break;
+    }
+
+    return ret;
+}
+
+
 #ifdef WOLFSSL_KEY_GEN
 
+/* Create DSA key pair (&dsa->x, &dsa->y)
+ *
+ * Based on NIST FIPS 186-4,
+ * "B.1.1 Key Pair Generation Using Extra Random Bits"
+ *
+ * rng - pointer to initialized WC_RNG structure
+ * dsa - pointer to initialized DsaKey structure, will hold generated key
+ *
+ * return 0 on success, negative on error */
 int wc_MakeDsaKey(WC_RNG *rng, DsaKey *dsa)
 {
-    unsigned char *buf;
-    int qsize, err;
+    byte* cBuf;
+    int qSz, pSz, cSz, err;
+    mp_int tmpQ;
 
     if (rng == NULL || dsa == NULL)
         return BAD_FUNC_ARG;
 
-    qsize = mp_unsigned_bin_size(&dsa->q);
-    if (qsize == 0)
-        return BAD_FUNC_ARG;
-
-    /* allocate ram */
-    buf = (unsigned char *)XMALLOC(qsize, dsa->heap,
-                                   DYNAMIC_TYPE_TMP_BUFFER);
-    if (buf == NULL)
+    qSz = mp_unsigned_bin_size(&dsa->q);
+    pSz = mp_unsigned_bin_size(&dsa->p);
+
+    /* verify (L,N) pair bit lengths */
+    if (CheckDsaLN(pSz * WOLFSSL_BIT_SIZE, qSz * WOLFSSL_BIT_SIZE) != 0)
+        return BAD_FUNC_ARG;
+
+    /* generate extra 64 bits so that bias from mod function is negligible */
+    cSz = qSz + (64 / WOLFSSL_BIT_SIZE);
+    cBuf = (byte*)XMALLOC(cSz, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (cBuf == NULL) {
         return MEMORY_E;
-
-    if (mp_init(&dsa->x) != MP_OKAY) {
-        XFREE(buf, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER);
-        return MP_INIT_E;
+    }
+
+    if ((err = mp_init_multi(&dsa->x, &dsa->y, &tmpQ, NULL, NULL, NULL))
+                   != MP_OKAY) {
+        XFREE(cBuf, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        return err;
     }
 
     do {
-        /* make a random exponent mod q */
-        err = wc_RNG_GenerateBlock(rng, buf, qsize);
+        /* generate N+64 bits (c) from RBG into &dsa->x, making sure positive.
+         * Hash_DRBG uses SHA-256 which matches maximum
+         * requested_security_strength of (L,N) */
+        err = wc_RNG_GenerateBlock(rng, cBuf, cSz);
         if (err != MP_OKAY) {
             mp_clear(&dsa->x);
-            XFREE(buf, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER);
+            mp_clear(&dsa->y);
+            mp_clear(&tmpQ);
+            XFREE(cBuf, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER);
             return err;
         }
 
-        err = mp_read_unsigned_bin(&dsa->x, buf, qsize);
+        err = mp_read_unsigned_bin(&dsa->x, cBuf, cSz);
         if (err != MP_OKAY) {
             mp_clear(&dsa->x);
-            XFREE(buf, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER);
+            mp_clear(&dsa->y);
+            mp_clear(&tmpQ);
+            XFREE(cBuf, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER);
             return err;
         }
     } while (mp_cmp_d(&dsa->x, 1) != MP_GT);
 
-    XFREE(buf, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER);
-
-    if (mp_init(&dsa->y) != MP_OKAY) {
-        mp_clear(&dsa->x);
-        return MP_INIT_E;
-    }
+    XFREE(cBuf, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER);
+
+    /* tmpQ = q - 1 */
+    if (err == MP_OKAY)
+        err = mp_copy(&dsa->q, &tmpQ);
+
+    if (err == MP_OKAY)
+        err = mp_sub_d(&tmpQ, 1, &tmpQ);
+
+    /* x = c mod (q-1), &dsa->x holds c */
+    if (err == MP_OKAY)
+        err = mp_mod(&dsa->x, &tmpQ, &dsa->x);
+
+    /* x = c mod (q-1) + 1 */
+    if (err == MP_OKAY)
+        err = mp_add_d(&dsa->x, 1, &dsa->x);
 
     /* public key : y = g^x mod p */
+    if (err == MP_OKAY)
     err = mp_exptmod(&dsa->g, &dsa->x, &dsa->p, &dsa->y);
+
+    if (err == MP_OKAY)
+        dsa->type = DSA_PRIVATE;
+
     if (err != MP_OKAY) {
         mp_clear(&dsa->x);
         mp_clear(&dsa->y);
-        return err;
-    }
-
-    dsa->type = DSA_PRIVATE;
-
-    return MP_OKAY;
-}
+    }
+    mp_clear(&tmpQ);
+
+    return err;
+}
+
 
 /* modulus_size in bits */
@@ -185,9 +250,8 @@
         default:
             return BAD_FUNC_ARG;
-            break;
     }
 
     /* modulus size in bytes */
-    msize = modulus_size / 8;
+    msize = modulus_size / WOLFSSL_BIT_SIZE;
 
     /* allocate ram */
@@ -273,5 +337,5 @@
     /* loop until p is prime */
     while (check_prime == MP_NO) {
-        err = mp_prime_is_prime(&dsa->p, 8, &check_prime);
+        err = mp_prime_is_prime_ex(&dsa->p, 8, &check_prime, rng);
         if (err != MP_OKAY) {
             mp_clear(&dsa->q);
@@ -362,4 +426,239 @@
 
 
+static int _DsaImportParamsRaw(DsaKey* dsa, const char* p, const char* q,
+                          const char* g, int trusted, WC_RNG* rng)
+{
+    int err;
+    word32 pSz, qSz;
+
+    if (dsa == NULL || p == NULL || q == NULL || g == NULL)
+        return BAD_FUNC_ARG;
+
+    /* read p */
+    err = mp_read_radix(&dsa->p, p, MP_RADIX_HEX);
+    if (err == MP_OKAY && !trusted) {
+        int isPrime = 1;
+        if (rng == NULL)
+            err = mp_prime_is_prime(&dsa->p, 8, &isPrime);
+        else
+            err = mp_prime_is_prime_ex(&dsa->p, 8, &isPrime, rng);
+
+        if (err == MP_OKAY) {
+            if (!isPrime)
+                err = DH_CHECK_PUB_E;
+        }
+    }
+
+    /* read q */
+    if (err == MP_OKAY)
+        err = mp_read_radix(&dsa->q, q, MP_RADIX_HEX);
+
+    /* read g */
+    if (err == MP_OKAY)
+        err = mp_read_radix(&dsa->g, g, MP_RADIX_HEX);
+
+    /* verify (L,N) pair bit lengths */
+    pSz = mp_unsigned_bin_size(&dsa->p);
+    qSz = mp_unsigned_bin_size(&dsa->q);
+
+    if (CheckDsaLN(pSz * WOLFSSL_BIT_SIZE, qSz * WOLFSSL_BIT_SIZE) != 0) {
+        WOLFSSL_MSG("Invalid DSA p or q parameter size");
+        err = BAD_FUNC_ARG;
+    }
+
+    if (err != MP_OKAY) {
+        mp_clear(&dsa->p);
+        mp_clear(&dsa->q);
+        mp_clear(&dsa->g);
+    }
+
+    return err;
+}
+
+
+/* Import raw DSA parameters into DsaKey structure for use with wc_MakeDsaKey(),
+ * input parameters (p,q,g) should be represented as ASCII hex values.
+ *
+ * dsa  - pointer to initialized DsaKey structure
+ * p    - DSA (p) parameter, ASCII hex string
+ * pSz  - length of p
+ * q    - DSA (q) parameter, ASCII hex string
+ * qSz  - length of q
+ * g    - DSA (g) parameter, ASCII hex string
+ * gSz  - length of g
+ *
+ * returns 0 on success, negative upon failure
+ */
+int wc_DsaImportParamsRaw(DsaKey* dsa, const char* p, const char* q,
+                          const char* g)
+{
+    return _DsaImportParamsRaw(dsa, p, q, g, 1, NULL);
+}
+
+
+/* Import raw DSA parameters into DsaKey structure for use with wc_MakeDsaKey(),
+ * input parameters (p,q,g) should be represented as ASCII hex values. Check
+ * that the p value is probably prime.
+ *
+ * dsa  - pointer to initialized DsaKey structure
+ * p    - DSA (p) parameter, ASCII hex string
+ * pSz  - length of p
+ * q    - DSA (q) parameter, ASCII hex string
+ * qSz  - length of q
+ * g    - DSA (g) parameter, ASCII hex string
+ * gSz  - length of g
+ * trusted - trust that p is OK
+ * rng  - random number generator for the prime test
+ *
+ * returns 0 on success, negative upon failure
+ */
+int wc_DsaImportParamsRawCheck(DsaKey* dsa, const char* p, const char* q,
+                          const char* g, int trusted, WC_RNG* rng)
+{
+    return _DsaImportParamsRaw(dsa, p, q, g, trusted, rng);
+}
+
+
+/* Export raw DSA parameters from DsaKey structure
+ *
+ * dsa  - pointer to initialized DsaKey structure
+ * p    - output location for DSA (p) parameter
+ * pSz  - [IN/OUT] size of output buffer for p, size of p
+ * q    - output location for DSA (q) parameter
+ * qSz  - [IN/OUT] size of output buffer for q, size of q
+ * g    - output location for DSA (g) parameter
+ * gSz  - [IN/OUT] size of output buffer for g, size of g
+ *
+ * If p, q, and g pointers are all passed in as NULL, the function
+ * will set pSz, qSz, and gSz to the required output buffer sizes for p,
+ * q, and g. In this case, the function will return LENGTH_ONLY_E.
+ *
+ * returns 0 on success, negative upon failure
+ */
+int wc_DsaExportParamsRaw(DsaKey* dsa, byte* p, word32* pSz,
+                          byte* q, word32* qSz, byte* g, word32* gSz)
+{
+    int err;
+    word32 pLen, qLen, gLen;
+
+    if (dsa == NULL || pSz == NULL || qSz == NULL || gSz == NULL)
+        return BAD_FUNC_ARG;
+
+    /* get required output buffer sizes */
+    pLen = mp_unsigned_bin_size(&dsa->p);
+    qLen = mp_unsigned_bin_size(&dsa->q);
+    gLen = mp_unsigned_bin_size(&dsa->g);
+
+    /* return buffer sizes and LENGTH_ONLY_E if buffers are NULL */
+    if (p == NULL && q == NULL && g == NULL) {
+        *pSz = pLen;
+        *qSz = qLen;
+        *gSz = gLen;
+        return LENGTH_ONLY_E;
+    }
+
+    if (p == NULL || q == NULL || g == NULL)
+        return BAD_FUNC_ARG;
+
+    /* export p */
+    if (*pSz < pLen) {
+        WOLFSSL_MSG("Output buffer for DSA p parameter too small, "
+                    "required size placed into pSz");
+        *pSz = pLen;
+        return BUFFER_E;
+    }
+    *pSz = pLen;
+    err = mp_to_unsigned_bin(&dsa->p, p);
+
+    /* export q */
+    if (err == MP_OKAY) {
+        if (*qSz < qLen) {
+            WOLFSSL_MSG("Output buffer for DSA q parameter too small, "
+                        "required size placed into qSz");
+            *qSz = qLen;
+            return BUFFER_E;
+        }
+        *qSz = qLen;
+        err = mp_to_unsigned_bin(&dsa->q, q);
+    }
+
+    /* export g */
+    if (err == MP_OKAY) {
+        if (*gSz < gLen) {
+            WOLFSSL_MSG("Output buffer for DSA g parameter too small, "
+                        "required size placed into gSz");
+            *gSz = gLen;
+            return BUFFER_E;
+        }
+        *gSz = gLen;
+        err = mp_to_unsigned_bin(&dsa->g, g);
+    }
+
+    return err;
+}
+
+
+/* Export raw DSA key (x, y) from DsaKey structure
+ *
+ * dsa  - pointer to initialized DsaKey structure
+ * x    - output location for private key
+ * xSz  - [IN/OUT] size of output buffer for x, size of x
+ * y    - output location for public key
+ * ySz  - [IN/OUT] size of output buffer for y, size of y
+ *
+ * If x and y pointers are all passed in as NULL, the function
+ * will set xSz and ySz to the required output buffer sizes for x
+ * and y. In this case, the function will return LENGTH_ONLY_E.
+ *
+ * returns 0 on success, negative upon failure
+ */
+int wc_DsaExportKeyRaw(DsaKey* dsa, byte* x, word32* xSz, byte* y, word32* ySz)
+{
+    int err;
+    word32 xLen, yLen;
+
+    if (dsa == NULL || xSz == NULL || ySz == NULL)
+        return BAD_FUNC_ARG;
+
+    /* get required output buffer sizes */
+    xLen = mp_unsigned_bin_size(&dsa->x);
+    yLen = mp_unsigned_bin_size(&dsa->y);
+
+    /* return buffer sizes and LENGTH_ONLY_E if buffers are NULL */
+    if (x == NULL && y == NULL) {
+        *xSz = xLen;
+        *ySz = yLen;
+        return LENGTH_ONLY_E;
+    }
+
+    if (x == NULL || y == NULL)
+        return BAD_FUNC_ARG;
+
+    /* export x */
+    if (*xSz < xLen) {
+        WOLFSSL_MSG("Output buffer for DSA private key (x) too small, "
+                    "required size placed into xSz");
+        *xSz = xLen;
+        return BUFFER_E;
+    }
+    *xSz = xLen;
+    err = mp_to_unsigned_bin(&dsa->x, x);
+
+    /* export y */
+    if (err == MP_OKAY) {
+        if (*ySz < yLen) {
+            WOLFSSL_MSG("Output buffer to DSA public key (y) too small, "
+                        "required size placed into ySz");
+            *ySz = yLen;
+            return BUFFER_E;
+        }
+        *ySz = yLen;
+        err = mp_to_unsigned_bin(&dsa->y, y);
+    }
+
+    return err;
+}
+
+
 int wc_DsaSign(const byte* digest, byte* out, DsaKey* key, WC_RNG* rng)
 {
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/ecc.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/ecc.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/ecc.c	(revision 372)
@@ -94,4 +94,14 @@
 
 
+#if defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+    /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+    #define FIPS_NO_WRAPPERS
+
+	#ifdef USE_WINDOWS_API
+		#pragma code_seg(".fipsA$f")
+		#pragma const_seg(".fipsB$f")
+	#endif
+#endif
+
 #include <wolfssl/wolfcrypt/ecc.h>
 #include <wolfssl/wolfcrypt/asn.h>
@@ -113,4 +123,8 @@
 #endif
 
+#ifdef WOLF_CRYPTO_DEV
+    #include <wolfssl/wolfcrypt/cryptodev.h>
+#endif
+
 #ifdef NO_INLINE
     #include <wolfssl/wolfcrypt/misc.h>
@@ -124,5 +138,7 @@
 #endif
 
-#ifdef USE_FAST_MATH
+#ifdef WOLFSSL_SP_MATH
+    #define GEN_MEM_ERR MP_MEM
+#elif defined(USE_FAST_MATH)
     #define GEN_MEM_ERR FP_MEM
 #else
@@ -186,269 +202,431 @@
 #endif
 
-
 /* The encoded OID's for ECC curves */
 #ifdef ECC112
     #ifndef NO_ECC_SECP
-        static const ecc_oid_t ecc_oid_secp112r1[] = {
         #ifdef HAVE_OID_ENCODING
-            1,3,132,0,6
+            #define CODED_SECP112R1    {1,3,132,0,6}
+            #define CODED_SECP112R1_SZ 5
         #else
-            0x2B,0x81,0x04,0x00,0x06
+            #define CODED_SECP112R1    {0x2B,0x81,0x04,0x00,0x06}
+            #define CODED_SECP112R1_SZ 5
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_secp112r1[] = CODED_SECP112R1;
+        #else
+            #define ecc_oid_secp112r1 CODED_SECP112R1
+        #endif
+        #define ecc_oid_secp112r1_sz CODED_SECP112R1_SZ
     #endif /* !NO_ECC_SECP */
     #ifdef HAVE_ECC_SECPR2
-        static const ecc_oid_t ecc_oid_secp112r2[] = {
         #ifdef HAVE_OID_ENCODING
-            1,3,132,0,7
+            #define CODED_SECP112R2    {1,3,132,0,7}
+            #define CODED_SECP112R2_SZ 5
         #else
-            0x2B,0x81,0x04,0x00,0x07
+            #define CODED_SECP112R2    {0x2B,0x81,0x04,0x00,0x07}
+            #define CODED_SECP112R2_SZ 5
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_secp112r2[] = CODED_SECP112R2;
+        #else
+            #define ecc_oid_secp112r2 CODED_SECP112R2
+        #endif
+        #define ecc_oid_secp112r2_sz CODED_SECP112R2_SZ
     #endif /* HAVE_ECC_SECPR2 */
 #endif /* ECC112 */
 #ifdef ECC128
     #ifndef NO_ECC_SECP
-        static const ecc_oid_t ecc_oid_secp128r1[] = {
         #ifdef HAVE_OID_ENCODING
-            1,3,132,0,28
+            #define CODED_SECP128R1    {1,3,132,0,28}
+            #define CODED_SECP128R1_SZ 5
         #else
-            0x2B,0x81,0x04,0x00,0x1C
+            #define CODED_SECP128R1    {0x2B,0x81,0x04,0x00,0x1C}
+            #define CODED_SECP128R1_SZ 5
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_secp128r1[] = CODED_SECP128R1;
+        #else
+            #define ecc_oid_secp128r1 CODED_SECP128R1
+        #endif
+        #define ecc_oid_secp128r1_sz CODED_SECP128R1_SZ
     #endif /* !NO_ECC_SECP */
     #ifdef HAVE_ECC_SECPR2
-        static const ecc_oid_t ecc_oid_secp128r2[] = {
         #ifdef HAVE_OID_ENCODING
-            1,3,132,0,29
+            #define CODED_SECP128R2    {1,3,132,0,29}
+            #define CODED_SECP128R2_SZ 5
         #else
-            0x2B,0x81,0x04,0x00,0x1D
+            #define CODED_SECP128R2    {0x2B,0x81,0x04,0x00,0x1D}
+            #define CODED_SECP128R2_SZ 5
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_secp128r2[] = CODED_SECP128R2;
+        #else
+            #define ecc_oid_secp128r2 CODED_SECP128R2
+        #endif
+        #define ecc_oid_secp128r2_sz CODED_SECP128R2_SZ
     #endif /* HAVE_ECC_SECPR2 */
 #endif /* ECC128 */
 #ifdef ECC160
     #ifndef NO_ECC_SECP
-        static const ecc_oid_t ecc_oid_secp160r1[] = {
         #ifdef HAVE_OID_ENCODING
-            1,3,132,0,8
+            #define CODED_SECP160R1    {1,3,132,0,8}
+            #define CODED_SECP160R1_SZ 5
         #else
-            0x2B,0x81,0x04,0x00,0x08
+            #define CODED_SECP160R1    {0x2B,0x81,0x04,0x00,0x08}
+            #define CODED_SECP160R1_SZ 5
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_secp160r1[] = CODED_SECP160R1;
+        #else
+            #define ecc_oid_secp160r1 CODED_SECP160R1
+        #endif
+        #define ecc_oid_secp160r1_sz CODED_SECP160R1_SZ
     #endif /* !NO_ECC_SECP */
     #ifdef HAVE_ECC_SECPR2
-        static const ecc_oid_t ecc_oid_secp160r2[] = {
         #ifdef HAVE_OID_ENCODING
-            1,3,132,0,30
+            #define CODED_SECP160R2    {1,3,132,0,30}
+            #define CODED_SECP160R1_SZ 5
         #else
-            0x2B,0x81,0x04,0x00,0x1E
+            #define CODED_SECP160R2    {0x2B,0x81,0x04,0x00,0x1E}
+            #define CODED_SECP160R2_SZ 5
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_secp160r2[] = CODED_SECP160R2;
+        #else
+            #define ecc_oid_secp160r2 CODED_SECP160R2
+        #endif
+        #define ecc_oid_secp160r2_sz CODED_SECP160R2_SZ
     #endif /* HAVE_ECC_SECPR2 */
     #ifdef HAVE_ECC_KOBLITZ
-        static const ecc_oid_t ecc_oid_secp160k1[] = {
         #ifdef HAVE_OID_ENCODING
-            1,3,132,0,9
+            #define CODED_SECP160K1    {1,3,132,0,9}
+            #define CODED_SECP160K1_SZ 5
         #else
-            0x2B,0x81,0x04,0x00,0x09
+            #define CODED_SECP160K1    {0x2B,0x81,0x04,0x00,0x09}
+            #define CODED_SECP160K1_SZ 5
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_secp160k1[] = CODED_SECP160K1;
+        #else
+            #define ecc_oid_secp160k1 CODED_SECP160K1
+        #endif
+        #define ecc_oid_secp160k1_sz CODED_SECP160K1_SZ
     #endif /* HAVE_ECC_KOBLITZ */
     #ifdef HAVE_ECC_BRAINPOOL
-        static const ecc_oid_t ecc_oid_brainpoolp160r1[] = {
         #ifdef HAVE_OID_ENCODING
-            1,3,36,3,3,2,8,1,1,1
+            #define CODED_BRAINPOOLP160R1    {1,3,36,3,3,2,8,1,1,1}
+            #define CODED_BRAINPOOLP160R1_SZ 10
         #else
-            0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x01
+            #define CODED_BRAINPOOLP160R1    {0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x01}
+            #define CODED_BRAINPOOLP160R1_SZ 9
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_brainpoolp160r1[] = CODED_BRAINPOOLP160R1;
+        #else
+            #define ecc_oid_brainpoolp160r1 CODED_BRAINPOOLP160R1
+        #endif
+        #define ecc_oid_brainpoolp160r1_sz CODED_BRAINPOOLP160R1_SZ
     #endif /* HAVE_ECC_BRAINPOOL */
 #endif /* ECC160 */
 #ifdef ECC192
     #ifndef NO_ECC_SECP
-        static const ecc_oid_t ecc_oid_secp192r1[] = {
         #ifdef HAVE_OID_ENCODING
-            1,2,840,10045,3,1,1
+            #define CODED_SECP192R1    {1,2,840,10045,3,1,1}
+            #define CODED_SECP192R1_SZ 7
         #else
-            0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x01
+            #define CODED_SECP192R1    {0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x01}
+            #define CODED_SECP192R1_SZ 8
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_secp192r1[] = CODED_SECP192R1;
+        #else
+            #define ecc_oid_secp192r1 CODED_SECP192R1
+        #endif
+        #define ecc_oid_secp192r1_sz CODED_SECP192R1_SZ
     #endif /* !NO_ECC_SECP */
     #ifdef HAVE_ECC_SECPR2
-        static const ecc_oid_t ecc_oid_prime192v2[] = {
         #ifdef HAVE_OID_ENCODING
-            1,2,840,10045,3,1,2
+            #define CODED_PRIME192V2    {1,2,840,10045,3,1,2}
+            #define CODED_PRIME192V2_SZ 7
         #else
-            0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x02
+            #define CODED_PRIME192V2    {0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x02}
+            #define CODED_PRIME192V2_SZ 8
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_prime192v2[] = CODED_PRIME192V2;
+        #else
+            #define ecc_oid_prime192v2 CODED_PRIME192V2
+        #endif
+        #define ecc_oid_prime192v2_sz CODED_PRIME192V2_SZ
     #endif /* HAVE_ECC_SECPR2 */
     #ifdef HAVE_ECC_SECPR3
-        static const ecc_oid_t ecc_oid_prime192v3[] = {
         #ifdef HAVE_OID_ENCODING
-            1,2,840,10045,3,1,3
+            #define CODED_PRIME192V3    {1,2,840,10045,3,1,3}
+            #define CODED_PRIME192V3_SZ 7
         #else
-            0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x03
+            #define CODED_PRIME192V3    {0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x03}
+            #define CODED_PRIME192V3_SZ 8
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_prime192v3[] = CODED_PRIME192V3;
+        #else
+            #define ecc_oid_prime192v3 CODED_PRIME192V3
+        #endif
+        #define ecc_oid_prime192v3_sz CODED_PRIME192V3_SZ
     #endif /* HAVE_ECC_SECPR3 */
     #ifdef HAVE_ECC_KOBLITZ
-        static const ecc_oid_t ecc_oid_secp192k1[] = {
         #ifdef HAVE_OID_ENCODING
-            1,3,132,0,31
+            #define CODED_SECP192K1    {1,3,132,0,31}
+            #define CODED_SECP192K1_SZ 5
         #else
-            0x2B,0x81,0x04,0x00,0x1F
+            #define CODED_SECP192K1    {0x2B,0x81,0x04,0x00,0x1F}
+            #define CODED_SECP192K1_SZ 5
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_secp192k1[] = CODED_SECP192K1;
+        #else
+            #define ecc_oid_secp192k1 CODED_SECP192K1
+        #endif
+        #define ecc_oid_secp192k1_sz CODED_SECP192K1_SZ
     #endif /* HAVE_ECC_KOBLITZ */
     #ifdef HAVE_ECC_BRAINPOOL
-        static const ecc_oid_t ecc_oid_brainpoolp192r1[] = {
         #ifdef HAVE_OID_ENCODING
-            1,3,36,3,3,2,8,1,1,3
+            #define CODED_BRAINPOOLP192R1    {1,3,36,3,3,2,8,1,1,3}
+            #define CODED_BRAINPOOLP192R1_SZ 10
         #else
-            0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x03
+            #define CODED_BRAINPOOLP192R1    {0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x03}
+            #define CODED_BRAINPOOLP192R1_SZ 9
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_brainpoolp192r1[] = CODED_BRAINPOOLP192R1;
+        #else
+            #define ecc_oid_brainpoolp192r1 CODED_BRAINPOOLP192R1
+        #endif
+        #define ecc_oid_brainpoolp192r1_sz CODED_BRAINPOOLP192R1_SZ
     #endif /* HAVE_ECC_BRAINPOOL */
 #endif /* ECC192 */
 #ifdef ECC224
     #ifndef NO_ECC_SECP
-        static const ecc_oid_t ecc_oid_secp224r1[] = {
         #ifdef HAVE_OID_ENCODING
-            1,3,132,0,33
+            #define CODED_SECP224R1    {1,3,132,0,33}
+            #define CODED_SECP224R1_SZ 5
         #else
-            0x2B,0x81,0x04,0x00,0x21
+            #define CODED_SECP224R1    {0x2B,0x81,0x04,0x00,0x21}
+            #define CODED_SECP224R1_SZ 5
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_secp224r1[] = CODED_SECP224R1;
+        #else
+            #define ecc_oid_secp224r1 CODED_SECP224R1
+        #endif
+        #define ecc_oid_secp224r1_sz CODED_SECP224R1_SZ
     #endif /* !NO_ECC_SECP */
     #ifdef HAVE_ECC_KOBLITZ
-        static const ecc_oid_t ecc_oid_secp224k1[] = {
         #ifdef HAVE_OID_ENCODING
-            1,3,132,0,32
+            #define CODED_SECP224K1    {1,3,132,0,32}
+            #define CODED_SECP224K1_SZ 5
         #else
-            0x2B,0x81,0x04,0x00,0x20
+            #define CODED_SECP224K1    {0x2B,0x81,0x04,0x00,0x20}
+            #define CODED_SECP224K1_SZ 5
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_secp224k1[] = CODED_SECP224K1;
+        #else
+            #define ecc_oid_secp224k1 CODED_SECP224K1
+        #endif
+        #define ecc_oid_secp224k1_sz CODED_SECP224K1_SZ
     #endif /* HAVE_ECC_KOBLITZ */
     #ifdef HAVE_ECC_BRAINPOOL
-        static const ecc_oid_t ecc_oid_brainpoolp224r1[] = {
         #ifdef HAVE_OID_ENCODING
-            1,3,36,3,3,2,8,1,1,5
+            #define CODED_BRAINPOOLP224R1    {1,3,36,3,3,2,8,1,1,5}
+            #define CODED_BRAINPOOLP224R1_SZ 10
         #else
-            0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x05
+            #define CODED_BRAINPOOLP224R1    {0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x05}
+            #define CODED_BRAINPOOLP224R1_SZ 9
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_brainpoolp224r1[] = CODED_BRAINPOOLP224R1;
+        #else
+            #define ecc_oid_brainpoolp224r1 CODED_BRAINPOOLP224R1
+        #endif
+        #define ecc_oid_brainpoolp224r1_sz CODED_BRAINPOOLP224R1_SZ
     #endif /* HAVE_ECC_BRAINPOOL */
 #endif /* ECC224 */
 #ifdef ECC239
     #ifndef NO_ECC_SECP
-        static const ecc_oid_t ecc_oid_prime239v1[] = {
         #ifdef HAVE_OID_ENCODING
-            1,2,840,10045,3,1,4
+            #define CODED_PRIME239V1    {1,2,840,10045,3,1,4}
+            #define CODED_PRIME239V1_SZ 7
         #else
-            0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x04
+            #define CODED_PRIME239V1    {0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x04}
+            #define CODED_PRIME239V1_SZ 8
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_prime239v1[] = CODED_PRIME239V1;
+        #else
+            #define ecc_oid_prime239v1 CODED_PRIME239V1
+        #endif
+        #define ecc_oid_prime239v1_sz CODED_PRIME239V1_SZ
     #endif /* !NO_ECC_SECP */
     #ifdef HAVE_ECC_SECPR2
-        static const ecc_oid_t ecc_oid_prime239v2[] = {
         #ifdef HAVE_OID_ENCODING
-            1,2,840,10045,3,1,5
+            #define CODED_PRIME239V2    {1,2,840,10045,3,1,5}
+            #define CODED_PRIME239V2_SZ 7
         #else
-            0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x05
+            #define CODED_PRIME239V2    {0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x05}
+            #define CODED_PRIME239V2_SZ 8
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_prime239v2[] = CODED_PRIME239V2;
+        #else
+            #define ecc_oid_prime239v2 CODED_PRIME239V2
+        #endif
+        #define ecc_oid_prime239v2_sz CODED_PRIME239V2_SZ
     #endif /* HAVE_ECC_SECPR2 */
     #ifdef HAVE_ECC_SECPR3
-        static const ecc_oid_t ecc_oid_prime239v3[] = {
         #ifdef HAVE_OID_ENCODING
-            1,2,840,10045,3,1,6
+            #define CODED_PRIME239V3    {1,2,840,10045,3,1,6}
+            #define CODED_PRIME239V3_SZ 7
         #else
-            0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x06
+            #define CODED_PRIME239V3    {0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x06}
+            #define CODED_PRIME239V3_SZ 8
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_prime239v3[] = CODED_PRIME239V3;
+        #else
+            #define ecc_oid_prime239v3 CODED_PRIME239V3
+        #endif
+        #define ecc_oid_prime239v3_sz CODED_PRIME239V3_SZ
     #endif /* HAVE_ECC_SECPR3 */
 #endif /* ECC239 */
 #ifdef ECC256
     #ifndef NO_ECC_SECP
-        static const ecc_oid_t ecc_oid_secp256r1[] = {
         #ifdef HAVE_OID_ENCODING
-            1,2,840,10045,3,1,7
+            #define CODED_SECP256R1    {1,2,840,10045,3,1,7}
+            #define CODED_SECP256R1_SZ 7
         #else
-            0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x07
+            #define CODED_SECP256R1    {0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x07}
+            #define CODED_SECP256R1_SZ 8
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_secp256r1[] = CODED_SECP256R1;
+        #else
+            #define ecc_oid_secp256r1 CODED_SECP256R1
+        #endif
+        #define ecc_oid_secp256r1_sz CODED_SECP256R1_SZ
     #endif /* !NO_ECC_SECP */
     #ifdef HAVE_ECC_KOBLITZ
-        static const ecc_oid_t ecc_oid_secp256k1[] = {
         #ifdef HAVE_OID_ENCODING
-            1,3,132,0,10
+            #define CODED_SECP256K1    {1,3,132,0,10}
+            #define CODED_SECP256K1_SZ 5
         #else
-            0x2B,0x81,0x04,0x00,0x0A
+            #define CODED_SECP256K1    {0x2B,0x81,0x04,0x00,0x0A}
+            #define CODED_SECP256K1_SZ 5
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_secp256k1[] = CODED_SECP256K1;
+        #else
+            #define ecc_oid_secp256k1 CODED_SECP256K1
+        #endif
+        #define ecc_oid_secp256k1_sz CODED_SECP256K1_SZ
     #endif /* HAVE_ECC_KOBLITZ */
     #ifdef HAVE_ECC_BRAINPOOL
-        static const ecc_oid_t ecc_oid_brainpoolp256r1[] = {
         #ifdef HAVE_OID_ENCODING
-            1,3,36,3,3,2,8,1,1,7
+            #define CODED_BRAINPOOLP256R1    {1,3,36,3,3,2,8,1,1,7}
+            #define CODED_BRAINPOOLP256R1_SZ 10
         #else
-            0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x07
+            #define CODED_BRAINPOOLP256R1    {0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x07}
+            #define CODED_BRAINPOOLP256R1_SZ 9
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_brainpoolp256r1[] = CODED_BRAINPOOLP256R1;
+        #else
+            #define ecc_oid_brainpoolp256r1 CODED_BRAINPOOLP256R1
+        #endif
+        #define ecc_oid_brainpoolp256r1_sz CODED_BRAINPOOLP256R1_SZ
     #endif /* HAVE_ECC_BRAINPOOL */
 #endif /* ECC256 */
 #ifdef ECC320
     #ifdef HAVE_ECC_BRAINPOOL
-        static const ecc_oid_t ecc_oid_brainpoolp320r1[] = {
         #ifdef HAVE_OID_ENCODING
-            1,3,36,3,3,2,8,1,1,9
+            #define CODED_BRAINPOOLP320R1    {1,3,36,3,3,2,8,1,1,9}
+            #define CODED_BRAINPOOLP320R1_SZ 10
         #else
-            0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x09
+            #define CODED_BRAINPOOLP320R1    {0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x09}
+            #define CODED_BRAINPOOLP320R1_SZ 9
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_brainpoolp320r1[] = CODED_BRAINPOOLP320R1;
+        #else
+            #define ecc_oid_brainpoolp320r1 CODED_BRAINPOOLP320R1
+        #endif
+        #define ecc_oid_brainpoolp320r1_sz CODED_BRAINPOOLP320R1_SZ
     #endif /* HAVE_ECC_BRAINPOOL */
 #endif /* ECC320 */
 #ifdef ECC384
     #ifndef NO_ECC_SECP
-        static const ecc_oid_t ecc_oid_secp384r1[] = {
         #ifdef HAVE_OID_ENCODING
-            1,3,132,0,34
+            #define CODED_SECP384R1    {1,3,132,0,34}
+            #define CODED_SECP384R1_SZ 5
         #else
-            0x2B,0x81,0x04,0x00,0x22
+            #define CODED_SECP384R1    {0x2B,0x81,0x04,0x00,0x22}
+            #define CODED_SECP384R1_SZ 5
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_secp384r1[] = CODED_SECP384R1;
+            #define CODED_SECP384R1_OID ecc_oid_secp384r1
+        #else
+			#define ecc_oid_secp384r1 CODED_SECP384R1
+        #endif
+        #define ecc_oid_secp384r1_sz CODED_SECP384R1_SZ
     #endif /* !NO_ECC_SECP */
     #ifdef HAVE_ECC_BRAINPOOL
-        static const ecc_oid_t ecc_oid_brainpoolp384r1[] = {
         #ifdef HAVE_OID_ENCODING
-            1,3,36,3,3,2,8,1,1,11
+            #define CODED_BRAINPOOLP384R1    {1,3,36,3,3,2,8,1,1,11}
+            #define CODED_BRAINPOOLP384R1_SZ 10
         #else
-            0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x0B
+            #define CODED_BRAINPOOLP384R1    {0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x0B}
+            #define CODED_BRAINPOOLP384R1_SZ 9
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_brainpoolp384r1[] = CODED_BRAINPOOLP384R1;
+        #else
+            #define ecc_oid_brainpoolp384r1 CODED_BRAINPOOLP384R1
+        #endif
+        #define ecc_oid_brainpoolp384r1_sz CODED_BRAINPOOLP384R1_SZ
     #endif /* HAVE_ECC_BRAINPOOL */
 #endif /* ECC384 */
 #ifdef ECC512
     #ifdef HAVE_ECC_BRAINPOOL
-        static const ecc_oid_t ecc_oid_brainpoolp512r1[] = {
         #ifdef HAVE_OID_ENCODING
-            1,3,36,3,3,2,8,1,1,13
+            #define CODED_BRAINPOOLP512R1    {1,3,36,3,3,2,8,1,1,13}
+            #define CODED_BRAINPOOLP512R1_SZ 10
         #else
-            0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x0D
+            #define CODED_BRAINPOOLP512R1    {0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x0D}
+            #define CODED_BRAINPOOLP512R1_SZ 9
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_brainpoolp512r1[] = CODED_BRAINPOOLP512R1;
+        #else
+            #define ecc_oid_brainpoolp512r1 CODED_BRAINPOOLP512R1
+        #endif
+        #define ecc_oid_brainpoolp512r1_sz CODED_BRAINPOOLP512R1_SZ
     #endif /* HAVE_ECC_BRAINPOOL */
 #endif /* ECC512 */
 #ifdef ECC521
     #ifndef NO_ECC_SECP
-        static const ecc_oid_t ecc_oid_secp521r1[] = {
         #ifdef HAVE_OID_ENCODING
-            1,3,132,0,35
+            #define CODED_SECP521R1     {1,3,132,0,35}
+            #define CODED_SECP521R1_SZ 5
         #else
-            0x2B,0x81,0x04,0x00,0x23
+            #define CODED_SECP521R1     {0x2B,0x81,0x04,0x00,0x23}
+            #define CODED_SECP521R1_SZ 5
         #endif
-        };
+        #ifndef USE_WINDOWS_API
+            static const ecc_oid_t ecc_oid_secp521r1[] = CODED_SECP521R1;
+        #else
+            #define ecc_oid_secp521r1 CODED_SECP521R1
+        #endif
+        #define ecc_oid_secp521r1_sz CODED_SECP521R1_SZ
     #endif /* !NO_ECC_SECP */
 #endif /* ECC521 */
@@ -472,5 +650,5 @@
         "A89CE5AF8724C0A23E0E0FF77500", /* Gy         */
         ecc_oid_secp112r1,              /* oid/oidSz  */
-        sizeof(ecc_oid_secp112r1) / sizeof(ecc_oid_t),
+        ecc_oid_secp112r1_sz,
         ECC_SECP112R1_OID,              /* oid sum    */
         1,                              /* cofactor   */
@@ -489,5 +667,5 @@
         "ADCD46F5882E3747DEF36E956E97", /* Gy         */
         ecc_oid_secp112r2,              /* oid/oidSz  */
-        sizeof(ecc_oid_secp112r2) / sizeof(ecc_oid_t),
+        ecc_oid_secp112r2_sz,
         ECC_SECP112R2_OID,              /* oid sum    */
         4,                              /* cofactor   */
@@ -508,5 +686,5 @@
         "CF5AC8395BAFEB13C02DA292DDED7A83", /* Gy         */
         ecc_oid_secp128r1,                  /* oid/oidSz  */
-        sizeof(ecc_oid_secp128r1) / sizeof(ecc_oid_t),
+        ecc_oid_secp128r1_sz,
         ECC_SECP128R1_OID,                  /* oid sum    */
         1,                                  /* cofactor   */
@@ -525,5 +703,5 @@
         "27B6916A894D3AEE7106FE805FC34B44", /* Gy         */
         ecc_oid_secp128r2,                  /* oid/oidSz  */
-        sizeof(ecc_oid_secp128r2) / sizeof(ecc_oid_t),
+        ecc_oid_secp128r2_sz,
         ECC_SECP128R2_OID,                  /* oid sum    */
         4,                                  /* cofactor   */
@@ -544,5 +722,5 @@
         "23A628553168947D59DCC912042351377AC5FB32", /* Gy         */
         ecc_oid_secp160r1,                          /* oid/oidSz  */
-        sizeof(ecc_oid_secp160r1) / sizeof(ecc_oid_t),
+        ecc_oid_secp160r1_sz,
         ECC_SECP160R1_OID,                          /* oid sum    */
         1,                                          /* cofactor   */
@@ -561,5 +739,5 @@
         "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E", /* Gy         */
         ecc_oid_secp160r2,                          /* oid/oidSz  */
-        sizeof(ecc_oid_secp160r2) / sizeof(ecc_oid_t),
+        ecc_oid_secp160r2_sz,
         ECC_SECP160R2_OID,                          /* oid sum    */
         1,                                          /* cofactor   */
@@ -578,5 +756,5 @@
         "938CF935318FDCED6BC28286531733C3F03C4FEE", /* Gy         */
         ecc_oid_secp160k1,                          /* oid/oidSz  */
-        sizeof(ecc_oid_secp160k1) / sizeof(ecc_oid_t),
+        ecc_oid_secp160k1_sz,
         ECC_SECP160K1_OID,                          /* oid sum    */
         1,                                          /* cofactor   */
@@ -595,5 +773,5 @@
         "1667CB477A1A8EC338F94741669C976316DA6321", /* Gy         */
         ecc_oid_brainpoolp160r1,                    /* oid/oidSz  */
-        sizeof(ecc_oid_brainpoolp160r1) / sizeof(ecc_oid_t),
+        ecc_oid_brainpoolp160r1_sz,
         ECC_BRAINPOOLP160R1_OID,                    /* oid sum    */
         1,                                          /* cofactor   */
@@ -614,5 +792,5 @@
         "7192B95FFC8DA78631011ED6B24CDD573F977A11E794811",  /* Gy         */
         ecc_oid_secp192r1,                                  /* oid/oidSz  */
-        sizeof(ecc_oid_secp192r1) / sizeof(ecc_oid_t),
+        ecc_oid_secp192r1_sz,
         ECC_SECP192R1_OID,                                  /* oid sum    */
         1,                                                  /* cofactor   */
@@ -631,5 +809,5 @@
         "6574D11D69B6EC7A672BB82A083DF2F2B0847DE970B2DE15", /* Gy         */
         ecc_oid_prime192v2,                                 /* oid/oidSz  */
-        sizeof(ecc_oid_prime192v2) / sizeof(ecc_oid_t),
+        ecc_oid_prime192v2_sz,
         ECC_PRIME192V2_OID,                                 /* oid sum    */
         1,                                                  /* cofactor   */
@@ -648,5 +826,5 @@
         "38A90F22637337334B49DCB66A6DC8F9978ACA7648A943B0", /* Gy         */
         ecc_oid_prime192v3,                                 /* oid/oidSz  */
-        sizeof(ecc_oid_prime192v3) / sizeof(ecc_oid_t),
+        ecc_oid_prime192v3_sz,
         ECC_PRIME192V3_OID,                                 /* oid sum    */
         1,                                                  /* cofactor   */
@@ -665,5 +843,5 @@
         "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D", /* Gy         */
         ecc_oid_secp192k1,                                  /* oid/oidSz  */
-        sizeof(ecc_oid_secp192k1) / sizeof(ecc_oid_t),
+        ecc_oid_secp192k1_sz,
         ECC_SECP192K1_OID,                                  /* oid sum    */
         1,                                                  /* cofactor   */
@@ -682,5 +860,5 @@
         "14B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F", /* Gy         */
         ecc_oid_brainpoolp192r1,                            /* oid/oidSz  */
-        sizeof(ecc_oid_brainpoolp192r1) / sizeof(ecc_oid_t),
+        ecc_oid_brainpoolp192r1_sz,
         ECC_BRAINPOOLP192R1_OID,                            /* oid sum    */
         1,                                                  /* cofactor   */
@@ -701,5 +879,5 @@
         "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34", /* Gy         */
         ecc_oid_secp224r1,                                          /* oid/oidSz  */
-        sizeof(ecc_oid_secp224r1) / sizeof(ecc_oid_t),
+        ecc_oid_secp224r1_sz,
         ECC_SECP224R1_OID,                                          /* oid sum    */
         1,                                                          /* cofactor   */
@@ -718,5 +896,5 @@
         "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5", /* Gy         */
         ecc_oid_secp224k1,                                          /* oid/oidSz  */
-        sizeof(ecc_oid_secp224k1) / sizeof(ecc_oid_t),
+        ecc_oid_secp224k1_sz,
         ECC_SECP224K1_OID,                                          /* oid sum    */
         1,                                                          /* cofactor   */
@@ -735,5 +913,5 @@
         "58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD", /* Gy         */
         ecc_oid_brainpoolp224r1,                                    /* oid/oidSz  */
-        sizeof(ecc_oid_brainpoolp224r1) / sizeof(ecc_oid_t),
+        ecc_oid_brainpoolp224r1_sz,
         ECC_BRAINPOOLP224R1_OID,                                    /* oid sum    */
         1,                                                          /* cofactor   */
@@ -754,5 +932,5 @@
         "7DEBE8E4E90A5DAE6E4054CA530BA04654B36818CE226B39FCCB7B02F1AE", /* Gy         */
         ecc_oid_prime239v1,                                             /* oid/oidSz  */
-        sizeof(ecc_oid_prime239v1) / sizeof(ecc_oid_t),
+        ecc_oid_prime239v1_sz,
         ECC_PRIME239V1_OID,                                             /* oid sum    */
         1,                                                              /* cofactor   */
@@ -771,5 +949,5 @@
         "5B0125E4DBEA0EC7206DA0FC01D9B081329FB555DE6EF460237DFF8BE4BA", /* Gy         */
         ecc_oid_prime239v2,                                             /* oid/oidSz  */
-        sizeof(ecc_oid_prime239v2) / sizeof(ecc_oid_t),
+        ecc_oid_prime239v2_sz,
         ECC_PRIME239V2_OID,                                             /* oid sum    */
         1,                                                              /* cofactor   */
@@ -788,5 +966,5 @@
         "1607E6898F390C06BC1D552BAD226F3B6FCFE48B6E818499AF18E3ED6CF3", /* Gy         */
         ecc_oid_prime239v3,                                             /* oid/oidSz  */
-        sizeof(ecc_oid_prime239v3) / sizeof(ecc_oid_t),
+        ecc_oid_prime239v3_sz,
         ECC_PRIME239V3_OID,                                             /* oid sum    */
         1,                                                              /* cofactor   */
@@ -807,5 +985,5 @@
         "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", /* Gy         */
         ecc_oid_secp256r1,                                                  /* oid/oidSz  */
-        sizeof(ecc_oid_secp256r1) / sizeof(ecc_oid_t),
+        ecc_oid_secp256r1_sz,
         ECC_SECP256R1_OID,                                                  /* oid sum    */
         1,                                                                  /* cofactor   */
@@ -824,5 +1002,5 @@
         "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", /* Gy         */
         ecc_oid_secp256k1,                                                  /* oid/oidSz  */
-        sizeof(ecc_oid_secp256k1) / sizeof(ecc_oid_t),
+        ecc_oid_secp256k1_sz,
         ECC_SECP256K1_OID,                                                  /* oid sum    */
         1,                                                                  /* cofactor   */
@@ -841,5 +1019,5 @@
         "547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997", /* Gy         */
         ecc_oid_brainpoolp256r1,                                            /* oid/oidSz  */
-        sizeof(ecc_oid_brainpoolp256r1) / sizeof(ecc_oid_t),
+        ecc_oid_brainpoolp256r1_sz,
         ECC_BRAINPOOLP256R1_OID,                                            /* oid sum    */
         1,                                                                  /* cofactor   */
@@ -859,5 +1037,5 @@
         "43BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E20611", /* Gx         */
         "14FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1", /* Gy         */
-        ecc_oid_brainpoolp320r1, sizeof(ecc_oid_brainpoolp320r1) / sizeof(ecc_oid_t),       /* oid/oidSz  */
+        ecc_oid_brainpoolp320r1, ecc_oid_brainpoolp320r1_sz,                                /* oid/oidSz  */
         ECC_BRAINPOOLP320R1_OID,                                                            /* oid sum    */
         1,                                                                                  /* cofactor   */
@@ -877,5 +1055,5 @@
         "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7", /* Gx         */
         "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F", /* Gy         */
-        ecc_oid_secp384r1, sizeof(ecc_oid_secp384r1) / sizeof(ecc_oid_t),                                   /* oid/oidSz  */
+        ecc_oid_secp384r1, ecc_oid_secp384r1_sz,                                                            /* oid/oidSz  */
         ECC_SECP384R1_OID,                                                                                  /* oid sum    */
         1,                                                                                                  /* cofactor   */
@@ -893,5 +1071,5 @@
         "1D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E", /* Gx         */
         "8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315", /* Gy         */
-        ecc_oid_brainpoolp384r1, sizeof(ecc_oid_brainpoolp384r1) / sizeof(ecc_oid_t),                       /* oid/oidSz  */
+        ecc_oid_brainpoolp384r1, ecc_oid_brainpoolp384r1_sz,                                                /* oid/oidSz  */
         ECC_BRAINPOOLP384R1_OID,                                                                            /* oid sum    */
         1,                                                                                                  /* cofactor   */
@@ -911,5 +1089,5 @@
         "81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822", /* Gx         */
         "7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892", /* Gy         */
-        ecc_oid_brainpoolp512r1, sizeof(ecc_oid_brainpoolp512r1) / sizeof(ecc_oid_t),                                                       /* oid/oidSz  */
+        ecc_oid_brainpoolp512r1, ecc_oid_brainpoolp512r1_sz,                                                                                /* oid/oidSz  */
         ECC_BRAINPOOLP512R1_OID,                                                                                                            /* oid sum    */
         1,                                                                                                                                  /* cofactor   */
@@ -929,5 +1107,5 @@
         "C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66",  /* Gx         */
         "11839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650", /* Gy         */
-        ecc_oid_secp521r1, sizeof(ecc_oid_secp521r1) / sizeof(ecc_oid_t),                                                                      /* oid/oidSz  */
+        ecc_oid_secp521r1, ecc_oid_secp521r1_sz,                                                                                               /* oid/oidSz  */
         ECC_SECP521R1_OID,                                                                                                                     /* oid sum    */
         1,                                                                                                                                     /* cofactor   */
@@ -940,15 +1118,25 @@
         1, /* non-zero */
         ECC_CURVE_CUSTOM,
-        NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-        NULL, 0, 0, 0
+        #ifndef USE_WINDOWS_API
+            NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+        #else
+            {0},{0},{0},{0},{0},{0},{0},{0},
+        #endif
+        0, 0, 0
     },
 #endif
 {
-   0, -1,
-   NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-   NULL, 0, 0, 0
+        0,
+        ECC_CURVE_INVALID,
+        #ifndef USE_WINDOWS_API
+            NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+        #else
+            {0},{0},{0},{0},{0},{0},{0},{0},
+        #endif
+        0, 0, 0
 }
 };
 #define ECC_SET_COUNT   (sizeof(ecc_sets)/sizeof(ecc_set_type))
+
 
 #ifdef HAVE_OID_ENCODING
@@ -970,9 +1158,7 @@
 #else
 
+#if defined(WOLFSSL_VALIDATE_ECC_KEYGEN) || !defined(WOLFSSL_SP_MATH)
 static int ecc_check_pubkey_order(ecc_key* key, ecc_point* pubkey, mp_int* a,
         mp_int* prime, mp_int* order);
-#ifdef ECC_SHAMIR
-static int ecc_mul2add(ecc_point* A, mp_int* kA, ecc_point* B, mp_int* kB,
-                       ecc_point* C, mp_int* a, mp_int* modulus, void* heap);
 #endif
 
@@ -1038,7 +1224,25 @@
     #endif
 
-    #define DECLARE_CURVE_SPECS(intcount) ecc_curve_spec* curve = NULL;
+    #define DECLARE_CURVE_SPECS(curve, intcount) ecc_curve_spec* curve = NULL
+    #define ALLOC_CURVE_SPECS(intcount)
+    #define FREE_CURVE_SPECS()
+#elif defined(WOLFSSL_SMALL_STACK)
+    #define DECLARE_CURVE_SPECS(curve, intcount)                        \
+        mp_int* spec_ints = NULL;                                       \
+        ecc_curve_spec curve_lcl;                                       \
+        ecc_curve_spec* curve = &curve_lcl;                             \
+        XMEMSET(curve, 0, sizeof(ecc_curve_spec));                      \
+        curve->spec_count = intcount
+
+    #define ALLOC_CURVE_SPECS(intcount)                                 \
+        spec_ints = (mp_int*)XMALLOC(sizeof(mp_int) * (intcount), NULL, \
+                            DYNAMIC_TYPE_ECC);                          \
+        if (spec_ints == NULL)                                          \
+            return MEMORY_E;                                            \
+        curve->spec_ints = spec_ints
+    #define FREE_CURVE_SPECS()                                          \
+        XFREE(spec_ints, NULL, DYNAMIC_TYPE_ECC)
 #else
-    #define DECLARE_CURVE_SPECS(intcount) \
+    #define DECLARE_CURVE_SPECS(curve, intcount) \
         mp_int spec_ints[(intcount)]; \
         ecc_curve_spec curve_lcl; \
@@ -1046,5 +1250,7 @@
         XMEMSET(curve, 0, sizeof(ecc_curve_spec)); \
         curve->spec_ints = spec_ints; \
-        curve->spec_count = intcount;
+        curve->spec_count = intcount
+    #define ALLOC_CURVE_SPECS(intcount)
+    #define FREE_CURVE_SPECS()
 #endif /* ECC_CACHE_CURVE */
 
@@ -1100,5 +1306,5 @@
         curve->load_mask |= mask;
 
-        err = mp_read_radix(*dst, src, 16);
+        err = mp_read_radix(*dst, src, MP_RADIX_HEX);
 
     #ifdef HAVE_WOLF_BIGINT
@@ -1169,5 +1375,5 @@
 
     /* determine items to load */
-    load_items = (~curve->load_mask & load_mask);
+    load_items = (((byte)~(word32)curve->load_mask) & load_mask);
     curve->load_mask |= load_items;
 
@@ -1293,5 +1499,17 @@
 }
 
+
+#ifdef ALT_ECC_SIZE
+static void alt_fp_init(mp_int* a)
+{
+    a->size = FP_SIZE_ECC;
+    mp_zero(a);
+}
+#endif /* ALT_ECC_SIZE */
+
+
 #ifndef WOLFSSL_ATECC508A
+
+#if !defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_PUBLIC_ECC_ADD_DBL)
 
 /**
@@ -1308,7 +1526,18 @@
                              mp_int* a, mp_int* modulus, mp_digit mp)
 {
-   mp_int t1, t2;
+#ifndef WOLFSSL_SP_MATH
+#ifdef WOLFSSL_SMALL_STACK
+   mp_int* t1 = NULL;
+   mp_int* t2 = NULL;
 #ifdef ALT_ECC_SIZE
-   mp_int rx, ry, rz;
+   mp_int* rx = NULL;
+   mp_int* ry = NULL;
+   mp_int* rz = NULL;
+#endif
+#else
+   mp_int  t1[1], t2[1];
+#ifdef ALT_ECC_SIZE
+   mp_int  rx[1], ry[1], rz[1];
+#endif
 #endif
    mp_int *x, *y, *z;
@@ -1326,5 +1555,56 @@
    }
 
-   if ((err = mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) {
+#ifdef WOLFSSL_SMALL_STACK
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+   if (R->key != NULL) {
+       t1 = R->key->t1;
+       t2 = R->key->t2;
+#ifdef ALT_ECC_SIZE
+       rx = R->key->x;
+       ry = R->key->y;
+       rz = R->key->z;
+#endif
+   }
+   else
+#endif /* WOLFSSL_SMALL_STACK_CACHE */
+   {
+       t1 = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+       t2 = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+       if (t1 == NULL || t2 == NULL) {
+           XFREE(t1, NULL, DYNAMIC_TYPE_ECC);
+           XFREE(t2, NULL, DYNAMIC_TYPE_ECC);
+           return MEMORY_E;
+       }
+#ifdef ALT_ECC_SIZE
+       rx = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+       ry = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+       rz = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+       if (rx == NULL || ry == NULL || rz == NULL) {
+           XFREE(rz, NULL, DYNAMIC_TYPE_ECC);
+           XFREE(ry, NULL, DYNAMIC_TYPE_ECC);
+           XFREE(rx, NULL, DYNAMIC_TYPE_ECC);
+           XFREE(t2, NULL, DYNAMIC_TYPE_ECC);
+           XFREE(t1, NULL, DYNAMIC_TYPE_ECC);
+           return MEMORY_E;
+       }
+#endif
+   }
+#endif /* WOLFSSL_SMALL_STACK */
+
+   if ((err = mp_init_multi(t1, t2, NULL, NULL, NULL, NULL)) != MP_OKAY) {
+#ifdef WOLFSSL_SMALL_STACK
+   #ifdef WOLFSSL_SMALL_STACK_CACHE
+       if (R->key == NULL)
+   #endif
+       {
+       #ifdef ALT_ECC_SIZE
+          XFREE(rz, NULL, DYNAMIC_TYPE_ECC);
+          XFREE(ry, NULL, DYNAMIC_TYPE_ECC);
+          XFREE(rx, NULL, DYNAMIC_TYPE_ECC);
+       #endif
+          XFREE(t2, NULL, DYNAMIC_TYPE_ECC);
+          XFREE(t1, NULL, DYNAMIC_TYPE_ECC);
+       }
+#endif
       return err;
    }
@@ -1332,11 +1612,25 @@
    /* should we dbl instead? */
    if (err == MP_OKAY)
-       err = mp_sub(modulus, Q->y, &t1);
+       err = mp_sub(modulus, Q->y, t1);
    if (err == MP_OKAY) {
        if ( (mp_cmp(P->x, Q->x) == MP_EQ) &&
             (get_digit_count(Q->z) && mp_cmp(P->z, Q->z) == MP_EQ) &&
-            (mp_cmp(P->y, Q->y) == MP_EQ || mp_cmp(P->y, &t1) == MP_EQ)) {
-           mp_clear(&t1);
-           mp_clear(&t2);
+            (mp_cmp(P->y, Q->y) == MP_EQ || mp_cmp(P->y, t1) == MP_EQ)) {
+           mp_clear(t1);
+           mp_clear(t2);
+    #ifdef WOLFSSL_SMALL_STACK
+       #ifdef WOLFSSL_SMALL_STACK_CACHE
+           if (R->key == NULL)
+       #endif
+           {
+            #ifdef ALT_ECC_SIZE
+               XFREE(rz, NULL, DYNAMIC_TYPE_ECC);
+               XFREE(ry, NULL, DYNAMIC_TYPE_ECC);
+               XFREE(rx, NULL, DYNAMIC_TYPE_ECC);
+            #endif
+               XFREE(t2, NULL, DYNAMIC_TYPE_ECC);
+               XFREE(t1, NULL, DYNAMIC_TYPE_ECC);
+           }
+        #endif
           return ecc_projective_dbl_point(P, R, a, modulus, mp);
        }
@@ -1351,7 +1645,7 @@
 #ifdef ALT_ECC_SIZE
    /* Use local stack variable */
-   x = &rx;
-   y = &ry;
-   z = &rz;
+   x = rx;
+   y = ry;
+   z = rz;
 
    if ((err = mp_init_multi(x, y, z, NULL, NULL, NULL)) != MP_OKAY) {
@@ -1376,11 +1670,11 @@
        if (!mp_iszero(Q->z)) {
            /* T1 = Z' * Z' */
-           err = mp_sqr(Q->z, &t1);
+           err = mp_sqr(Q->z, t1);
            if (err == MP_OKAY)
-               err = mp_montgomery_reduce(&t1, modulus, mp);
+               err = mp_montgomery_reduce(t1, modulus, mp);
 
            /* X = X * T1 */
            if (err == MP_OKAY)
-               err = mp_mul(&t1, x, x);
+               err = mp_mul(t1, x, x);
            if (err == MP_OKAY)
                err = mp_montgomery_reduce(x, modulus, mp);
@@ -1388,11 +1682,11 @@
            /* T1 = Z' * T1 */
            if (err == MP_OKAY)
-               err = mp_mul(Q->z, &t1, &t1);
+               err = mp_mul(Q->z, t1, t1);
            if (err == MP_OKAY)
-               err = mp_montgomery_reduce(&t1, modulus, mp);
+               err = mp_montgomery_reduce(t1, modulus, mp);
 
            /* Y = Y * T1 */
            if (err == MP_OKAY)
-               err = mp_mul(&t1, y, y);
+               err = mp_mul(t1, y, y);
            if (err == MP_OKAY)
                err = mp_montgomery_reduce(y, modulus, mp);
@@ -1402,29 +1696,29 @@
    /* T1 = Z*Z */
    if (err == MP_OKAY)
-       err = mp_sqr(z, &t1);
-   if (err == MP_OKAY)
-       err = mp_montgomery_reduce(&t1, modulus, mp);
+       err = mp_sqr(z, t1);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(t1, modulus, mp);
 
    /* T2 = X' * T1 */
    if (err == MP_OKAY)
-       err = mp_mul(Q->x, &t1, &t2);
-   if (err == MP_OKAY)
-       err = mp_montgomery_reduce(&t2, modulus, mp);
+       err = mp_mul(Q->x, t1, t2);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(t2, modulus, mp);
 
    /* T1 = Z * T1 */
    if (err == MP_OKAY)
-       err = mp_mul(z, &t1, &t1);
-   if (err == MP_OKAY)
-       err = mp_montgomery_reduce(&t1, modulus, mp);
+       err = mp_mul(z, t1, t1);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(t1, modulus, mp);
 
    /* T1 = Y' * T1 */
    if (err == MP_OKAY)
-       err = mp_mul(Q->y, &t1, &t1);
-   if (err == MP_OKAY)
-       err = mp_montgomery_reduce(&t1, modulus, mp);
+       err = mp_mul(Q->y, t1, t1);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(t1, modulus, mp);
 
    /* Y = Y - T1 */
    if (err == MP_OKAY)
-       err = mp_sub(y, &t1, y);
+       err = mp_sub(y, t1, y);
    if (err == MP_OKAY) {
        if (mp_isneg(y))
@@ -1433,19 +1727,19 @@
    /* T1 = 2T1 */
    if (err == MP_OKAY)
-       err = mp_add(&t1, &t1, &t1);
+       err = mp_add(t1, t1, t1);
    if (err == MP_OKAY) {
-       if (mp_cmp(&t1, modulus) != MP_LT)
-           err = mp_sub(&t1, modulus, &t1);
+       if (mp_cmp(t1, modulus) != MP_LT)
+           err = mp_sub(t1, modulus, t1);
    }
    /* T1 = Y + T1 */
    if (err == MP_OKAY)
-       err = mp_add(&t1, y, &t1);
+       err = mp_add(t1, y, t1);
    if (err == MP_OKAY) {
-       if (mp_cmp(&t1, modulus) != MP_LT)
-           err = mp_sub(&t1, modulus, &t1);
+       if (mp_cmp(t1, modulus) != MP_LT)
+           err = mp_sub(t1, modulus, t1);
    }
    /* X = X - T2 */
    if (err == MP_OKAY)
-       err = mp_sub(x, &t2, x);
+       err = mp_sub(x, t2, x);
    if (err == MP_OKAY) {
        if (mp_isneg(x))
@@ -1454,15 +1748,15 @@
    /* T2 = 2T2 */
    if (err == MP_OKAY)
-       err = mp_add(&t2, &t2, &t2);
+       err = mp_add(t2, t2, t2);
    if (err == MP_OKAY) {
-       if (mp_cmp(&t2, modulus) != MP_LT)
-           err = mp_sub(&t2, modulus, &t2);
+       if (mp_cmp(t2, modulus) != MP_LT)
+           err = mp_sub(t2, modulus, t2);
    }
    /* T2 = X + T2 */
    if (err == MP_OKAY)
-       err = mp_add(&t2, x, &t2);
+       err = mp_add(t2, x, t2);
    if (err == MP_OKAY) {
-       if (mp_cmp(&t2, modulus) != MP_LT)
-           err = mp_sub(&t2, modulus, &t2);
+       if (mp_cmp(t2, modulus) != MP_LT)
+           err = mp_sub(t2, modulus, t2);
    }
 
@@ -1484,7 +1778,7 @@
    /* T1 = T1 * X  */
    if (err == MP_OKAY)
-       err = mp_mul(&t1, x, &t1);
-   if (err == MP_OKAY)
-       err = mp_montgomery_reduce(&t1, modulus, mp);
+       err = mp_mul(t1, x, t1);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(t1, modulus, mp);
 
    /* X = X * X */
@@ -1496,13 +1790,13 @@
    /* T2 = T2 * x */
    if (err == MP_OKAY)
-       err = mp_mul(&t2, x, &t2);
-   if (err == MP_OKAY)
-       err = mp_montgomery_reduce(&t2, modulus, mp);
+       err = mp_mul(t2, x, t2);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(t2, modulus, mp);
 
    /* T1 = T1 * X  */
    if (err == MP_OKAY)
-       err = mp_mul(&t1, x, &t1);
-   if (err == MP_OKAY)
-       err = mp_montgomery_reduce(&t1, modulus, mp);
+       err = mp_mul(t1, x, t1);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(t1, modulus, mp);
 
    /* X = Y*Y */
@@ -1514,5 +1808,5 @@
    /* X = X - T2 */
    if (err == MP_OKAY)
-       err = mp_sub(x, &t2, x);
+       err = mp_sub(x, t2, x);
    if (err == MP_OKAY) {
        if (mp_isneg(x))
@@ -1521,25 +1815,25 @@
    /* T2 = T2 - X */
    if (err == MP_OKAY)
-       err = mp_sub(&t2, x, &t2);
+       err = mp_sub(t2, x, t2);
    if (err == MP_OKAY) {
-       if (mp_isneg(&t2))
-           err = mp_add(&t2, modulus, &t2);
+       if (mp_isneg(t2))
+           err = mp_add(t2, modulus, t2);
    }
    /* T2 = T2 - X */
    if (err == MP_OKAY)
-       err = mp_sub(&t2, x, &t2);
+       err = mp_sub(t2, x, t2);
    if (err == MP_OKAY) {
-       if (mp_isneg(&t2))
-           err = mp_add(&t2, modulus, &t2);
+       if (mp_isneg(t2))
+           err = mp_add(t2, modulus, t2);
    }
    /* T2 = T2 * Y */
    if (err == MP_OKAY)
-       err = mp_mul(&t2, y, &t2);
-   if (err == MP_OKAY)
-       err = mp_montgomery_reduce(&t2, modulus, mp);
+       err = mp_mul(t2, y, t2);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(t2, modulus, mp);
 
    /* Y = T2 - T1 */
    if (err == MP_OKAY)
-       err = mp_sub(&t2, &t1, y);
+       err = mp_sub(t2, t1, y);
    if (err == MP_OKAY) {
        if (mp_isneg(y))
@@ -1566,8 +1860,33 @@
 
    /* clean up */
-   mp_clear(&t1);
-   mp_clear(&t2);
+   mp_clear(t1);
+   mp_clear(t2);
+#ifdef WOLFSSL_SMALL_STACK
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+   if (R->key == NULL)
+#endif
+   {
+   #ifdef ALT_ECC_SIZE
+      XFREE(rz, NULL, DYNAMIC_TYPE_ECC);
+      XFREE(ry, NULL, DYNAMIC_TYPE_ECC);
+      XFREE(rx, NULL, DYNAMIC_TYPE_ECC);
+   #endif
+      XFREE(t2, NULL, DYNAMIC_TYPE_ECC);
+      XFREE(t1, NULL, DYNAMIC_TYPE_ECC);
+   }
+#endif
 
    return err;
+#else
+    if (P == NULL || Q == NULL || R == NULL || modulus == NULL) {
+        return ECC_BAD_ARG_E;
+    }
+
+    (void)a;
+    (void)mp;
+
+    return sp_ecc_proj_add_point_256(P->x, P->y, P->z, Q->x, Q->y, Q->z,
+                                     R->x, R->y, R->z);
+#endif
 }
 
@@ -1602,7 +1921,18 @@
                                        mp_int* modulus, mp_digit mp)
 {
-   mp_int t1, t2;
+#ifndef WOLFSSL_SP_MATH
+#ifdef WOLFSSL_SMALL_STACK
+   mp_int* t1 = NULL;
+   mp_int* t2 = NULL;
 #ifdef ALT_ECC_SIZE
-   mp_int rx, ry, rz;
+   mp_int* rx = NULL;
+   mp_int* ry = NULL;
+   mp_int* rz = NULL;
+#endif
+#else
+   mp_int  t1[1], t2[1];
+#ifdef ALT_ECC_SIZE
+   mp_int  rx[1], ry[1], rz[1];
+#endif
 #endif
    mp_int *x, *y, *z;
@@ -1612,5 +1942,56 @@
        return ECC_BAD_ARG_E;
 
-   if ((err = mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) {
+#ifdef WOLFSSL_SMALL_STACK
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+   if (R->key != NULL) {
+       t1 = R->key->t1;
+       t2 = R->key->t2;
+   #ifdef ALT_ECC_SIZE
+       rx = R->key->x;
+       ry = R->key->y;
+       rz = R->key->z;
+   #endif
+   }
+   else
+#endif /* WOLFSSL_SMALL_STACK_CACHE */
+   {
+       t1 = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+       t2 = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+       if (t1 == NULL || t2 == NULL) {
+           XFREE(t2, NULL, DYNAMIC_TYPE_ECC);
+           XFREE(t1, NULL, DYNAMIC_TYPE_ECC);
+           return MEMORY_E;
+       }
+    #ifdef ALT_ECC_SIZE
+       rx = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+       ry = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+       rz = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+       if (rx == NULL || ry == NULL || rz == NULL) {
+           XFREE(rz, NULL, DYNAMIC_TYPE_ECC);
+           XFREE(ry, NULL, DYNAMIC_TYPE_ECC);
+           XFREE(rx, NULL, DYNAMIC_TYPE_ECC);
+           XFREE(t2, NULL, DYNAMIC_TYPE_ECC);
+           XFREE(t1, NULL, DYNAMIC_TYPE_ECC);
+           return MEMORY_E;
+       }
+    #endif
+    }
+#endif
+
+   if ((err = mp_init_multi(t1, t2, NULL, NULL, NULL, NULL)) != MP_OKAY) {
+#ifdef WOLFSSL_SMALL_STACK
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+    if (R->key == NULL)
+#endif
+    {
+    #ifdef ALT_ECC_SIZE
+       XFREE(rz, NULL, DYNAMIC_TYPE_ECC);
+       XFREE(ry, NULL, DYNAMIC_TYPE_ECC);
+       XFREE(rx, NULL, DYNAMIC_TYPE_ECC);
+    #endif
+       XFREE(t2, NULL, DYNAMIC_TYPE_ECC);
+       XFREE(t1, NULL, DYNAMIC_TYPE_ECC);
+     }
+#endif
       return err;
    }
@@ -1620,11 +2001,25 @@
 #ifdef ALT_ECC_SIZE
    /* Use local stack variable */
-   x = &rx;
-   y = &ry;
-   z = &rz;
+   x = rx;
+   y = ry;
+   z = rz;
 
    if ((err = mp_init_multi(x, y, z, NULL, NULL, NULL)) != MP_OKAY) {
-       mp_clear(&t1);
-       mp_clear(&t2);
+       mp_clear(t1);
+       mp_clear(t2);
+    #ifdef WOLFSSL_SMALL_STACK
+    #ifdef WOLFSSL_SMALL_STACK_CACHE
+       if (R->key == NULL)
+    #endif
+       {
+       #ifdef ALT_ECC_SIZE
+          XFREE(rz, NULL, DYNAMIC_TYPE_ECC);
+          XFREE(ry, NULL, DYNAMIC_TYPE_ECC);
+          XFREE(rx, NULL, DYNAMIC_TYPE_ECC);
+       #endif
+          XFREE(t2, NULL, DYNAMIC_TYPE_ECC);
+          XFREE(t1, NULL, DYNAMIC_TYPE_ECC);
+       }
+    #endif
        return err;
    }
@@ -1645,7 +2040,7 @@
    /* T1 = Z * Z */
    if (err == MP_OKAY)
-       err = mp_sqr(z, &t1);
-   if (err == MP_OKAY)
-       err = mp_montgomery_reduce(&t1, modulus, mp);
+       err = mp_sqr(z, t1);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(t1, modulus, mp);
 
    /* Z = Y * Z */
@@ -1667,42 +2062,42 @@
    if (err == MP_OKAY) {
       /* Use a and prime to determine if a == 3 */
-      err = mp_submod(modulus, a, modulus, &t2);
-   }
-   if (err == MP_OKAY && mp_cmp_d(&t2, 3) != MP_EQ) {
+      err = mp_submod(modulus, a, modulus, t2);
+   }
+   if (err == MP_OKAY && mp_cmp_d(t2, 3) != MP_EQ) {
       /* use "a" in calc */
 
       /* T2 = T1 * T1 */
       if (err == MP_OKAY)
-          err = mp_sqr(&t1, &t2);
+          err = mp_sqr(t1, t2);
       if (err == MP_OKAY)
-          err = mp_montgomery_reduce(&t2, modulus, mp);
+          err = mp_montgomery_reduce(t2, modulus, mp);
       /* T1 = T2 * a */
       if (err == MP_OKAY)
-          err = mp_mulmod(&t2, a, modulus, &t1);
+          err = mp_mulmod(t2, a, modulus, t1);
       /* T2 = X * X */
       if (err == MP_OKAY)
-          err = mp_sqr(x, &t2);
+          err = mp_sqr(x, t2);
       if (err == MP_OKAY)
-          err = mp_montgomery_reduce(&t2, modulus, mp);
+          err = mp_montgomery_reduce(t2, modulus, mp);
       /* T1 = T2 + T1 */
       if (err == MP_OKAY)
-          err = mp_add(&t1, &t2, &t1);
+          err = mp_add(t1, t2, t1);
       if (err == MP_OKAY) {
-         if (mp_cmp(&t1, modulus) != MP_LT)
-            err = mp_sub(&t1, modulus, &t1);
+         if (mp_cmp(t1, modulus) != MP_LT)
+            err = mp_sub(t1, modulus, t1);
       }
       /* T1 = T2 + T1 */
       if (err == MP_OKAY)
-          err = mp_add(&t1, &t2, &t1);
+          err = mp_add(t1, t2, t1);
       if (err == MP_OKAY) {
-          if (mp_cmp(&t1, modulus) != MP_LT)
-              err = mp_sub(&t1, modulus, &t1);
+          if (mp_cmp(t1, modulus) != MP_LT)
+              err = mp_sub(t1, modulus, t1);
       }
       /* T1 = T2 + T1 */
       if (err == MP_OKAY)
-          err = mp_add(&t1, &t2, &t1);
+          err = mp_add(t1, t2, t1);
       if (err == MP_OKAY) {
-         if (mp_cmp(&t1, modulus) != MP_LT)
-            err = mp_sub(&t1, modulus, &t1);
+         if (mp_cmp(t1, modulus) != MP_LT)
+            err = mp_sub(t1, modulus, t1);
       }
    }
@@ -1715,35 +2110,35 @@
       /* T2 = X - T1 */
       if (err == MP_OKAY)
-          err = mp_sub(x, &t1, &t2);
+          err = mp_sub(x, t1, t2);
       if (err == MP_OKAY) {
-          if (mp_isneg(&t2))
-              err = mp_add(&t2, modulus, &t2);
+          if (mp_isneg(t2))
+              err = mp_add(t2, modulus, t2);
       }
       /* T1 = X + T1 */
       if (err == MP_OKAY)
-          err = mp_add(&t1, x, &t1);
+          err = mp_add(t1, x, t1);
       if (err == MP_OKAY) {
-          if (mp_cmp(&t1, modulus) != MP_LT)
-              err = mp_sub(&t1, modulus, &t1);
+          if (mp_cmp(t1, modulus) != MP_LT)
+              err = mp_sub(t1, modulus, t1);
       }
       /* T2 = T1 * T2 */
       if (err == MP_OKAY)
-          err = mp_mul(&t1, &t2, &t2);
+          err = mp_mul(t1, t2, t2);
       if (err == MP_OKAY)
-          err = mp_montgomery_reduce(&t2, modulus, mp);
+          err = mp_montgomery_reduce(t2, modulus, mp);
 
       /* T1 = 2T2 */
       if (err == MP_OKAY)
-          err = mp_add(&t2, &t2, &t1);
+          err = mp_add(t2, t2, t1);
       if (err == MP_OKAY) {
-          if (mp_cmp(&t1, modulus) != MP_LT)
-              err = mp_sub(&t1, modulus, &t1);
+          if (mp_cmp(t1, modulus) != MP_LT)
+              err = mp_sub(t1, modulus, t1);
       }
       /* T1 = T1 + T2 */
       if (err == MP_OKAY)
-          err = mp_add(&t1, &t2, &t1);
+          err = mp_add(t1, t2, t1);
       if (err == MP_OKAY) {
-          if (mp_cmp(&t1, modulus) != MP_LT)
-              err = mp_sub(&t1, modulus, &t1);
+          if (mp_cmp(t1, modulus) != MP_LT)
+              err = mp_sub(t1, modulus, t1);
       }
    }
@@ -1764,15 +2159,15 @@
    /* T2 = Y * Y */
    if (err == MP_OKAY)
-       err = mp_sqr(y, &t2);
-   if (err == MP_OKAY)
-       err = mp_montgomery_reduce(&t2, modulus, mp);
+       err = mp_sqr(y, t2);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(t2, modulus, mp);
 
    /* T2 = T2/2 */
    if (err == MP_OKAY) {
-       if (mp_isodd(&t2) == MP_YES)
-           err = mp_add(&t2, modulus, &t2);
-   }
-   if (err == MP_OKAY)
-       err = mp_div_2(&t2, &t2);
+       if (mp_isodd(t2) == MP_YES)
+           err = mp_add(t2, modulus, t2);
+   }
+   if (err == MP_OKAY)
+       err = mp_div_2(t2, t2);
 
    /* Y = Y * X */
@@ -1784,5 +2179,5 @@
    /* X = T1 * T1 */
    if (err == MP_OKAY)
-       err = mp_sqr(&t1, x);
+       err = mp_sqr(t1, x);
    if (err == MP_OKAY)
        err = mp_montgomery_reduce(x, modulus, mp);
@@ -1812,5 +2207,5 @@
    /* Y = Y * T1 */
    if (err == MP_OKAY)
-       err = mp_mul(y, &t1, y);
+       err = mp_mul(y, t1, y);
    if (err == MP_OKAY)
        err = mp_montgomery_reduce(y, modulus, mp);
@@ -1818,5 +2213,5 @@
    /* Y = Y - T2 */
    if (err == MP_OKAY)
-       err = mp_sub(y, &t2, y);
+       err = mp_sub(y, t2, y);
    if (err == MP_OKAY) {
        if (mp_isneg(y))
@@ -1834,8 +2229,32 @@
 
    /* clean up */
-   mp_clear(&t1);
-   mp_clear(&t2);
+   mp_clear(t1);
+   mp_clear(t2);
+
+#ifdef WOLFSSL_SMALL_STACK
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+   if (R->key == NULL)
+#endif
+   {
+    #ifdef ALT_ECC_SIZE
+       XFREE(rz, NULL, DYNAMIC_TYPE_ECC);
+       XFREE(ry, NULL, DYNAMIC_TYPE_ECC);
+       XFREE(rx, NULL, DYNAMIC_TYPE_ECC);
+    #endif
+       XFREE(t2, NULL, DYNAMIC_TYPE_ECC);
+       XFREE(t1, NULL, DYNAMIC_TYPE_ECC);
+    }
+#endif
 
    return err;
+#else
+    if (P == NULL || R == NULL || modulus == NULL)
+        return ECC_BAD_ARG_E;
+
+    (void)a;
+    (void)mp;
+
+    return sp_ecc_proj_dbl_point_256(P->x, P->y, P->z, R->x, R->y, R->z);
+#endif
 }
 
@@ -1850,8 +2269,19 @@
 int ecc_map(ecc_point* P, mp_int* modulus, mp_digit mp)
 {
-   mp_int t1, t2;
+#ifndef WOLFSSL_SP_MATH
+#ifdef WOLFSSL_SMALL_STACK
+   mp_int* t1 = NULL;
+   mp_int* t2 = NULL;
 #ifdef ALT_ECC_SIZE
-   mp_int rx, ry, rz;
-#endif
+   mp_int* rx = NULL;
+   mp_int* ry = NULL;
+   mp_int* rz = NULL;
+#endif
+#else
+   mp_int  t1[1], t2[1];
+#ifdef ALT_ECC_SIZE
+   mp_int  rx[1], ry[1], rz[1];
+#endif
+#endif /* WOLFSSL_SMALL_STACK */
    mp_int *x, *y, *z;
    int    err;
@@ -1870,5 +2300,56 @@
    }
 
-   if ((err = mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) {
+#ifdef WOLFSSL_SMALL_STACK
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+   if (P->key != NULL) {
+       t1 = P->key->t1;
+       t2 = P->key->t2;
+   #ifdef ALT_ECC_SIZE
+       rx = P->key->x;
+       ry = P->key->y;
+       rz = P->key->z;
+   #endif
+   }
+   else
+#endif /* WOLFSSL_SMALL_STACK_CACHE */
+   {
+       t1 = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+       t2 = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+       if (t1 == NULL || t2 == NULL) {
+           XFREE(t2, NULL, DYNAMIC_TYPE_ECC);
+           XFREE(t1, NULL, DYNAMIC_TYPE_ECC);
+           return MEMORY_E;
+       }
+#ifdef ALT_ECC_SIZE
+       rx = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+       ry = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+       rz = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+       if (rx == NULL || ry == NULL || rz == NULL) {
+           XFREE(rz, NULL, DYNAMIC_TYPE_ECC);
+           XFREE(ry, NULL, DYNAMIC_TYPE_ECC);
+           XFREE(rx, NULL, DYNAMIC_TYPE_ECC);
+           XFREE(t2, NULL, DYNAMIC_TYPE_ECC);
+           XFREE(t1, NULL, DYNAMIC_TYPE_ECC);
+           return MEMORY_E;
+       }
+#endif
+   }
+#endif /* WOLFSSL_SMALL_STACK */
+
+   if ((err = mp_init_multi(t1, t2, NULL, NULL, NULL, NULL)) != MP_OKAY) {
+#ifdef WOLFSSL_SMALL_STACK
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+      if (P->key == NULL)
+#endif
+      {
+      #ifdef ALT_ECC_SIZE
+         XFREE(rz, NULL, DYNAMIC_TYPE_ECC);
+         XFREE(ry, NULL, DYNAMIC_TYPE_ECC);
+         XFREE(rx, NULL, DYNAMIC_TYPE_ECC);
+      #endif
+         XFREE(t2, NULL, DYNAMIC_TYPE_ECC);
+         XFREE(t1, NULL, DYNAMIC_TYPE_ECC);
+      }
+#endif
       return MEMORY_E;
    }
@@ -1876,7 +2357,7 @@
 #ifdef ALT_ECC_SIZE
    /* Use local stack variable */
-   x = &rx;
-   y = &ry;
-   z = &rz;
+   x = rx;
+   y = ry;
+   z = rz;
 
    if ((err = mp_init_multi(x, y, z, NULL, NULL, NULL)) != MP_OKAY) {
@@ -1906,23 +2387,23 @@
    /* get 1/z */
    if (err == MP_OKAY)
-       err = mp_invmod(z, modulus, &t1);
+       err = mp_invmod(z, modulus, t1);
 
    /* get 1/z^2 and 1/z^3 */
    if (err == MP_OKAY)
-       err = mp_sqr(&t1, &t2);
-   if (err == MP_OKAY)
-       err = mp_mod(&t2, modulus, &t2);
-   if (err == MP_OKAY)
-       err = mp_mul(&t1, &t2, &t1);
-   if (err == MP_OKAY)
-       err = mp_mod(&t1, modulus, &t1);
+       err = mp_sqr(t1, t2);
+   if (err == MP_OKAY)
+       err = mp_mod(t2, modulus, t2);
+   if (err == MP_OKAY)
+       err = mp_mul(t1, t2, t1);
+   if (err == MP_OKAY)
+       err = mp_mod(t1, modulus, t1);
 
    /* multiply against x/y */
    if (err == MP_OKAY)
-       err = mp_mul(x, &t2, x);
+       err = mp_mul(x, t2, x);
    if (err == MP_OKAY)
        err = mp_montgomery_reduce(x, modulus, mp);
    if (err == MP_OKAY)
-       err = mp_mul(y, &t1, y);
+       err = mp_mul(y, t1, y);
    if (err == MP_OKAY)
        err = mp_montgomery_reduce(y, modulus, mp);
@@ -1944,12 +2425,38 @@
 
    /* clean up */
-   mp_clear(&t1);
-   mp_clear(&t2);
+   mp_clear(t1);
+   mp_clear(t2);
+
+#ifdef WOLFSSL_SMALL_STACK
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+   if (P->key == NULL)
+#endif
+   {
+   #ifdef ALT_ECC_SIZE
+      XFREE(rz, NULL, DYNAMIC_TYPE_ECC);
+      XFREE(ry, NULL, DYNAMIC_TYPE_ECC);
+      XFREE(rx, NULL, DYNAMIC_TYPE_ECC);
+   #endif
+      XFREE(t2, NULL, DYNAMIC_TYPE_ECC);
+      XFREE(t1, NULL, DYNAMIC_TYPE_ECC);
+}
+#endif
 
    return err;
-}
+#else
+    if (P == NULL || modulus == NULL)
+        return ECC_BAD_ARG_E;
+
+    (void)mp;
+
+    return sp_ecc_map_256(P->x, P->y, P->z);
+#endif
+}
+
+#endif /* !WOLFSSL_SP_MATH || WOLFSSL_PUBLIC_ECC_ADD_DBL */
 
 #if !defined(FREESCALE_LTC_ECC)
 
+#if !defined(FP_ECC) || !defined(WOLFSSL_SP_MATH)
 /**
    Perform a point multiplication
@@ -1973,4 +2480,5 @@
 #endif
 {
+#ifndef WOLFSSL_SP_MATH
 #ifndef ECC_TIMING_RESISTANT
    /* size of sliding window, don't change this! */
@@ -1984,5 +2492,12 @@
    ecc_point     *tG, *M[M_POINTS];
    int           i, err;
-   mp_int        mu;
+#ifdef WOLFSSL_SMALL_STACK
+   mp_int*       mu = NULL;
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+   ecc_key       key;
+#endif
+#else
+   mp_int        mu[1];
+#endif
    mp_digit      mp;
    mp_digit      buf;
@@ -1996,15 +2511,80 @@
    tG = NULL;
    XMEMSET(M, 0, sizeof(M));
+#ifdef WOLFSSL_SMALL_STACK
+   mu = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC);
+   if (mu == NULL)
+       return MEMORY_E;
+#endif
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+   key.t1 = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC);
+   key.t2 = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC);
+#ifdef ALT_ECC_SIZE
+   key.x = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC);
+   key.y = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC);
+   key.z = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC);
+#endif
+   if (key.t1 == NULL || key.t2 == NULL
+#ifdef ALT_ECC_SIZE
+      || key.x == NULL || key.y == NULL || key.z == NULL
+#endif
+   ) {
+#ifdef ALT_ECC_SIZE
+       XFREE(key.z, heap, DYNAMIC_TYPE_ECC);
+       XFREE(key.y, heap, DYNAMIC_TYPE_ECC);
+       XFREE(key.x, heap, DYNAMIC_TYPE_ECC);
+#endif
+       XFREE(key.t2, heap, DYNAMIC_TYPE_ECC);
+       XFREE(key.t1, heap, DYNAMIC_TYPE_ECC);
+       XFREE(mu, heap, DYNAMIC_TYPE_ECC);
+       return MEMORY_E;
+   }
+#endif /* WOLFSSL_SMALL_STACK_CACHE */
 
    /* init montgomery reduction */
    if ((err = mp_montgomery_setup(modulus, &mp)) != MP_OKAY) {
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+#ifdef ALT_ECC_SIZE
+       XFREE(key.z, heap, DYNAMIC_TYPE_ECC);
+       XFREE(key.y, heap, DYNAMIC_TYPE_ECC);
+       XFREE(key.x, heap, DYNAMIC_TYPE_ECC);
+#endif
+       XFREE(key.t2, heap, DYNAMIC_TYPE_ECC);
+       XFREE(key.t1, heap, DYNAMIC_TYPE_ECC);
+#endif /* WOLFSSL_SMALL_STACK_CACHE */
+#ifdef WOLFSSL_SMALL_STACK
+       XFREE(mu, heap, DYNAMIC_TYPE_ECC);
+#endif
        return err;
    }
 
-   if ((err = mp_init(&mu)) != MP_OKAY) {
+   if ((err = mp_init(mu)) != MP_OKAY) {
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+#ifdef ALT_ECC_SIZE
+       XFREE(key.z, heap, DYNAMIC_TYPE_ECC);
+       XFREE(key.y, heap, DYNAMIC_TYPE_ECC);
+       XFREE(key.x, heap, DYNAMIC_TYPE_ECC);
+#endif
+       XFREE(key.t2, heap, DYNAMIC_TYPE_ECC);
+       XFREE(key.t1, heap, DYNAMIC_TYPE_ECC);
+#endif /* WOLFSSL_SMALL_STACK_CACHE */
+#ifdef WOLFSSL_SMALL_STACK
+       XFREE(mu, heap, DYNAMIC_TYPE_ECC);
+#endif
        return err;
    }
-   if ((err = mp_montgomery_calc_normalization(&mu, modulus)) != MP_OKAY) {
-       mp_clear(&mu);
+   if ((err = mp_montgomery_calc_normalization(mu, modulus)) != MP_OKAY) {
+       mp_clear(mu);
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+#ifdef ALT_ECC_SIZE
+       XFREE(key.z, heap, DYNAMIC_TYPE_ECC);
+       XFREE(key.y, heap, DYNAMIC_TYPE_ECC);
+       XFREE(key.x, heap, DYNAMIC_TYPE_ECC);
+#endif
+       XFREE(key.t2, heap, DYNAMIC_TYPE_ECC);
+       XFREE(key.t1, heap, DYNAMIC_TYPE_ECC);
+#endif /* WOLFSSL_SMALL_STACK_CACHE */
+#ifdef WOLFSSL_SMALL_STACK
+       XFREE(mu, heap, DYNAMIC_TYPE_ECC);
+#endif
        return err;
    }
@@ -2014,7 +2594,10 @@
       M[i] = wc_ecc_new_point_h(heap);
       if (M[i] == NULL) {
-         mp_clear(&mu);
+         mp_clear(mu);
          err = MEMORY_E; goto exit;
       }
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+      M[i]->key = &key;
+#endif
   }
 
@@ -2026,5 +2609,5 @@
    /* tG = G  and convert to montgomery */
    if (err == MP_OKAY) {
-       if (mp_cmp_d(&mu, 1) == MP_EQ) {
+       if (mp_cmp_d(mu, 1) == MP_EQ) {
            err = mp_copy(G->x, tG->x);
            if (err == MP_OKAY)
@@ -2033,15 +2616,18 @@
                err = mp_copy(G->z, tG->z);
        } else {
-           err = mp_mulmod(G->x, &mu, modulus, tG->x);
+           err = mp_mulmod(G->x, mu, modulus, tG->x);
            if (err == MP_OKAY)
-               err = mp_mulmod(G->y, &mu, modulus, tG->y);
+               err = mp_mulmod(G->y, mu, modulus, tG->y);
            if (err == MP_OKAY)
-               err = mp_mulmod(G->z, &mu, modulus, tG->z);
+               err = mp_mulmod(G->z, mu, modulus, tG->z);
        }
    }
 
    /* done with mu */
-   mp_clear(&mu);
-
+   mp_clear(mu);
+
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+   R->key = &key;
+#endif
 #ifndef ECC_TIMING_RESISTANT
 
@@ -2305,7 +2891,31 @@
        wc_ecc_del_point_h(M[i], heap);
    }
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+   R->key = NULL;
+#ifdef ALT_ECC_SIZE
+   XFREE(key.z, heap, DYNAMIC_TYPE_ECC);
+   XFREE(key.y, heap, DYNAMIC_TYPE_ECC);
+   XFREE(key.x, heap, DYNAMIC_TYPE_ECC);
+#endif
+   XFREE(key.t2, heap, DYNAMIC_TYPE_ECC);
+   XFREE(key.t1, heap, DYNAMIC_TYPE_ECC);
+#endif /* WOLFSSL_SMALL_STACK_CACHE */
+#ifdef WOLFSSL_SMALL_STACK
+   XFREE(mu, heap, DYNAMIC_TYPE_ECC);
+#endif
 
    return err;
-}
+#else
+   if (k == NULL || G == NULL || R == NULL || modulus == NULL) {
+       return ECC_BAD_ARG_E;
+}
+
+   (void)a;
+
+   return sp_ecc_mulmod_256(k, G, R, map, heap);
+#endif
+}
+
+#endif /* !FP_ECC || !WOLFSSL_SP_MATH */
 
 #endif /* !FREESCALE_LTC_ECC */
@@ -2327,15 +2937,5 @@
 }
 
-
-#ifdef ALT_ECC_SIZE
-
-static void alt_fp_init(fp_int* a)
-{
-    a->size = FP_SIZE_ECC;
-    fp_zero(a);
-}
-
-#endif /* ALT_ECC_SIZE */
-
+#endif /* !WOLFSSL_ATECC508A */
 
 /**
@@ -2346,4 +2946,6 @@
 {
    ecc_point* p;
+
+   (void)heap;
 
    p = (ecc_point*)XMALLOC(sizeof(ecc_point), heap, DYNAMIC_TYPE_ECC);
@@ -2455,6 +3057,4 @@
 }
 
-#endif /* !WOLFSSL_ATECC508A */
-
 
 /** Returns whether an ECC idx is valid or not
@@ -2588,20 +3188,41 @@
 {
     int err = MP_OKAY;
-    mp_int a, b;
+#ifdef WOLFSSL_SMALL_STACK
+    mp_int* a = NULL;
+    mp_int* b = NULL;
+#else
+    mp_int  a[1], b[1];
+#endif
 
     if (param == NULL || curveParam == NULL)
         return BAD_FUNC_ARG;
 
-    if ((err = mp_init_multi(&a, &b, NULL, NULL, NULL, NULL)) != MP_OKAY)
+#ifdef WOLFSSL_SMALL_STACK
+    a = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+    if (a == NULL)
+        return MEMORY_E;
+    b = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+    if (b == NULL) {
+        XFREE(a, NULL, DYNAMIC_TYPE_ECC);
+        return MEMORY_E;
+    }
+#endif
+
+    if ((err = mp_init_multi(a, b, NULL, NULL, NULL, NULL)) != MP_OKAY) {
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(a, NULL, DYNAMIC_TYPE_ECC);
+        XFREE(b, NULL, DYNAMIC_TYPE_ECC);
+    #endif
         return err;
+    }
 
     if (err == MP_OKAY)
-        err = mp_read_unsigned_bin(&a, param, paramSz);
+        err = mp_read_unsigned_bin(a, param, paramSz);
 
     if (err == MP_OKAY)
-        err = mp_read_radix(&b, curveParam, 16);
+        err = mp_read_radix(b, curveParam, MP_RADIX_HEX);
 
     if (err == MP_OKAY) {
-        if (mp_cmp(&a, &b) != MP_EQ) {
+        if (mp_cmp(a, b) != MP_EQ) {
             err = -1;
         } else {
@@ -2610,6 +3231,10 @@
     }
 
-    mp_clear(&a);
-    mp_clear(&b);
+    mp_clear(a);
+    mp_clear(b);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(b, NULL, DYNAMIC_TYPE_ECC);
+    XFREE(a, NULL, DYNAMIC_TYPE_ECC);
+#endif
 
     return err;
@@ -2672,4 +3297,75 @@
 }
 
+/* Returns the curve id that corresponds to a given OID,
+ * as listed in ecc_sets[] of ecc.c.
+ *
+ * oid   OID, from ecc_sets[].name in ecc.c
+ * len   OID len, from ecc_sets[].name in ecc.c
+ * return curve id, from ecc_sets[] on success, negative on error
+ */
+int wc_ecc_get_curve_id_from_oid(const byte* oid, word32 len)
+{
+    int curve_idx;
+
+    if (oid == NULL)
+        return BAD_FUNC_ARG;
+
+    for (curve_idx = 0; ecc_sets[curve_idx].size != 0; curve_idx++) {
+        if (ecc_sets[curve_idx].oid && ecc_sets[curve_idx].oidSz == len &&
+                              XMEMCMP(ecc_sets[curve_idx].oid, oid, len) == 0) {
+            break;
+        }
+    }
+    if (ecc_sets[curve_idx].size == 0) {
+        WOLFSSL_MSG("ecc_set curve name not found");
+        return ECC_CURVE_INVALID;
+    }
+
+    return ecc_sets[curve_idx].id;
+}
+
+
+#ifdef WOLFSSL_ASYNC_CRYPT
+static WC_INLINE int wc_ecc_alloc_mpint(ecc_key* key, mp_int** mp)
+{
+   if (key == NULL || mp == NULL)
+      return BAD_FUNC_ARG;
+   if (*mp == NULL) {
+      *mp = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_BIGINT);
+      if (*mp == NULL) {
+         return MEMORY_E;
+      }
+      XMEMSET(*mp, 0, sizeof(mp_int));
+   }
+   return 0;
+}
+static WC_INLINE void wc_ecc_free_mpint(ecc_key* key, mp_int** mp)
+{
+   if (key && mp && *mp) {
+      mp_clear(*mp);
+      XFREE(*mp, key->heap, DYNAMIC_TYPE_BIGINT);
+      *mp = NULL;
+   }
+}
+
+static int wc_ecc_alloc_async(ecc_key* key)
+{
+    int err = wc_ecc_alloc_mpint(key, &key->r);
+    if (err == 0)
+        err = wc_ecc_alloc_mpint(key, &key->s);
+    return err;
+}
+
+static void wc_ecc_free_async(ecc_key* key)
+{
+    wc_ecc_free_mpint(key, &key->r);
+    wc_ecc_free_mpint(key, &key->s);
+#ifdef HAVE_CAVIUM_V
+    wc_ecc_free_mpint(key, &key->e);
+    wc_ecc_free_mpint(key, &key->signK);
+#endif /* HAVE_CAVIUM_V */
+}
+#endif /* WOLFSSL_ASYNC_CRYPT */
+
 
 #ifdef HAVE_ECC_DHE
@@ -2693,4 +3389,12 @@
    }
 
+#ifdef WOLF_CRYPTO_DEV
+    if (private_key->devId != INVALID_DEVID) {
+        err = wc_CryptoDev_Ecdh(private_key, public_key, out, outlen);
+        if (err != NOT_COMPILED_IN)
+            return err;
+    }
+#endif
+
    /* type valid? */
    if (private_key->type != ECC_PRIVATEKEY &&
@@ -2711,10 +3415,15 @@
 
 #ifdef WOLFSSL_ATECC508A
-   err = atcatls_ecdh(private_key->slot, public_key->pubkey, out);
-   if (err != ATCA_SUCCESS) {
-      err = BAD_COND_E;
-   }
+   /* For SECP256R1 use hardware */
+   if (private_key->dp->id == ECC_SECP256R1) {
+       err = atmel_ecc_create_pms(private_key->slot, public_key->pubkey_raw, out);
    *outlen = private_key->dp->size;
+   }
+   else {
+      err = NOT_COMPILED_IN;
+   }
+
 #else
+
    err = wc_ecc_shared_secret_ex(private_key, &public_key->pubkey, out, outlen);
 #endif /* WOLFSSL_ATECC508A */
@@ -2730,6 +3439,8 @@
 {
     int err;
+#ifndef WOLFSSL_SP_MATH
     ecc_point* result = NULL;
     word32 x = 0;
+#endif
     mp_int* k = &private_key->k;
 #ifdef HAVE_ECC_CDH
@@ -2763,4 +3474,11 @@
 #endif
 #endif
+#ifdef WOLFSSL_SP_MATH
+    {
+        err = WC_KEY_SIZE_E;
+
+        (void)curve;
+    }
+#else
     {
         /* make new point */
@@ -2792,4 +3510,5 @@
         wc_ecc_del_point_h(result, private_key->heap);
     }
+#endif
 #ifdef HAVE_ECC_CDH
     if (k == &k_lcl)
@@ -2807,17 +3526,33 @@
     int err;
 
-#ifdef HAVE_CAVIUM
-    /* TODO: Not implemented - use software for now */
-    err = wc_ecc_shared_secret_gen_sync(private_key, point, out, outlen, curve);
-
-#elif defined(HAVE_INTEL_QA)
+#if defined(HAVE_CAVIUM_V) || defined(HAVE_INTEL_QA)
+#ifdef HAVE_CAVIUM_V
+    /* verify the curve is supported by hardware */
+    if (NitroxEccIsCurveSupported(private_key))
+#endif
+    {
+        word32 keySz = private_key->dp->size;
+
     /* sync public key x/y */
-    err = wc_ecc_curve_load(private_key->dp, &curve, ECC_CURVE_FIELD_BF);
+        err = wc_mp_to_bigint_sz(&private_key->k, &private_key->k.raw, keySz);
+        if (err == MP_OKAY)
+            err = wc_mp_to_bigint_sz(point->x, &point->x->raw, keySz);
+        if (err == MP_OKAY)
+            err = wc_mp_to_bigint_sz(point->y, &point->y->raw, keySz);
+    #ifdef HAVE_CAVIUM_V
+        /* allocate buffer for output */
     if (err == MP_OKAY)
-        err = wc_mp_to_bigint(&private_key->k, &private_key->k.raw);
+            err = wc_ecc_alloc_mpint(private_key, &private_key->e);
     if (err == MP_OKAY)
-        err = wc_mp_to_bigint(point->x, &point->x->raw);
+            err = wc_bigint_alloc(&private_key->e->raw,
+                NitroxEccGetSize(private_key)*2);
     if (err == MP_OKAY)
-        err = wc_mp_to_bigint(point->y, &point->y->raw);
+            err = NitroxEcdh(private_key,
+                &private_key->k.raw, &point->x->raw, &point->y->raw,
+                private_key->e->raw.buf, &private_key->e->raw.len,
+                &curve->prime->raw);
+    #else
+        if (err == MP_OKAY)
+            err = wc_ecc_curve_load(private_key->dp, &curve, ECC_CURVE_FIELD_BF);
     if (err == MP_OKAY)
         err = IntelQaEcdh(&private_key->asyncDev,
@@ -2826,5 +3561,8 @@
             &curve->Af->raw, &curve->Bf->raw, &curve->prime->raw,
             private_key->dp->cofactor);
-#else /* WOLFSSL_ASYNC_CRYPT_TEST */
+    #endif
+        return err;
+    }
+#elif defined(WOLFSSL_ASYNC_CRYPT_TEST)
     if (wc_AsyncTestInit(&private_key->asyncDev, ASYNC_TEST_ECC_SHARED_SEC)) {
         WC_ASYNC_TEST* testDev = &private_key->asyncDev.test;
@@ -2835,6 +3573,8 @@
         return WC_PENDING_E;
     }
+#endif
+
+    /* use sync in other cases */
     err = wc_ecc_shared_secret_gen_sync(private_key, point, out, outlen, curve);
-#endif
 
     return err;
@@ -2846,5 +3586,5 @@
 {
     int err;
-    DECLARE_CURVE_SPECS(2)
+    DECLARE_CURVE_SPECS(curve, 2);
 
     if (private_key == NULL || point == NULL || out == NULL ||
@@ -2853,9 +3593,13 @@
     }
 
+    ALLOC_CURVE_SPECS(2);
+
     /* load curve info */
     err = wc_ecc_curve_load(private_key->dp, &curve,
         (ECC_CURVE_FIELD_PRIME | ECC_CURVE_FIELD_AF));
-    if (err != MP_OKAY)
+    if (err != MP_OKAY) {
+        FREE_CURVE_SPECS();
         return err;
+    }
 
 #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC)
@@ -2872,4 +3616,5 @@
 
     wc_ecc_curve_free(curve);
+    FREE_CURVE_SPECS();
 
     return err;
@@ -2918,4 +3663,16 @@
         case ECC_STATE_SHARED_SEC_RES:
             private_key->state = ECC_STATE_SHARED_SEC_RES;
+        #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC)
+            if (private_key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_ECC) {
+            #ifdef HAVE_CAVIUM_V
+                /* verify the curve is supported by hardware */
+                if (NitroxEccIsCurveSupported(private_key)) {
+                    /* copy output */
+                    *outlen = private_key->dp->size;
+                    XMEMCPY(out, private_key->e->raw.buf, *outlen);
+                }
+            #endif /* HAVE_CAVIUM_V */
+            }
+        #endif /* WOLFSSL_ASYNC_CRYPT */
             err = 0;
             break;
@@ -2931,4 +3688,8 @@
     }
 
+    /* cleanup */
+#ifdef WOLFSSL_ASYNC_CRYPT
+    wc_ecc_free_async(private_key);
+#endif
     private_key->state = ECC_STATE_NONE;
 
@@ -2952,18 +3713,14 @@
 }
 
+#ifndef WOLFSSL_SP_MATH
 /* generate random and ensure its greater than 0 and less than order */
 static int wc_ecc_gen_k(WC_RNG* rng, int size, mp_int* k, mp_int* order)
 {
+#ifndef WC_NO_RNG
     int err;
-#ifdef WOLFSSL_SMALL_STACK
-    byte* buf;
+#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC)
+    DECLARE_VAR(buf, byte, ECC_MAXSIZE_GEN, rng->heap);
 #else
     byte  buf[ECC_MAXSIZE_GEN];
-#endif
-
-#ifdef WOLFSSL_SMALL_STACK
-    buf = (byte*)XMALLOC(ECC_MAXSIZE_GEN, NULL, DYNAMIC_TYPE_ECC_BUFFER);
-    if (buf == NULL)
-        return MEMORY_E;
 #endif
 
@@ -2978,10 +3735,4 @@
     if (err == 0)
         err = mp_read_unsigned_bin(k, (byte*)buf, size);
-
-    /* quick sanity check to make sure we're not dealing with a 0 key */
-    if (err == MP_OKAY) {
-        if (mp_iszero(k) == MP_YES)
-          err = MP_ZERO_E;
-    }
 
     /* the key should be smaller than the order of base point */
@@ -2992,14 +3743,28 @@
     }
 
+    /* quick sanity check to make sure we're not dealing with a 0 key */
+    if (err == MP_OKAY) {
+        if (mp_iszero(k) == MP_YES)
+          err = MP_ZERO_E;
+    }
+
     ForceZero(buf, ECC_MAXSIZE);
-#ifdef WOLFSSL_SMALL_STACK
-    XFREE(buf, NULL, DYNAMIC_TYPE_ECC_BUFFER);
+#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC)
+    FREE_VAR(buf, rng->heap);
 #endif
 
     return err;
-}
+#else
+    (void)rng;
+    (void)size;
+    (void)k;
+    (void)order;
+    return NOT_COMPILED_IN;
+#endif /* !WC_NO_RNG */
+}
+#endif /* WOLFSSL_SP_MATH */
 #endif /* !WOLFSSL_ATECC508A */
 
-static INLINE void wc_ecc_reset(ecc_key* key)
+static WC_INLINE void wc_ecc_reset(ecc_key* key)
 {
     /* make sure required key variables are reset */
@@ -3026,8 +3791,10 @@
     int err = MP_OKAY;
 #ifndef WOLFSSL_ATECC508A
+#ifndef WOLFSSL_SP_MATH
     ecc_point* base = NULL;
+#endif
     ecc_point* pub;
-    DECLARE_CURVE_SPECS(ECC_CURVE_FIELD_COUNT)
-#endif
+    DECLARE_CURVE_SPECS(curve, ECC_CURVE_FIELD_COUNT);
+#endif /* !WOLFSSL_ATECC508A */
 
     if (key == NULL) {
@@ -3036,4 +3803,5 @@
 
 #ifndef WOLFSSL_ATECC508A
+
     /* if ecc_point passed in then use it as output for public key point */
     if (pubOut != NULL) {
@@ -3052,4 +3820,6 @@
     }
     else {
+        ALLOC_CURVE_SPECS(ECC_CURVE_FIELD_COUNT);
+
         /* load curve info */
         if (err == MP_OKAY)
@@ -3080,4 +3850,7 @@
 #endif
 #endif
+#ifdef WOLFSSL_SP_MATH
+        err = WC_KEY_SIZE_E;
+#else
     {
         if (err == MP_OKAY) {
@@ -3102,4 +3875,5 @@
         wc_ecc_del_point_h(base, key->heap);
     }
+#endif
 
 #ifdef WOLFSSL_VALIDATE_ECC_KEYGEN
@@ -3122,6 +3896,9 @@
     if (curveIn == NULL) {
         wc_ecc_curve_free(curve);
-    }
-
+        FREE_CURVE_SPECS();
+    }
+
+#else
+    (void)curveIn;
 #endif /* WOLFSSL_ATECC508A */
 
@@ -3156,6 +3933,8 @@
     int            err;
 #ifndef WOLFSSL_ATECC508A
-    DECLARE_CURVE_SPECS(ECC_CURVE_FIELD_COUNT)
-#endif
+#ifndef WOLFSSL_SP_MATH
+    DECLARE_CURVE_SPECS(curve, ECC_CURVE_FIELD_COUNT);
+#endif
+#endif /* !WOLFSSL_ATECC508A */
 
     if (key == NULL || rng == NULL) {
@@ -3170,4 +3949,12 @@
         return err;
     }
+
+#ifdef WOLF_CRYPTO_DEV
+    if (key->devId != INVALID_DEVID) {
+        err = wc_CryptoDev_MakeEccKey(rng, keysize, key, curve_id);
+        if (err != NOT_COMPILED_IN)
+            return err;
+    }
+#endif
 
 #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC)
@@ -3188,11 +3975,21 @@
     #endif
     }
-#endif /* WOLFSSL_ASYNC_CRYPT */
+#endif /* WOLFSSL_ASYNC_CRYPT && WC_ASYNC_ENABLE_ECC */
 
 #ifdef WOLFSSL_ATECC508A
     key->type = ECC_PRIVATEKEY;
-    err = atcatls_create_key(key->slot, key->pubkey);
-    if (err != ATCA_SUCCESS)
-        err = BAD_COND_E;
+   key->slot = atmel_ecc_alloc(ATMEL_SLOT_ECDHE);
+   err = atmel_ecc_create_key(key->slot, key->pubkey_raw);
+
+   /* populate key->pubkey */
+   if (err == 0 && key->pubkey.x) {
+       err = mp_read_unsigned_bin(key->pubkey.x, key->pubkey_raw,
+                                  ECC_MAX_CRYPTO_HW_SIZE);
+   }
+   if (err == 0 && key->pubkey.y) {
+       err = mp_read_unsigned_bin(key->pubkey.y,
+                                  key->pubkey_raw + ECC_MAX_CRYPTO_HW_SIZE,
+                                  ECC_MAX_CRYPTO_HW_SIZE);
+   }
 #else
 
@@ -3206,6 +4003,12 @@
     else
 #endif
-#endif
-    {
+#endif /* WOLFSSL_HAVE_SP_ECC */
+
+   { /* software key gen */
+#ifdef WOLFSSL_SP_MATH
+        err = WC_KEY_SIZE_E;
+#else
+        ALLOC_CURVE_SPECS(ECC_CURVE_FIELD_COUNT);
+
         /* setup the key variables */
         err = mp_init(&key->k);
@@ -3234,5 +4037,18 @@
         /* cleanup allocations */
         wc_ecc_curve_free(curve);
-    }
+        FREE_CURVE_SPECS();
+#endif /* WOLFSSL_SP_MATH */
+    }
+
+#ifdef HAVE_WOLF_BIGINT
+    if (err == MP_OKAY)
+         err = wc_mp_to_bigint(&key->k, &key->k.raw);
+    if (err == MP_OKAY)
+         err = wc_mp_to_bigint(key->pubkey.x, &key->pubkey.x->raw);
+    if (err == MP_OKAY)
+         err = wc_mp_to_bigint(key->pubkey.y, &key->pubkey.y->raw);
+    if (err == MP_OKAY)
+         err = wc_mp_to_bigint(key->pubkey.z, &key->pubkey.z->raw);
+#endif
 
 #endif /* WOLFSSL_ATECC508A */
@@ -3311,64 +4127,4 @@
 }
 
-static INLINE int wc_ecc_alloc_rs(ecc_key* key, mp_int** r, mp_int** s)
-{
-    int err = 0;
-
-#ifndef WOLFSSL_ASYNC_CRYPT
-    (void)key;
-#endif
-
-    if (*r == NULL) {
-    #ifdef WOLFSSL_ASYNC_CRYPT
-        *r = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_BIGINT);
-        if (*r == NULL) {
-            return MEMORY_E;
-        }
-        key->r = *r;
-    #endif
-    }
-    if (*s == NULL) {
-    #ifdef WOLFSSL_ASYNC_CRYPT
-        *s = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_BIGINT);
-        if (*s == NULL) {
-            XFREE(*r, key->heap, DYNAMIC_TYPE_BIGINT);
-            return MEMORY_E;
-        }
-        key->s = *s;
-    #endif
-    }
-
-    /* initialize mp_int */
-    if (*r)
-        XMEMSET(*r, 0, sizeof(mp_int));
-    if (*s)
-        XMEMSET(*s, 0, sizeof(mp_int));
-
-    return err;
-}
-
-static INLINE void wc_ecc_free_rs(ecc_key* key, mp_int** r, mp_int** s)
-{
-    if (*r) {
-        mp_clear(*r);
-
-    #ifdef WOLFSSL_ASYNC_CRYPT
-        XFREE(*r, key->heap, DYNAMIC_TYPE_BIGINT);
-        key->r = NULL;
-    #endif
-        *r = NULL;
-    }
-    if (*s) {
-        mp_clear(*s);
-
-    #ifdef WOLFSSL_ASYNC_CRYPT
-        XFREE(*s, key->heap, DYNAMIC_TYPE_BIGINT);
-        key->s = NULL;
-    #endif
-        *s = NULL;
-    }
-    (void)key;
-}
-
 /* Setup dynamic pointers if using normal math for proper freeing */
 int wc_ecc_init_ex(ecc_key* key, void* heap, int devId)
@@ -3387,9 +4143,12 @@
     key->state = ECC_STATE_NONE;
 
+#if defined(PLUTON_CRYPTO_ECC) || defined(WOLF_CRYPTO_DEV)
+    key->devId = devId;
+#else
+    (void)devId;
+#endif
+
 #ifdef WOLFSSL_ATECC508A
-    key->slot = atmel_ecc_alloc();
-    if (key->slot == ATECC_INVALID_SLOT) {
-        return ECC_BAD_ARG_E;
-    }
+    key->slot = ATECC_INVALID_SLOT;
 #else
 #ifdef ALT_ECC_SIZE
@@ -3420,6 +4179,4 @@
     ret = wolfAsync_DevCtxInit(&key->asyncDev, WOLFSSL_ASYNC_MARKER_ECC,
                                                             key->heap, devId);
-#else
-    (void)devId;
 #endif
 
@@ -3431,4 +4188,27 @@
     return wc_ecc_init_ex(key, NULL, INVALID_DEVID);
 }
+
+#ifdef HAVE_PKCS11
+int wc_ecc_init_id(ecc_key* key, unsigned char* id, int len, void* heap,
+                   int devId)
+{
+    int ret = 0;
+
+    if (key == NULL)
+        ret = BAD_FUNC_ARG;
+    if (ret == 0 && (len < 0 || len > ECC_MAX_ID_LEN))
+        ret = BUFFER_E;
+
+    if (ret == 0)
+        ret = wc_ecc_init_ex(key, heap, devId);
+
+    if (ret == 0 && id != NULL && len != 0) {
+        XMEMCPY(key->id, id, len);
+        key->idLen = len;
+    }
+
+    return ret;
+}
+#endif
 
 int wc_ecc_set_flags(ecc_key* key, word32 flags)
@@ -3444,4 +4224,72 @@
 
 #ifndef NO_ASN
+
+#if defined(WOLFSSL_ATECC508A) || defined(PLUTON_CRYPTO_ECC)
+static int wc_ecc_sign_hash_hw(const byte* in, word32 inlen,
+    mp_int* r, mp_int* s, byte* out, word32 *outlen, WC_RNG* rng,
+    ecc_key* key)
+{
+    int err;
+
+#ifdef PLUTON_CRYPTO_ECC
+    if (key->devId != INVALID_DEVID) /* use hardware */
+#endif
+    {
+        word32 keysize = (word32)key->dp->size;
+
+        /* Check args */
+        if (keysize > ECC_MAX_CRYPTO_HW_SIZE || inlen != keysize ||
+                                                *outlen < keysize*2) {
+            return ECC_BAD_ARG_E;
+        }
+
+    #if defined(WOLFSSL_ATECC508A)
+        key->slot = atmel_ecc_alloc(ATMEL_SLOT_DEVICE);
+        if (key->slot == ATECC_INVALID_SLOT) {
+            return ECC_BAD_ARG_E;
+        }
+
+        /* Sign: Result is 32-bytes of R then 32-bytes of S */
+        err = atmel_ecc_sign(key->slot, in, out);
+        if (err != 0) {
+           return err;
+        }
+    #elif defined(PLUTON_CRYPTO_ECC)
+        {
+            /* perform ECC sign */
+            word32 raw_sig_size = *outlen;
+            err = Crypto_EccSign(in, inlen, out, &raw_sig_size);
+            if (err != CRYPTO_RES_SUCCESS || raw_sig_size != keysize*2){
+               return BAD_COND_E;
+            }
+        }
+    #endif
+
+        /* Load R and S */
+        err = mp_read_unsigned_bin(r, &out[0], keysize);
+        if (err != MP_OKAY) {
+            return err;
+        }
+        err = mp_read_unsigned_bin(s, &out[keysize], keysize);
+        if (err != MP_OKAY) {
+            return err;
+        }
+
+        /* Check for zeros */
+        if (mp_iszero(r) || mp_iszero(s)) {
+            return MP_ZERO_E;
+        }
+    }
+#ifdef PLUTON_CRYPTO_ECC
+    else {
+        err = wc_ecc_sign_hash_ex(in, inlen, rng, key, r, s);
+    }
+#endif
+    (void)rng;
+
+    return err;
+}
+#endif /* WOLFSSL_ATECC508A || PLUTON_CRYPTO_ECC */
+
 /**
  Sign a message digest
@@ -3458,8 +4306,6 @@
     int err;
     mp_int *r = NULL, *s = NULL;
-#ifndef WOLFSSL_ASYNC_CRYPT
+#if !defined(WOLFSSL_ASYNC_CRYPT) && !defined(WOLFSSL_SMALL_STACK)
     mp_int r_lcl, s_lcl;
-    r = &r_lcl;
-    s = &s_lcl;
 #endif
 
@@ -3468,4 +4314,32 @@
         return ECC_BAD_ARG_E;
     }
+
+#ifdef WOLF_CRYPTO_DEV
+    if (key->devId != INVALID_DEVID) {
+        err = wc_CryptoDev_EccSign(in, inlen, out, outlen, rng, key);
+        if (err != NOT_COMPILED_IN)
+            return err;
+    }
+#endif
+
+#ifdef WOLFSSL_ASYNC_CRYPT
+    err = wc_ecc_alloc_async(key);
+    if (err != 0)
+        return err;
+    r = key->r;
+    s = key->s;
+#elif !defined(WOLFSSL_SMALL_STACK)
+    r = &r_lcl;
+    s = &s_lcl;
+#else
+    r = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC);
+    if (r == NULL)
+        return MEMORY_E;
+    s = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC);
+    if (s == NULL) {
+        XFREE(r, key->heap, DYNAMIC_TYPE_ECC);
+        return MEMORY_E;
+    }
+#endif
 
     switch(key->state) {
@@ -3474,47 +4348,18 @@
             key->state = ECC_STATE_SIGN_DO;
 
-            err = wc_ecc_alloc_rs(key, &r, &s);
-            if (err != 0)
-                break;
-
             if ((err = mp_init_multi(r, s, NULL, NULL, NULL, NULL)) != MP_OKAY){
                 break;
             }
 
-        #ifdef WOLFSSL_ATECC508A
-            /* Check args */
-            if (inlen != ATECC_KEY_SIZE || *outlen < SIGN_RSP_SIZE) {
-                return ECC_BAD_ARG_E;
-            }
-
-            /* Sign: Result is 32-bytes of R then 32-bytes of S */
-            err = atcatls_sign(key->slot, in, out);
-            if (err != ATCA_SUCCESS) {
-               return BAD_COND_E;
-           }
-
-            /* Load R and S */
-            err = mp_read_unsigned_bin(r, &out[0], ATECC_KEY_SIZE);
-            if (err != MP_OKAY) {
-                return err;
-            }
-            err = mp_read_unsigned_bin(s, &out[ATECC_KEY_SIZE], ATECC_KEY_SIZE);
-            if (err != MP_OKAY) {
-                return err;
-            }
-
-            /* Check for zeros */
-            if (mp_iszero(r) || mp_iszero(s)) {
-                return MP_ZERO_E;
-            }
-
+        /* hardware crypto */
+        #if defined(WOLFSSL_ATECC508A) || defined(PLUTON_CRYPTO_ECC)
+            err = wc_ecc_sign_hash_hw(in, inlen, r, s, out, outlen, rng, key);
         #else
-
             err = wc_ecc_sign_hash_ex(in, inlen, rng, key, r, s);
+        #endif
             if (err < 0) {
                 break;
             }
 
-        #endif /* WOLFSSL_ATECC508A */
             FALL_THROUGH;
 
@@ -3523,11 +4368,11 @@
 
         #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC)
-            /* restore r/s */
-            r = key->r;
-            s = key->s;
-
             if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_ECC) {
-                /* only do this if not simulator, since it overwrites result */
+                #ifdef HAVE_CAVIUM_V
+                    /* Nitrox requires r and s in sep buffer, so split it */
+                    NitroxEccRsSplit(key, &r->raw, &s->raw);
+                #endif
                 #ifndef WOLFSSL_ASYNC_CRYPT_TEST
+                    /* only do this if not simulator, since it overwrites result */
                     wc_bigint_to_mp(&r->raw, r);
                     wc_bigint_to_mp(&s->raw, s);
@@ -3539,11 +4384,16 @@
             err = StoreECC_DSA_Sig(out, outlen, r, s);
 
-            /* always free r/s */
+            /* done with R/S */
             mp_clear(r);
             mp_clear(s);
+        #if !defined(WOLFSSL_ASYNC_CRYPT) && defined(WOLFSSL_SMALL_STACK)
+            XFREE(s, key->heap, DYNAMIC_TYPE_ECC);
+            XFREE(r, key->heap, DYNAMIC_TYPE_ECC);
+        #endif
             break;
 
         default:
             err = BAD_STATE_E;
+            break;
     }
 
@@ -3555,5 +4405,7 @@
 
     /* cleanup */
-    wc_ecc_free_rs(key, &r, &s);
+#ifdef WOLFSSL_ASYNC_CRYPT
+    wc_ecc_free_async(key);
+#endif
     key->state = ECC_STATE_NONE;
 
@@ -3576,6 +4428,12 @@
 {
    int    err;
-   mp_int e;
-   DECLARE_CURVE_SPECS(1)
+#ifndef WOLFSSL_SP_MATH
+   mp_int* e;
+#if (!defined(WOLFSSL_ASYNC_CRYPT) || !defined(HAVE_CAVIUM_V)) && \
+                                                   !defined(WOLFSSL_SMALL_STACK)
+   mp_int  e_lcl;
+#endif
+   DECLARE_CURVE_SPECS(curve, 1);
+#endif /* !WOLFSSL_SP_MATH */
 
    if (in == NULL || r == NULL || s == NULL || key == NULL || rng == NULL)
@@ -3592,4 +4450,10 @@
    }
 
+#ifdef WOLFSSL_SP_MATH
+    if (key->idx != ECC_CUSTOM_IDX && ecc_sets[key->idx].id == ECC_SECP256R1)
+        return sp_ecc_sign_256(in, inlen, rng, &key->k, r, s, key->heap);
+    else
+        return WC_KEY_SIZE_E;
+#else
 #ifdef WOLFSSL_HAVE_SP_ECC
     #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) && \
@@ -3603,5 +4467,6 @@
 #endif
     }
-#endif
+#endif /* WOLFSSL_HAVE_SP_ECC */
+
 
 #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) && \
@@ -3621,7 +4486,30 @@
 #endif
 
+   ALLOC_CURVE_SPECS(1);
+
+#if defined(WOLFSSL_ASYNC_CRYPT) && defined(HAVE_CAVIUM_V)
+   err = wc_ecc_alloc_mpint(key, &key->e);
+   if (err != 0) {
+      FREE_CURVE_SPECS();
+      return err;
+   }
+   e = key->e;
+#elif !defined(WOLFSSL_SMALL_STACK)
+   e = &e_lcl;
+#else
+   e = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC);
+   if (e == NULL) {
+      FREE_CURVE_SPECS();
+      return MEMORY_E;
+   }
+#endif
+
    /* get the hash and load it as a bignum into 'e' */
    /* init the bignums */
-   if ((err = mp_init(&e)) != MP_OKAY) {
+   if ((err = mp_init(e)) != MP_OKAY) {
+   #ifdef WOLFSSL_SMALL_STACK
+      XFREE(e, key->heap, DYNAMIC_TYPE_ECC);
+   #endif
+      FREE_CURVE_SPECS();
       return err;
    }
@@ -3638,9 +4526,9 @@
        if ((WOLFSSL_BIT_SIZE * inlen) > orderBits)
            inlen = (orderBits + WOLFSSL_BIT_SIZE - 1) / WOLFSSL_BIT_SIZE;
-       err = mp_read_unsigned_bin(&e, (byte*)in, inlen);
+       err = mp_read_unsigned_bin(e, (byte*)in, inlen);
 
        /* may still need bit truncation too */
        if (err == MP_OKAY && (WOLFSSL_BIT_SIZE * inlen) > orderBits)
-           mp_rshb(&e, WOLFSSL_BIT_SIZE - (orderBits & 0x7));
+           mp_rshb(e, WOLFSSL_BIT_SIZE - (orderBits & 0x7));
    }
 
@@ -3648,94 +4536,191 @@
    if (err == MP_OKAY) {
        int loop_check = 0;
-       ecc_key pubkey;
+   #ifdef WOLFSSL_SMALL_STACK
+       ecc_key* pubkey = NULL;
+   #else
+       ecc_key  pubkey[1];
+   #endif
 
    #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC)
         if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_ECC) {
-        #ifdef HAVE_CAVIUM
-            /* TODO: Not implemented */
-        #elif defined(HAVE_INTEL_QA)
-           mp_int k;
-
-           err = mp_init(&k);
+        #if defined(HAVE_CAVIUM_V) || defined(HAVE_INTEL_QA)
+        #ifdef HAVE_CAVIUM_V
+            if (NitroxEccIsCurveSupported(key))
+        #endif
+            {
+               word32 keySz = key->dp->size;
+               mp_int* k;
+            #ifdef HAVE_CAVIUM_V
+               err = wc_ecc_alloc_mpint(key, &key->signK);
+               if (err != 0)
+                  return err;
+               k = key->signK;
+            #else
+               mp_int k_lcl;
+               k = &k_lcl;
+            #endif
+
+               err = mp_init(k);
+
            /* make sure r and s are allocated */
+           #ifdef HAVE_CAVIUM_V
+               /* Nitrox V needs single buffer for R and S */
+               if (err == MP_OKAY)
+                   err = wc_bigint_alloc(&key->r->raw, NitroxEccGetSize(key)*2);
+               /* Nitrox V only needs Prime and Order */
+               if (err == MP_OKAY)
+                   err = wc_ecc_curve_load(key->dp, &curve,
+                        (ECC_CURVE_FIELD_PRIME | ECC_CURVE_FIELD_ORDER));
+           #else
            if (err == MP_OKAY)
                err = wc_bigint_alloc(&key->r->raw, key->dp->size);
            if (err == MP_OKAY)
+                   err = wc_ecc_curve_load(key->dp, &curve, ECC_CURVE_FIELD_ALL);
+           #endif
+               if (err == MP_OKAY)
                err = wc_bigint_alloc(&key->s->raw, key->dp->size);
+
            /* load e and k */
            if (err == MP_OKAY)
-               err = wc_mp_to_bigint(&e, &e.raw);
+                   err = wc_mp_to_bigint_sz(e, &e->raw, keySz);
            if (err == MP_OKAY)
-               err = wc_mp_to_bigint(&key->k, &key->k.raw);
+                   err = wc_mp_to_bigint_sz(&key->k, &key->k.raw, keySz);
            if (err == MP_OKAY)
-               err = wc_ecc_curve_load(key->dp, &curve, ECC_CURVE_FIELD_ALL);
+                   err = wc_ecc_gen_k(rng, key->dp->size, k, curve->order);
            if (err == MP_OKAY)
-               err = wc_ecc_gen_k(rng, key->dp->size, &k, curve->order);
+                   err = wc_mp_to_bigint_sz(k, &k->raw, keySz);
+
+           #ifdef HAVE_CAVIUM_V
            if (err == MP_OKAY)
-               err = wc_mp_to_bigint(&k, &k.raw);
+                   err = NitroxEcdsaSign(key, &e->raw, &key->k.raw, &k->raw,
+                    &r->raw, &s->raw, &curve->prime->raw, &curve->order->raw);
+           #else
            if (err == MP_OKAY)
-               err = IntelQaEcdsaSign(&key->asyncDev, &e.raw, &key->k.raw,
-                  &k.raw, &r->raw, &s->raw, &curve->Af->raw, &curve->Bf->raw,
+                   err = IntelQaEcdsaSign(&key->asyncDev, &e->raw, &key->k.raw,
+                      &k->raw, &r->raw, &s->raw, &curve->Af->raw, &curve->Bf->raw,
                   &curve->prime->raw, &curve->order->raw, &curve->Gx->raw,
                   &curve->Gy->raw);
-
-           mp_clear(&e);
-           mp_clear(&k);
+           #endif
+
+           #ifndef HAVE_CAVIUM_V
+               mp_clear(e);
+               mp_clear(k);
+           #endif
            wc_ecc_curve_free(curve);
+               FREE_CURVE_SPECS();
 
            return err;
-       #endif
+           }
+       #endif /* HAVE_CAVIUM_V || HAVE_INTEL_QA */
        }
    #endif /* WOLFSSL_ASYNC_CRYPT */
 
+   #ifdef WOLFSSL_SMALL_STACK
+       pubkey = (ecc_key*)XMALLOC(sizeof(ecc_key), key->heap, DYNAMIC_TYPE_ECC);
+       if (pubkey == NULL)
+           err = MEMORY_E;
+   #endif
+
        /* don't use async for key, since we don't support async return here */
-       if (wc_ecc_init_ex(&pubkey, key->heap, INVALID_DEVID) == MP_OKAY) {
+       if (err == MP_OKAY && (err = wc_ecc_init_ex(pubkey, key->heap,
+                                                   INVALID_DEVID)) == MP_OKAY) {
+       #ifdef WOLFSSL_SMALL_STACK
+           mp_int* b = NULL;
+       #else
+           mp_int  b[1];
+       #endif
+
+       #ifdef WOLFSSL_SMALL_STACK
+           if (err == MP_OKAY) {
+               b = (mp_int*)XMALLOC(sizeof(mp_int), key->heap,
+                                                              DYNAMIC_TYPE_ECC);
+               if (b == NULL)
+                   err = MEMORY_E;
+           }
+       #endif
+
+           if (err == MP_OKAY) {
+               err = mp_init(b);
+           }
+
        #ifdef WOLFSSL_CUSTOM_CURVES
            /* if custom curve, apply params to pubkey */
-           if (key->idx == ECC_CUSTOM_IDX) {
-               wc_ecc_set_custom_curve(&pubkey, key->dp);
+           if (err == MP_OKAY && key->idx == ECC_CUSTOM_IDX) {
+               err = wc_ecc_set_custom_curve(pubkey, key->dp);
            }
        #endif
 
-           for (;;) {
+           if (err == MP_OKAY) {
+               /* Generate blinding value - non-zero value. */
+               do {
+                   if (++loop_check > 64) {
+                        err = RNG_FAILURE_E;
+                        break;
+                   }
+
+                   err = wc_ecc_gen_k(rng, key->dp->size, b, curve->order);
+               }
+               while (err == MP_ZERO_E);
+               loop_check = 0;
+           }
+
+           for (; err == MP_OKAY;) {
                if (++loop_check > 64) {
                     err = RNG_FAILURE_E;
                     break;
                }
-               err = wc_ecc_make_key_ex(rng, key->dp->size, &pubkey,
+               err = wc_ecc_make_key_ex(rng, key->dp->size, pubkey,
                                                               key->dp->id);
                if (err != MP_OKAY) break;
 
                /* find r = x1 mod n */
-               err = mp_mod(pubkey.pubkey.x, curve->order, r);
+               err = mp_mod(pubkey->pubkey.x, curve->order, r);
                if (err != MP_OKAY) break;
 
                if (mp_iszero(r) == MP_YES) {
                 #ifndef ALT_ECC_SIZE
-                   mp_clear(pubkey.pubkey.x);
-                   mp_clear(pubkey.pubkey.y);
-                   mp_clear(pubkey.pubkey.z);
+                   mp_clear(pubkey->pubkey.x);
+                   mp_clear(pubkey->pubkey.y);
+                   mp_clear(pubkey->pubkey.z);
                 #endif
-                   mp_forcezero(&pubkey.k);
+                   mp_forcezero(&pubkey->k);
                }
                else {
-                   /* find s = (e + xr)/k */
-                   err = mp_invmod(&pubkey.k, curve->order, &pubkey.k);
+                   /* find s = (e + xr)/k
+                             = b.(e/k.b + x.r/k.b) */
+
+                   /* k = k.b */
+                   err = mp_mulmod(&pubkey->k, b, curve->order, &pubkey->k);
                    if (err != MP_OKAY) break;
 
-                   /* s = xr */
+                   /* k = 1/k.b */
+                   err = mp_invmod(&pubkey->k, curve->order, &pubkey->k);
+                   if (err != MP_OKAY) break;
+
+                   /* s = x.r */
                    err = mp_mulmod(&key->k, r, curve->order, s);
                    if (err != MP_OKAY) break;
 
-                   /* s = e +  xr */
-                   err = mp_add(&e, s, s);
+                   /* s = x.r/k.b */
+                   err = mp_mulmod(&pubkey->k, s, curve->order, s);
                    if (err != MP_OKAY) break;
 
-                   /* s = e +  xr */
+                   /* e = e/k.b */
+                   err = mp_mulmod(&pubkey->k, e, curve->order, e);
+                   if (err != MP_OKAY) break;
+
+                   /* s = e/k.b + x.r/k.b
+                        = (e + x.r)/k.b */
+                   err = mp_add(e, s, s);
+                   if (err != MP_OKAY) break;
+
+                   /* s = b.(e + x.r)/k.b
+                        = (e + x.r)/k */
+                   err = mp_mulmod(s, b, curve->order, s);
+                   if (err != MP_OKAY) break;
+
+                   /* s = (e + xr)/k */
                    err = mp_mod(s, curve->order, s);
                    if (err != MP_OKAY) break;
-
-                   /* s = (e + xr)/k */
-                   err = mp_mulmod(s, &pubkey.k, curve->order, s);
 
                    if (mp_iszero(s) == MP_NO)
@@ -3743,10 +4728,23 @@
                 }
            }
-           wc_ecc_free(&pubkey);
+           mp_clear(b);
+           mp_free(b);
+       #ifdef WOLFSSL_SMALL_STACK
+           XFREE(b, key->heap, DYNAMIC_TYPE_ECC);
+       #endif
+           wc_ecc_free(pubkey);
+       #ifdef WOLFSSL_SMALL_STACK
+           XFREE(pubkey, key->heap, DYNAMIC_TYPE_ECC);
+       #endif
        }
    }
 
-   mp_clear(&e);
+   mp_clear(e);
    wc_ecc_curve_free(curve);
+#ifdef WOLFSSL_SMALL_STACK
+   XFREE(e, key->heap, DYNAMIC_TYPE_ECC);
+#endif
+   FREE_CURVE_SPECS();
+#endif /* WOLFSSL_SP_MATH */
 
    return err;
@@ -3754,4 +4752,26 @@
 #endif /* WOLFSSL_ATECC508A */
 #endif /* HAVE_ECC_SIGN */
+
+#ifdef WOLFSSL_CUSTOM_CURVES
+void wc_ecc_free_curve(const ecc_set_type* curve, void* heap)
+{
+    if (curve->prime != NULL)
+        XFREE((void*)curve->prime, heap, DYNAMIC_TYPE_ECC_BUFFER);
+    if (curve->Af != NULL)
+        XFREE((void*)curve->Af, heap, DYNAMIC_TYPE_ECC_BUFFER);
+    if (curve->Bf != NULL)
+        XFREE((void*)curve->Bf, heap, DYNAMIC_TYPE_ECC_BUFFER);
+    if (curve->order != NULL)
+        XFREE((void*)curve->order, heap, DYNAMIC_TYPE_ECC_BUFFER);
+    if (curve->Gx != NULL)
+        XFREE((void*)curve->Gx, heap, DYNAMIC_TYPE_ECC_BUFFER);
+    if (curve->Gy != NULL)
+        XFREE((void*)curve->Gy, heap, DYNAMIC_TYPE_ECC_BUFFER);
+
+    XFREE((void*)curve, heap, DYNAMIC_TYPE_ECC_BUFFER);
+
+    (void)heap;
+}
+#endif /* WOLFSSL_CUSTOM_CURVES */
 
 /**
@@ -3759,18 +4779,20 @@
   key   The key you wish to free
 */
-void wc_ecc_free(ecc_key* key)
+int wc_ecc_free(ecc_key* key)
 {
     if (key == NULL) {
-        return;
-    }
-
-#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC)
+        return 0;
+    }
+
+#ifdef WOLFSSL_ASYNC_CRYPT
+    #ifdef WC_ASYNC_ENABLE_ECC
     wolfAsync_DevCtxFree(&key->asyncDev, WOLFSSL_ASYNC_MARKER_ECC);
-    wc_ecc_free_rs(key, &key->r, &key->s);
+    #endif
+    wc_ecc_free_async(key);
 #endif
 
 #ifdef WOLFSSL_ATECC508A
    atmel_ecc_free(key->slot);
-   key->slot = -1;
+    key->slot = ATECC_INVALID_SLOT;
 #else
 
@@ -3781,6 +4803,14 @@
     mp_forcezero(&key->k);
 #endif /* WOLFSSL_ATECC508A */
-}
-
+
+#ifdef WOLFSSL_CUSTOM_CURVES
+    if (key->deallocSet && key->dp != NULL)
+        wc_ecc_free_curve(key->dp, key->heap);
+#endif
+
+    return 0;
+}
+
+#if !defined(WOLFSSL_SP_MATH) && !defined(WOLFSSL_ATECC508A)
 #ifdef ECC_SHAMIR
 
@@ -3801,5 +4831,5 @@
                              void* heap)
 #else
-static int ecc_mul2add(ecc_point* A, mp_int* kA,
+int ecc_mul2add(ecc_point* A, mp_int* kA,
                     ecc_point* B, mp_int* kB,
                     ecc_point* C, mp_int* a, mp_int* modulus,
@@ -3807,10 +4837,17 @@
 #endif
 {
-  ecc_point*     precomp[16];
+#ifdef WOLFSSL_SMALL_STACK
+  ecc_point**    precomp = NULL;
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+  ecc_key        key;
+#endif
+#else
+  ecc_point*     precomp[SHAMIR_PRECOMP_SZ];
+#endif
   unsigned       bitbufA, bitbufB, lenA, lenB, len, nA, nB, nibble;
   unsigned char* tA;
   unsigned char* tB;
   int            err = MP_OKAY, first, x, y;
-  mp_digit mp;
+  mp_digit       mp = 0;
 
   /* argchks */
@@ -3830,9 +4867,49 @@
      return GEN_MEM_ERR;
   }
+#ifdef WOLFSSL_SMALL_STACK
+  precomp = (ecc_point**)XMALLOC(sizeof(ecc_point*) * SHAMIR_PRECOMP_SZ, heap,
+                                                       DYNAMIC_TYPE_ECC_BUFFER);
+  if (precomp == NULL) {
+     XFREE(tB, heap, DYNAMIC_TYPE_ECC_BUFFER);
+     XFREE(tA, heap, DYNAMIC_TYPE_ECC_BUFFER);
+     return GEN_MEM_ERR;
+  }
+#endif
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+  key.t1 = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC);
+  key.t2 = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC);
+#ifdef ALT_ECC_SIZE
+  key.x = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC);
+  key.y = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC);
+  key.z = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC);
+#endif
+  if (key.t1 == NULL || key.t2 == NULL
+#ifdef ALT_ECC_SIZE
+     || key.x == NULL || key.y == NULL || key.z == NULL
+#endif
+  ) {
+#ifdef ALT_ECC_SIZE
+      XFREE(key.z, heap, DYNAMIC_TYPE_ECC);
+      XFREE(key.y, heap, DYNAMIC_TYPE_ECC);
+      XFREE(key.x, heap, DYNAMIC_TYPE_ECC);
+#endif
+      XFREE(key.t2, heap, DYNAMIC_TYPE_ECC);
+      XFREE(key.t1, heap, DYNAMIC_TYPE_ECC);
+      XFREE(precomp, heap, DYNAMIC_TYPE_ECC_BUFFER);
+      XFREE(tB, heap, DYNAMIC_TYPE_ECC_BUFFER);
+      XFREE(tA, heap, DYNAMIC_TYPE_ECC_BUFFER);
+      return MEMORY_E;
+  }
+  C->key = &key;
+#endif /* WOLFSSL_SMALL_STACK_CACHE */
 
   /* init variables */
   XMEMSET(tA, 0, ECC_BUFSIZE);
   XMEMSET(tB, 0, ECC_BUFSIZE);
+#ifndef WOLFSSL_SMALL_STACK
   XMEMSET(precomp, 0, sizeof(precomp));
+#else
+  XMEMSET(precomp, 0, sizeof(ecc_point*) * SHAMIR_PRECOMP_SZ);
+#endif
 
   /* get sizes */
@@ -3856,5 +4933,5 @@
     /* allocate the table */
     if (err == MP_OKAY) {
-        for (x = 0; x < 16; x++) {
+        for (x = 0; x < SHAMIR_PRECOMP_SZ; x++) {
             precomp[x] = wc_ecc_new_point_h(heap);
             if (precomp[x] == NULL) {
@@ -3862,4 +4939,7 @@
                 break;
             }
+        #ifdef WOLFSSL_SMALL_STACK_CACHE
+            precomp[x]->key = &key;
+        #endif
         }
     }
@@ -3871,27 +4951,41 @@
 
   if (err == MP_OKAY) {
-    mp_int mu;
-    err = mp_init(&mu);
+  #ifdef WOLFSSL_SMALL_STACK
+    mp_int* mu = NULL;
+  #else
+    mp_int  mu[1];
+  #endif
+  #ifdef WOLFSSL_SMALL_STACK
+    mu = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC);
+    if (mu == NULL)
+        err = MEMORY_E;
+  #endif
     if (err == MP_OKAY) {
-      err = mp_montgomery_calc_normalization(&mu, modulus);
+        err = mp_init(mu);
+    }
+    if (err == MP_OKAY) {
+      err = mp_montgomery_calc_normalization(mu, modulus);
 
       if (err == MP_OKAY)
         /* copy ones ... */
-        err = mp_mulmod(A->x, &mu, modulus, precomp[1]->x);
+        err = mp_mulmod(A->x, mu, modulus, precomp[1]->x);
 
       if (err == MP_OKAY)
-        err = mp_mulmod(A->y, &mu, modulus, precomp[1]->y);
+        err = mp_mulmod(A->y, mu, modulus, precomp[1]->y);
       if (err == MP_OKAY)
-        err = mp_mulmod(A->z, &mu, modulus, precomp[1]->z);
+        err = mp_mulmod(A->z, mu, modulus, precomp[1]->z);
 
       if (err == MP_OKAY)
-        err = mp_mulmod(B->x, &mu, modulus, precomp[1<<2]->x);
+        err = mp_mulmod(B->x, mu, modulus, precomp[1<<2]->x);
       if (err == MP_OKAY)
-        err = mp_mulmod(B->y, &mu, modulus, precomp[1<<2]->y);
+        err = mp_mulmod(B->y, mu, modulus, precomp[1<<2]->y);
       if (err == MP_OKAY)
-        err = mp_mulmod(B->z, &mu, modulus, precomp[1<<2]->z);
+        err = mp_mulmod(B->z, mu, modulus, precomp[1<<2]->z);
 
       /* done with mu */
-      mp_clear(&mu);
+      mp_clear(mu);
+  #ifdef WOLFSSL_SMALL_STACK
+      XFREE(mu, heap, DYNAMIC_TYPE_ECC);
+  #endif
     }
   }
@@ -3916,9 +5010,10 @@
     for (x = 1; x < 4; x++) {
         for (y = 1; y < 4; y++) {
-            if (err == MP_OKAY)
+        if (err == MP_OKAY) {
                 err = ecc_projective_add_point(precomp[x], precomp[(y<<2)],
                                                precomp[x+(y<<2)], a, modulus, mp);
         }
     }
+  }
   }
 
@@ -3994,5 +5089,5 @@
 
   /* clean up */
-  for (x = 0; x < 16; x++) {
+  for (x = 0; x < SHAMIR_PRECOMP_SZ; x++) {
      wc_ecc_del_point_h(precomp[x], heap);
   }
@@ -4000,6 +5095,19 @@
   ForceZero(tA, ECC_BUFSIZE);
   ForceZero(tB, ECC_BUFSIZE);
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+#ifdef ALT_ECC_SIZE
+  XFREE(key.z, heap, DYNAMIC_TYPE_ECC);
+  XFREE(key.y, heap, DYNAMIC_TYPE_ECC);
+  XFREE(key.x, heap, DYNAMIC_TYPE_ECC);
+#endif
+  XFREE(key.t2, heap, DYNAMIC_TYPE_ECC);
+  XFREE(key.t1, heap, DYNAMIC_TYPE_ECC);
+  C->key = NULL;
+#endif
+#ifdef WOLFSSL_SMALL_STACK
+  XFREE(precomp, heap, DYNAMIC_TYPE_ECC_BUFFER);
+#endif
+  XFREE(tB, heap, DYNAMIC_TYPE_ECC_BUFFER);
   XFREE(tA, heap, DYNAMIC_TYPE_ECC_BUFFER);
-  XFREE(tB, heap, DYNAMIC_TYPE_ECC_BUFFER);
 
   return err;
@@ -4007,4 +5115,5 @@
 
 #endif /* ECC_SHAMIR */
+#endif /* !WOLFSSL_SP_MATH && !WOLFSSL_ATECC508A */
 
 
@@ -4037,7 +5146,7 @@
     mp_int *r = NULL, *s = NULL;
 #ifndef WOLFSSL_ASYNC_CRYPT
-    mp_int r_lcl, s_lcl;
-    r = &r_lcl;
-    s = &s_lcl;
+#ifndef WOLFSSL_SMALL_STACK
+    mp_int r_lcl[1], s_lcl[1];
+#endif
 #endif
 
@@ -4045,4 +5154,36 @@
         return ECC_BAD_ARG_E;
     }
+
+#ifdef WOLF_CRYPTO_DEV
+    if (key->devId != INVALID_DEVID) {
+        err = wc_CryptoDev_EccVerify(sig, siglen, hash, hashlen, res, key);
+        if (err != NOT_COMPILED_IN)
+            return err;
+    }
+#endif
+
+#ifdef WOLFSSL_ASYNC_CRYPT
+    err = wc_ecc_alloc_async(key);
+    if (err != 0)
+        return err;
+    r = key->r;
+    s = key->s;
+#else
+    #ifndef WOLFSSL_SMALL_STACK
+    r = r_lcl;
+    s = s_lcl;
+    #else
+    r = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC);
+    if (r == NULL)
+        return MEMORY_E;
+    s = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC);
+    if (s == NULL) {
+        XFREE(r, key->heap, DYNAMIC_TYPE_ECC);
+        return MEMORY_E;
+    }
+    #endif
+    XMEMSET(r, 0, sizeof(mp_int));
+    XMEMSET(s, 0, sizeof(mp_int));
+#endif /* WOLFSSL_ASYNC_CRYPT */
 
     switch(key->state) {
@@ -4058,8 +5199,4 @@
              * the rest of this function will execute, and everything
              * gets cleaned up at the end. */
-            err = wc_ecc_alloc_rs(key, &r, &s);
-            if (err != 0)
-                break;
-
             /* decode DSA header */
             err = DecodeECC_DSA_Sig(sig, siglen, r, s);
@@ -4073,4 +5210,17 @@
 
             err = wc_ecc_verify_hash_ex(r, s, hash, hashlen, res, key);
+
+        #ifndef WOLFSSL_ASYNC_CRYPT
+            /* done with R/S */
+            mp_clear(r);
+            mp_clear(s);
+        #ifdef WOLFSSL_SMALL_STACK
+            XFREE(s, key->heap, DYNAMIC_TYPE_ECC);
+            XFREE(r, key->heap, DYNAMIC_TYPE_ECC);
+            r = NULL;
+            s = NULL;
+        #endif
+        #endif
+
             if (err < 0) {
                 break;
@@ -4081,14 +5231,4 @@
             key->state = ECC_STATE_VERIFY_RES;
             err = 0;
-
-        #ifdef WOLFSSL_ASYNC_CRYPT
-            /* restore r/s */
-            r = key->r;
-            s = key->s;
-        #endif
-
-            /* done with R/S */
-            mp_clear(r);
-            mp_clear(s);
             break;
 
@@ -4104,6 +5244,17 @@
 
     /* cleanup */
-    wc_ecc_free_rs(key, &r, &s);
+#ifdef WOLFSSL_ASYNC_CRYPT
+    wc_ecc_free_async(key);
+#endif
     key->state = ECC_STATE_NONE;
+
+#ifdef WOLFSSL_SMALL_STACK
+    if (err != WC_PENDING_E) {
+            XFREE(s, key->heap, DYNAMIC_TYPE_ECC);
+            XFREE(r, key->heap, DYNAMIC_TYPE_ECC);
+            r = NULL;
+            s = NULL;
+    }
+#endif
 
     return err;
@@ -4126,15 +5277,29 @@
 {
    int           err;
-#ifndef WOLFSSL_ATECC508A
+   word32        keySz;
+#ifdef WOLFSSL_ATECC508A
+   byte sigRS[ATECC_KEY_SIZE*2];
+#elif !defined(WOLFSSL_SP_MATH)
    int          did_init = 0;
    ecc_point    *mG = NULL, *mQ = NULL;
-   mp_int        v;
-   mp_int        w;
-   mp_int        u1;
-   mp_int        u2;
-   mp_int        e;
-   DECLARE_CURVE_SPECS(ECC_CURVE_FIELD_COUNT)
-#else
-   byte sigRS[ATECC_KEY_SIZE*2];
+#ifdef WOLFSSL_SMALL_STACK
+   mp_int*       v = NULL;
+   mp_int*       w = NULL;
+   mp_int*       u1 = NULL;
+   mp_int*       u2 = NULL;
+#if !defined(WOLFSSL_ASYNC_CRYPT) || !defined(HAVE_CAVIUM_V)
+   mp_int*       e_lcl = NULL;
+#endif
+#else /* WOLFSSL_SMALL_STACK */
+   mp_int        v[1];
+   mp_int        w[1];
+   mp_int        u1[1];
+   mp_int        u2[1];
+#if !defined(WOLFSSL_ASYNC_CRYPT) || !defined(HAVE_CAVIUM_V)
+   mp_int        e_lcl[1];
+#endif
+#endif /* WOLFSSL_SMALL_STACK */
+   mp_int*       e;
+   DECLARE_CURVE_SPECS(curve, ECC_CURVE_FIELD_COUNT);
 #endif
 
@@ -4149,4 +5314,6 @@
       return ECC_BAD_ARG_E;
    }
+
+   keySz = key->dp->size;
 
 #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) && \
@@ -4172,16 +5339,16 @@
         return err;
     }
-    err = mp_to_unsigned_bin(s, &sigRS[ATECC_KEY_SIZE]);
+    err = mp_to_unsigned_bin(s, &sigRS[keySz]);
     if (err != MP_OKAY) {
         return err;
     }
 
-    err = atcatls_verify(hash, sigRS, key->pubkey, (bool*)res);
-    if (err != ATCA_SUCCESS) {
-       return BAD_COND_E;
-   }
+    err = atmel_ecc_verify(hash, sigRS, key->pubkey_raw, res);
+    if (err != 0) {
+       return err;
+   }
+    (void)hashlen;
 
 #else
-
   /* checking if private key with no public part */
   if (key->type == ECC_PRIVATEKEY_ONLY) {
@@ -4194,4 +5361,12 @@
   }
 
+#ifdef WOLFSSL_SP_MATH
+  if (key->idx != ECC_CUSTOM_IDX && ecc_sets[key->idx].id == ECC_SECP256R1) {
+      return sp_ecc_verify_256(hash, hashlen, key->pubkey.x, key->pubkey.y,
+                                           key->pubkey.z, r, s, res, key->heap);
+  }
+  else
+      return WC_KEY_SIZE_E;
+#else
 #ifdef WOLFSSL_HAVE_SP_ECC
 #ifndef WOLFSSL_SP_NO_256
@@ -4205,8 +5380,28 @@
                                      key->pubkey.z,r, s, res, key->heap);
     }
-#endif
-#endif
-
-   err = mp_init(&e);
+#endif /* WOLFSSL_SP_NO_256 */
+#endif /* WOLFSSL_HAVE_SP_ECC */
+
+   ALLOC_CURVE_SPECS(ECC_CURVE_FIELD_COUNT);
+
+#if defined(WOLFSSL_ASYNC_CRYPT) && defined(HAVE_CAVIUM_V)
+   err = wc_ecc_alloc_mpint(key, &key->e);
+   if (err != 0) {
+      FREE_CURVE_SPECS();
+      return err;
+   }
+   e = key->e;
+#else
+#ifdef WOLFSSL_SMALL_STACK
+   e_lcl = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC);
+   if (e_lcl == NULL) {
+       FREE_CURVE_SPECS();
+       return MEMORY_E;
+   }
+#endif
+   e = e_lcl;
+#endif
+
+   err = mp_init(e);
    if (err != MP_OKAY)
       return MEMORY_E;
@@ -4232,9 +5427,9 @@
        if ( (WOLFSSL_BIT_SIZE * hashlen) > orderBits)
            hashlen = (orderBits + WOLFSSL_BIT_SIZE - 1) / WOLFSSL_BIT_SIZE;
-       err = mp_read_unsigned_bin(&e, hash, hashlen);
+       err = mp_read_unsigned_bin(e, hash, hashlen);
 
        /* may still need bit truncation too */
        if (err == MP_OKAY && (WOLFSSL_BIT_SIZE * hashlen) > orderBits)
-           mp_rshb(&e, WOLFSSL_BIT_SIZE - (orderBits & 0x7));
+           mp_rshb(e, WOLFSSL_BIT_SIZE - (orderBits & 0x7));
    }
 
@@ -4242,30 +5437,64 @@
 #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC)
    if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_ECC) {
-   #ifdef HAVE_CAVIUM
-      /* TODO: Not implemented */
-   #elif defined(HAVE_INTEL_QA)
-      err = wc_mp_to_bigint(&e, &e.raw);
+   #if defined(HAVE_CAVIUM_V) || defined(HAVE_INTEL_QA)
+   #ifdef HAVE_CAVIUM_V
+      if (NitroxEccIsCurveSupported(key))
+   #endif
+      {
+          err = wc_mp_to_bigint_sz(e, &e->raw, keySz);
       if (err == MP_OKAY)
-          err = wc_mp_to_bigint(key->pubkey.x, &key->pubkey.x->raw);
+              err = wc_mp_to_bigint_sz(key->pubkey.x, &key->pubkey.x->raw, keySz);
       if (err == MP_OKAY)
-          err = wc_mp_to_bigint(key->pubkey.y, &key->pubkey.y->raw);
+              err = wc_mp_to_bigint_sz(key->pubkey.y, &key->pubkey.y->raw, keySz);
       if (err == MP_OKAY)
-          err = IntelQaEcdsaVerify(&key->asyncDev, &e.raw, &key->pubkey.x->raw,
+          #ifdef HAVE_CAVIUM_V
+              err = NitroxEcdsaVerify(key, &e->raw, &key->pubkey.x->raw,
+                    &key->pubkey.y->raw, &r->raw, &s->raw,
+                    &curve->prime->raw, &curve->order->raw, res);
+          #else
+              err = IntelQaEcdsaVerify(&key->asyncDev, &e->raw, &key->pubkey.x->raw,
                 &key->pubkey.y->raw, &r->raw, &s->raw, &curve->Af->raw,
                 &curve->Bf->raw, &curve->prime->raw, &curve->order->raw,
                 &curve->Gx->raw, &curve->Gy->raw, res);
-
-      mp_clear(&e);
-
+          #endif
+
+      #ifndef HAVE_CAVIUM_V
+          mp_clear(e);
+      #endif
       wc_ecc_curve_free(curve);
+          FREE_CURVE_SPECS();
 
       return err;
-   #endif
+      }
+   #endif /* HAVE_CAVIUM_V || HAVE_INTEL_QA */
    }
 #endif /* WOLFSSL_ASYNC_CRYPT */
+
+#ifdef WOLFSSL_SMALL_STACK
+   if (err == MP_OKAY) {
+       v = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC);
+       if (v == NULL)
+           err = MEMORY_E;
+   }
+   if (err == MP_OKAY) {
+       w = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC);
+       if (w == NULL)
+           err = MEMORY_E;
+   }
+   if (err == MP_OKAY) {
+       u1 = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC);
+       if (u1 == NULL)
+           err = MEMORY_E;
+   }
+   if (err == MP_OKAY) {
+       u2 = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC);
+       if (u2 == NULL)
+           err = MEMORY_E;
+   }
+#endif
 
    /* allocate ints */
    if (err == MP_OKAY) {
-       if ((err = mp_init_multi(&v, &w, &u1, &u2, NULL, NULL)) != MP_OKAY) {
+       if ((err = mp_init_multi(v, w, u1, u2, NULL, NULL)) != MP_OKAY) {
           err = MEMORY_E;
        }
@@ -4283,13 +5512,13 @@
    /*  w  = s^-1 mod n */
    if (err == MP_OKAY)
-       err = mp_invmod(s, curve->order, &w);
+       err = mp_invmod(s, curve->order, w);
 
    /* u1 = ew */
    if (err == MP_OKAY)
-       err = mp_mulmod(&e, &w, curve->order, &u1);
+       err = mp_mulmod(e, w, curve->order, u1);
 
    /* u2 = rw */
    if (err == MP_OKAY)
-       err = mp_mulmod(r, &w, curve->order, &u2);
+       err = mp_mulmod(r, w, curve->order, u2);
 
    /* find mG and mQ */
@@ -4311,21 +5540,21 @@
    /* use PKHA to compute u1*mG + u2*mQ */
    if (err == MP_OKAY)
-       err = wc_ecc_mulmod_ex(&u1, mG, mG, curve->Af, curve->prime, 0, key->heap);
-   if (err == MP_OKAY)
-       err = wc_ecc_mulmod_ex(&u2, mQ, mQ, curve->Af, curve->prime, 0, key->heap);
+       err = wc_ecc_mulmod_ex(u1, mG, mG, curve->Af, curve->prime, 0, key->heap);
+   if (err == MP_OKAY)
+       err = wc_ecc_mulmod_ex(u2, mQ, mQ, curve->Af, curve->prime, 0, key->heap);
    if (err == MP_OKAY)
        err = wc_ecc_point_add(mG, mQ, mG, curve->prime);
-#else /* FREESCALE_LTC_ECC */
+#else
 #ifndef ECC_SHAMIR
     {
-        mp_digit      mp;
+        mp_digit mp = 0;
 
         /* compute u1*mG + u2*mQ = mG */
         if (err == MP_OKAY) {
-            err = wc_ecc_mulmod_ex(&u1, mG, mG, curve->Af, curve->prime, 0,
+            err = wc_ecc_mulmod_ex(u1, mG, mG, curve->Af, curve->prime, 0,
                                                                      key->heap);
         }
         if (err == MP_OKAY) {
-            err = wc_ecc_mulmod_ex(&u2, mQ, mQ, curve->Af, curve->prime, 0,
+            err = wc_ecc_mulmod_ex(u2, mQ, mQ, curve->Af, curve->prime, 0,
                                                                      key->heap);
         }
@@ -4347,5 +5576,5 @@
        /* use Shamir's trick to compute u1*mG + u2*mQ using half the doubles */
         if (err == MP_OKAY) {
-            err = ecc_mul2add(mG, &u1, mQ, &u2, mG, curve->Af, curve->prime,
+            err = ecc_mul2add(mG, u1, mQ, u2, mG, curve->Af, curve->prime,
                                                                     key->heap);
         }
@@ -4354,9 +5583,9 @@
    /* v = X_x1 mod n */
    if (err == MP_OKAY)
-       err = mp_mod(mG->x, curve->order, &v);
+       err = mp_mod(mG->x, curve->order, v);
 
    /* does v == r */
    if (err == MP_OKAY) {
-       if (mp_cmp(&v, r) == MP_EQ)
+       if (mp_cmp(v, r) == MP_EQ)
            *res = 1;
    }
@@ -4366,16 +5595,30 @@
    wc_ecc_del_point_h(mQ, key->heap);
 
-   mp_clear(&e);
+   mp_clear(e);
    if (did_init) {
-       mp_clear(&v);
-       mp_clear(&w);
-       mp_clear(&u1);
-       mp_clear(&u2);
-   }
+       mp_clear(v);
+       mp_clear(w);
+       mp_clear(u1);
+       mp_clear(u2);
+   }
+#ifdef WOLFSSL_SMALL_STACK
+   XFREE(u2, key->heap, DYNAMIC_TYPE_ECC);
+   XFREE(u1, key->heap, DYNAMIC_TYPE_ECC);
+   XFREE(w, key->heap, DYNAMIC_TYPE_ECC);
+   XFREE(v, key->heap, DYNAMIC_TYPE_ECC);
+#if !defined(WOLFSSL_ASYNC_CRYPT) || !defined(HAVE_CAVIUM_V)
+   XFREE(e_lcl, key->heap, DYNAMIC_TYPE_ECC);
+#endif
+#endif
 
    wc_ecc_curve_free(curve);
-
+   FREE_CURVE_SPECS();
+
+#endif /* WOLFSSL_SP_MATH */
 #endif /* WOLFSSL_ATECC508A */
 
+   (void)keySz;
+   (void)hashlen;
+
    return err;
 }
@@ -4383,5 +5626,4 @@
 
 #ifdef HAVE_ECC_KEY_IMPORT
-#ifndef WOLFSSL_ATECC508A
 /* import point from der */
 int wc_ecc_import_point_der(byte* in, word32 inLen, const int curve_idx,
@@ -4390,4 +5632,6 @@
     int err = 0;
     int compressed = 0;
+    int keysize;
+    byte pointType;
 
     if (in == NULL || point == NULL || (curve_idx < 0) ||
@@ -4414,10 +5658,12 @@
         return MEMORY_E;
 
-    /* check for 4, 2, or 3 */
-    if (in[0] != 0x04 && in[0] != 0x02 && in[0] != 0x03) {
+    /* check for point type (4, 2, or 3) */
+    pointType = in[0];
+    if (pointType != ECC_POINT_UNCOMP && pointType != ECC_POINT_COMP_EVEN &&
+                                         pointType != ECC_POINT_COMP_ODD) {
         err = ASN_PARSE_E;
     }
 
-    if (in[0] == 0x02 || in[0] == 0x03) {
+    if (pointType == ECC_POINT_COMP_EVEN || pointType == ECC_POINT_COMP_ODD) {
 #ifdef HAVE_COMP_KEY
         compressed = 1;
@@ -4427,13 +5673,23 @@
     }
 
+    /* adjust to skip first byte */
+    inLen -= 1;
+    in += 1;
+
+    /* calculate key size based on inLen / 2 */
+    keysize = inLen>>1;
+
     /* read data */
     if (err == MP_OKAY)
-        err = mp_read_unsigned_bin(point->x, (byte*)in+1, (inLen-1)>>1);
+        err = mp_read_unsigned_bin(point->x, (byte*)in, keysize);
 
 #ifdef HAVE_COMP_KEY
     if (err == MP_OKAY && compressed == 1) {   /* build y */
+#ifndef WOLFSSL_SP_MATH
         int did_init = 0;
         mp_int t1, t2;
-        DECLARE_CURVE_SPECS(3)
+        DECLARE_CURVE_SPECS(curve, 3);
+
+        ALLOC_CURVE_SPECS(3);
 
         if (mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL) != MP_OKAY)
@@ -4470,6 +5726,6 @@
         /* adjust y */
         if (err == MP_OKAY) {
-            if ((mp_isodd(&t2) == MP_YES && in[0] == 0x03) ||
-                (mp_isodd(&t2) == MP_NO && in[0] == 0x02)) {
+            if ((mp_isodd(&t2) == MP_YES && pointType == ECC_POINT_COMP_ODD) ||
+                (mp_isodd(&t2) == MP_NO &&  pointType == ECC_POINT_COMP_EVEN)) {
                 err = mp_mod(&t2, curve->prime, point->y);
             }
@@ -4485,10 +5741,13 @@
 
         wc_ecc_curve_free(curve);
+        FREE_CURVE_SPECS();
+#else
+        sp_ecc_uncompress_256(point->x, pointType, point->y);
+#endif
     }
 #endif
 
     if (err == MP_OKAY && compressed == 0)
-        err = mp_read_unsigned_bin(point->y,
-                                   (byte*)in+1+((inLen-1)>>1), (inLen-1)>>1);
+        err = mp_read_unsigned_bin(point->y, (byte*)in + keysize, keysize);
     if (err == MP_OKAY)
         err = mp_set(point->z, 1);
@@ -4502,5 +5761,4 @@
     return err;
 }
-#endif /* !WOLFSSL_ATECC508A */
 #endif /* HAVE_ECC_KEY_IMPORT */
 
@@ -4512,5 +5770,4 @@
     int    ret = MP_OKAY;
     word32 numlen;
-#ifndef WOLFSSL_ATECC508A
 #ifdef WOLFSSL_SMALL_STACK
     byte*  buf;
@@ -4518,5 +5775,4 @@
     byte   buf[ECC_BUFSIZE];
 #endif
-#endif /* !WOLFSSL_ATECC508A */
 
     if ((curve_idx < 0) || (wc_ecc_is_valid_idx(curve_idx) == 0))
@@ -4540,12 +5796,6 @@
     }
 
-#ifdef WOLFSSL_ATECC508A
-   /* TODO: Implement equiv call to ATECC508A */
-   ret = BAD_COND_E;
-
-#else
-
-    /* store byte 0x04 */
-    out[0] = 0x04;
+    /* store byte point type */
+    out[0] = ECC_POINT_UNCOMP;
 
 #ifdef WOLFSSL_SMALL_STACK
@@ -4577,5 +5827,4 @@
     XFREE(buf, NULL, DYNAMIC_TYPE_ECC_BUFFER);
 #endif
-#endif /* WOLFSSL_ATECC508A */
 
     return ret;
@@ -4588,5 +5837,4 @@
    int    ret = MP_OKAY;
    word32 numlen;
-#ifndef WOLFSSL_ATECC508A
 #ifdef WOLFSSL_SMALL_STACK
    byte*  buf;
@@ -4595,5 +5843,4 @@
 #endif
    word32 pubxlen, pubylen;
-#endif /* WOLFSSL_ATECC508A */
 
    /* return length needed only */
@@ -4620,10 +5867,4 @@
       return BUFFER_E;
    }
-
-#ifdef WOLFSSL_ATECC508A
-   /* TODO: Implement equiv call to ATECC508A */
-   ret = BAD_COND_E;
-
-#else
 
    /* verify public key length is less than key size */
@@ -4635,6 +5876,6 @@
    }
 
-   /* store byte 0x04 */
-   out[0] = 0x04;
+   /* store byte point type */
+   out[0] = ECC_POINT_UNCOMP;
 
 #ifdef WOLFSSL_SMALL_STACK
@@ -4664,5 +5905,4 @@
    XFREE(buf, NULL, DYNAMIC_TYPE_ECC_BUFFER);
 #endif
-#endif /* WOLFSSL_ATECC508A */
 
    return ret;
@@ -4692,8 +5932,29 @@
 int wc_ecc_is_point(ecc_point* ecp, mp_int* a, mp_int* b, mp_int* prime)
 {
+#ifndef WOLFSSL_SP_MATH
    int err;
-   mp_int t1, t2;
-
-   if ((err = mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) {
+#ifdef WOLFSSL_SMALL_STACK
+   mp_int* t1 = NULL;
+   mp_int* t2 = NULL;
+#else
+   mp_int  t1[1], t2[1];
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+   t1 = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+   if (t1 == NULL)
+       return MEMORY_E;
+   t2 = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+   if (t2 == NULL) {
+       XFREE(t1, NULL, DYNAMIC_TYPE_ECC);
+       return MEMORY_E;
+   }
+#endif
+
+   if ((err = mp_init_multi(t1, t2, NULL, NULL, NULL, NULL)) != MP_OKAY) {
+   #ifdef WOLFSSL_SMALL_STACK
+      XFREE(t2, NULL, DYNAMIC_TYPE_ECC);
+      XFREE(t1, NULL, DYNAMIC_TYPE_ECC);
+   #endif
       return err;
    }
@@ -4701,17 +5962,17 @@
    /* compute y^2 */
    if (err == MP_OKAY)
-       err = mp_sqr(ecp->y, &t1);
+       err = mp_sqr(ecp->y, t1);
 
    /* compute x^3 */
    if (err == MP_OKAY)
-       err = mp_sqr(ecp->x, &t2);
-   if (err == MP_OKAY)
-       err = mp_mod(&t2, prime, &t2);
-   if (err == MP_OKAY)
-       err = mp_mul(ecp->x, &t2, &t2);
+       err = mp_sqr(ecp->x, t2);
+   if (err == MP_OKAY)
+       err = mp_mod(t2, prime, t2);
+   if (err == MP_OKAY)
+       err = mp_mul(ecp->x, t2, t2);
 
    /* compute y^2 - x^3 */
    if (err == MP_OKAY)
-       err = mp_sub(&t1, &t2, &t1);
+       err = mp_sub(t1, t2, t1);
 
    /* Determine if curve "a" should be used in calc */
@@ -4719,14 +5980,14 @@
    if (err == MP_OKAY) {
       /* Use a and prime to determine if a == 3 */
-      err = mp_set(&t2, 0);
+      err = mp_set(t2, 0);
       if (err == MP_OKAY)
-          err = mp_submod(prime, a, prime, &t2);
-   }
-   if (err == MP_OKAY && mp_cmp_d(&t2, 3) != MP_EQ) {
+          err = mp_submod(prime, a, prime, t2);
+   }
+   if (err == MP_OKAY && mp_cmp_d(t2, 3) != MP_EQ) {
       /* compute y^2 - x^3 + a*x */
       if (err == MP_OKAY)
-          err = mp_mulmod(&t2, ecp->x, prime, &t2);
+          err = mp_mulmod(t2, ecp->x, prime, t2);
       if (err == MP_OKAY)
-          err = mp_addmod(&t1, &t2, prime, &t1);
+          err = mp_addmod(t1, t2, prime, t1);
    }
    else
@@ -4738,24 +5999,24 @@
       /* compute y^2 - x^3 + 3x */
       if (err == MP_OKAY)
-          err = mp_add(&t1, ecp->x, &t1);
+          err = mp_add(t1, ecp->x, t1);
       if (err == MP_OKAY)
-          err = mp_add(&t1, ecp->x, &t1);
+          err = mp_add(t1, ecp->x, t1);
       if (err == MP_OKAY)
-          err = mp_add(&t1, ecp->x, &t1);
+          err = mp_add(t1, ecp->x, t1);
       if (err == MP_OKAY)
-          err = mp_mod(&t1, prime, &t1);
+          err = mp_mod(t1, prime, t1);
   }
 
    /* adjust range (0, prime) */
-   while (err == MP_OKAY && mp_isneg(&t1)) {
-      err = mp_add(&t1, prime, &t1);
-   }
-   while (err == MP_OKAY && mp_cmp(&t1, prime) != MP_LT) {
-      err = mp_sub(&t1, prime, &t1);
+   while (err == MP_OKAY && mp_isneg(t1)) {
+      err = mp_add(t1, prime, t1);
+   }
+   while (err == MP_OKAY && mp_cmp(t1, prime) != MP_LT) {
+      err = mp_sub(t1, prime, t1);
    }
 
    /* compare to b */
    if (err == MP_OKAY) {
-       if (mp_cmp(&t1, b) != MP_EQ) {
+       if (mp_cmp(t1, b) != MP_EQ) {
           err = MP_VAL;
        } else {
@@ -4764,11 +6025,22 @@
    }
 
-   mp_clear(&t1);
-   mp_clear(&t2);
+   mp_clear(t1);
+   mp_clear(t2);
+#ifdef WOLFSSL_SMALL_STACK
+   XFREE(t2, NULL, DYNAMIC_TYPE_ECC);
+   XFREE(t1, NULL, DYNAMIC_TYPE_ECC);
+#endif
 
    return err;
-}
-
-
+#else
+   (void)a;
+   (void)b;
+   (void)prime;
+
+   return sp_ecc_is_point_256(ecp->x, ecp->y);
+#endif
+}
+
+#ifndef WOLFSSL_SP_MATH
 /* validate privkey * generator == pubkey, 0 on success */
 static int ecc_check_privkey_gen(ecc_key* key, mp_int* a, mp_int* prime)
@@ -4777,8 +6049,10 @@
     ecc_point* base = NULL;
     ecc_point* res  = NULL;
-    DECLARE_CURVE_SPECS(2)
+    DECLARE_CURVE_SPECS(curve, 2);
 
     if (key == NULL)
         return BAD_FUNC_ARG;
+
+    ALLOC_CURVE_SPECS(2);
 
     res = wc_ecc_new_point_h(key->heap);
@@ -4831,7 +6105,9 @@
     wc_ecc_del_point_h(res, key->heap);
     wc_ecc_del_point_h(base, key->heap);
+    FREE_CURVE_SPECS();
 
     return err;
 }
+#endif
 
 #ifdef WOLFSSL_VALIDATE_ECC_IMPORT
@@ -4842,5 +6118,5 @@
     int    err;
 #ifndef WOLFSSL_ATECC508A
-    DECLARE_CURVE_SPECS(2)
+    DECLARE_CURVE_SPECS(curve, 2);
 #endif
 
@@ -4849,8 +6125,9 @@
 
 #ifdef WOLFSSL_ATECC508A
-    /* TODO: Implement equiv call to ATECC508A */
-    err = BAD_COND_E;
+    /* Hardware based private key, so this operation is not supported */
+    err = MP_OKAY; /* just report success */
 
 #else
+    ALLOC_CURVE_SPECS(2);
 
     /* load curve info */
@@ -4862,4 +6139,5 @@
 
     wc_ecc_curve_free(curve);
+    FREE_CURVE_SPECS();
 
 #endif /* WOLFSSL_ATECC508A */
@@ -4871,4 +6149,5 @@
 
 
+#if defined(WOLFSSL_VALIDATE_ECC_KEYGEN) || !defined(WOLFSSL_SP_MATH)
 /* validate order * pubkey = point at infinity, 0 on success */
 static int ecc_check_pubkey_order(ecc_key* key, ecc_point* pubkey, mp_int* a,
@@ -4894,7 +6173,14 @@
 #endif
 #endif
+#ifndef WOLFSSL_SP_MATH
             err = wc_ecc_mulmod_ex(order, pubkey, inf, a, prime, 1, key->heap);
         if (err == MP_OKAY && !wc_ecc_point_is_at_infinity(inf))
             err = ECC_INF_E;
+#else
+            (void)a;
+            (void)prime;
+
+            err = WC_KEY_SIZE_E;
+#endif
     }
 
@@ -4903,5 +6189,5 @@
     return err;
 }
-
+#endif
 #endif /* !WOLFSSL_ATECC508A */
 
@@ -4911,14 +6197,15 @@
 {
     int    err;
+#ifndef WOLFSSL_SP_MATH
 #ifndef WOLFSSL_ATECC508A
-    mp_int* b;
+    mp_int* b = NULL;
 #ifdef USE_ECC_B_PARAM
-    DECLARE_CURVE_SPECS(4)
+    DECLARE_CURVE_SPECS(curve, 4);
 #else
+#ifndef WOLFSSL_SMALL_STACK
     mp_int b_lcl;
-    DECLARE_CURVE_SPECS(3)
-    b = &b_lcl;
-    XMEMSET(b, 0, sizeof(mp_int));
-#endif
+#endif
+    DECLARE_CURVE_SPECS(curve, 3);
+#endif /* USE_ECC_B_PARAM */
 #endif /* WOLFSSL_ATECC508A */
 
@@ -4928,14 +6215,32 @@
 #ifdef WOLFSSL_ATECC508A
 
-    if (key->slot == ATECC_INVALID_SLOT)
-        return ECC_BAD_ARG_E;
-
-    err = 0; /* consider key check success on ECC508A */
+    err = 0; /* consider key check success on ATECC508A */
 
 #else
-
+    #ifdef USE_ECC_B_PARAM
+        ALLOC_CURVE_SPECS(4);
+    #else
+        ALLOC_CURVE_SPECS(3);
+        #ifndef WOLFSSL_SMALL_STACK
+            b = &b_lcl;
+        #else
+            b = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC);
+            if (b == NULL) {
+                FREE_CURVE_SPECS();
+                return MEMORY_E;
+            }
+        #endif
+        XMEMSET(b, 0, sizeof(mp_int));
+    #endif
+
+    /* SP 800-56Ar3, section 5.6.2.3.3, process step 1 */
     /* pubkey point cannot be at infinity */
-    if (wc_ecc_point_is_at_infinity(&key->pubkey))
+    if (wc_ecc_point_is_at_infinity(&key->pubkey)) {
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(b, key->heap, DYNAMIC_TYPE_ECC);
+    #endif
+        FREE_CURVE_SPECS();
         return ECC_INF_E;
+    }
 
     /* load curve info */
@@ -4952,9 +6257,10 @@
         err = mp_init(b);
     if (err == MP_OKAY)
-        err = mp_read_radix(b, key->dp->Bf, 16);
+        err = mp_read_radix(b, key->dp->Bf, MP_RADIX_HEX);
 #else
     b = curve->Bf;
 #endif
 
+    /* SP 800-56Ar3, section 5.6.2.3.3, process step 2 */
     /* Qx must be in the range [0, p-1] */
     if (mp_cmp(key->pubkey.x, curve->prime) != MP_LT)
@@ -4965,8 +6271,10 @@
         err = ECC_OUT_OF_RANGE_E;
 
+    /* SP 800-56Ar3, section 5.6.2.3.3, process steps 3 */
     /* make sure point is actually on curve */
     if (err == MP_OKAY)
         err = wc_ecc_is_point(&key->pubkey, curve->Af, b, curve->prime);
 
+    /* SP 800-56Ar3, section 5.6.2.3.3, process steps 4 */
     /* pubkey * order must be at infinity */
     if (err == MP_OKAY)
@@ -4974,4 +6282,5 @@
                 curve->order);
 
+    /* SP 800-56Ar3, section 5.6.2.1.4, method (b) for ECC */
     /* private * base generator must equal pubkey */
     if (err == MP_OKAY && key->type == ECC_PRIVATEKEY)
@@ -4982,7 +6291,24 @@
 #ifndef USE_ECC_B_PARAM
     mp_clear(b);
-#endif
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(b, key->heap, DYNAMIC_TYPE_ECC);
+#endif
+#endif
+
+    FREE_CURVE_SPECS();
 
 #endif /* WOLFSSL_ATECC508A */
+#else
+    if (key == NULL)
+        return BAD_FUNC_ARG;
+
+    /* pubkey point cannot be at infinity */
+    if (key->idx != ECC_CUSTOM_IDX && ecc_sets[key->idx].id == ECC_SECP256R1) {
+        err = sp_ecc_check_key_256(key->pubkey.x, key->pubkey.y, &key->k,
+                                                                     key->heap);
+    }
+    else
+        err = WC_KEY_SIZE_E;
+#endif
 
     return err;
@@ -4995,7 +6321,7 @@
 {
     int err = MP_OKAY;
-#ifndef WOLFSSL_ATECC508A
     int compressed = 0;
-#endif /* !WOLFSSL_ATECC508A */
+    int keysize = 0;
+    byte pointType;
 
     if (in == NULL || key == NULL)
@@ -5009,10 +6335,4 @@
     /* make sure required variables are reset */
     wc_ecc_reset(key);
-
-#ifdef WOLFSSL_ATECC508A
-    /* TODO: Implement equiv call to ATECC508A */
-    err = BAD_COND_E;
-
-#else
 
     /* init key */
@@ -5032,10 +6352,12 @@
         return MEMORY_E;
 
-    /* check for 4, 2, or 3 */
-    if (in[0] != 0x04 && in[0] != 0x02 && in[0] != 0x03) {
+    /* check for point type (4, 2, or 3) */
+    pointType = in[0];
+    if (pointType != ECC_POINT_UNCOMP && pointType != ECC_POINT_COMP_EVEN &&
+                                         pointType != ECC_POINT_COMP_ODD) {
         err = ASN_PARSE_E;
     }
 
-    if (in[0] == 0x02 || in[0] == 0x03) {
+    if (pointType == ECC_POINT_COMP_EVEN || pointType == ECC_POINT_COMP_ODD) {
     #ifdef HAVE_COMP_KEY
         compressed = 1;
@@ -5045,14 +6367,25 @@
     }
 
+    /* adjust to skip first byte */
+    inLen -= 1;
+    in += 1;
+
+#ifdef WOLFSSL_ATECC508A
+    /* For SECP256R1 only save raw public key for hardware */
+    if (curve_id == ECC_SECP256R1 && !compressed &&
+                                            inLen <= sizeof(key->pubkey_raw)) {
+        XMEMCPY(key->pubkey_raw, (byte*)in, inLen);
+    }
+#endif
+
     if (err == MP_OKAY) {
-        int keysize;
     #ifdef HAVE_COMP_KEY
         /* adjust inLen if compressed */
         if (compressed)
-            inLen = (inLen-1)*2 + 1;  /* used uncompressed len */
+            inLen = inLen*2 + 1;  /* used uncompressed len */
     #endif
 
         /* determine key size */
-        keysize = ((inLen-1)>>1);
+        keysize = (inLen>>1);
         err = wc_ecc_set_curve(key, keysize, curve_id);
         key->type = ECC_PUBLICKEY;
@@ -5061,12 +6394,14 @@
     /* read data */
     if (err == MP_OKAY)
-        err = mp_read_unsigned_bin(key->pubkey.x, (byte*)in+1, (inLen-1)>>1);
+        err = mp_read_unsigned_bin(key->pubkey.x, (byte*)in, keysize);
 
 #ifdef HAVE_COMP_KEY
     if (err == MP_OKAY && compressed == 1) {   /* build y */
+#ifndef WOLFSSL_SP_MATH
         mp_int t1, t2;
         int did_init = 0;
 
-        DECLARE_CURVE_SPECS(3)
+        DECLARE_CURVE_SPECS(curve, 3);
+        ALLOC_CURVE_SPECS(3);
 
         if (mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL) != MP_OKAY)
@@ -5103,6 +6438,6 @@
         /* adjust y */
         if (err == MP_OKAY) {
-            if ((mp_isodd(&t2) == MP_YES && in[0] == 0x03) ||
-                (mp_isodd(&t2) == MP_NO && in[0] == 0x02)) {
+            if ((mp_isodd(&t2) == MP_YES && pointType == ECC_POINT_COMP_ODD) ||
+                (mp_isodd(&t2) == MP_NO &&  pointType == ECC_POINT_COMP_EVEN)) {
                 err = mp_mod(&t2, curve->prime, &t2);
             }
@@ -5120,10 +6455,13 @@
 
         wc_ecc_curve_free(curve);
+        FREE_CURVE_SPECS();
+#else
+        sp_ecc_uncompress_256(key->pubkey.x, pointType, key->pubkey.y);
+#endif
     }
 #endif /* HAVE_COMP_KEY */
 
     if (err == MP_OKAY && compressed == 0)
-        err = mp_read_unsigned_bin(key->pubkey.y, (byte*)in+1+((inLen-1)>>1),
-                                                                (inLen-1)>>1);
+        err = mp_read_unsigned_bin(key->pubkey.y, (byte*)in + keysize, keysize);
     if (err == MP_OKAY)
         err = mp_set(key->pubkey.z, 1);
@@ -5140,8 +6478,7 @@
         mp_clear(&key->k);
     }
-#endif /* WOLFSSL_ATECC508A */
 
     return err;
-}
+    }
 
 int wc_ecc_import_x963(const byte* in, word32 inLen, ecc_key* key)
@@ -5152,148 +6489,96 @@
 
 #ifdef HAVE_ECC_KEY_EXPORT
-/* export ecc private key only raw, outLen is in/out size
+
+/* export ecc key to component form, d is optional if only exporting public
+ * encType is WC_TYPE_UNSIGNED_BIN or WC_TYPE_HEX_STR
+ * return MP_OKAY on success */
+int wc_ecc_export_ex(ecc_key* key, byte* qx, word32* qxLen,
+                 byte* qy, word32* qyLen, byte* d, word32* dLen, int encType)
+{
+    int err = 0;
+    word32 keySz;
+
+    if (key == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    if (wc_ecc_is_valid_idx(key->idx) == 0) {
+        return ECC_BAD_ARG_E;
+    }
+    keySz = key->dp->size;
+
+    /* private key, d */
+    if (d != NULL) {
+        if (dLen == NULL ||
+            (key->type != ECC_PRIVATEKEY && key->type != ECC_PRIVATEKEY_ONLY))
+            return BAD_FUNC_ARG;
+
+    #ifdef WOLFSSL_ATECC508A
+        /* Hardware cannot export private portion */
+        return NOT_COMPILED_IN;
+    #else
+        err = wc_export_int(&key->k, d, dLen, keySz, encType);
+        if (err != MP_OKAY)
+            return err;
+    #endif
+    }
+
+    /* public x component */
+    if (qx != NULL) {
+        if (qxLen == NULL || key->type == ECC_PRIVATEKEY_ONLY)
+            return BAD_FUNC_ARG;
+
+        err = wc_export_int(key->pubkey.x, qx, qxLen, keySz, encType);
+    if (err != MP_OKAY)
+        return err;
+    }
+
+    /* public y component */
+    if (qy != NULL) {
+        if (qyLen == NULL || key->type == ECC_PRIVATEKEY_ONLY)
+            return BAD_FUNC_ARG;
+
+        err = wc_export_int(key->pubkey.y, qy, qyLen, keySz, encType);
+    if (err != MP_OKAY)
+        return err;
+    }
+
+    return err;
+}
+
+
+/* export ecc private key only raw, outLen is in/out size as unsigned bin
    return MP_OKAY on success */
 int wc_ecc_export_private_only(ecc_key* key, byte* out, word32* outLen)
 {
-    word32 numlen;
-
-    if (key == NULL || out == NULL || outLen == NULL) {
+    if (out == NULL || outLen == NULL) {
         return BAD_FUNC_ARG;
-    }
-
-    if (wc_ecc_is_valid_idx(key->idx) == 0) {
-        return ECC_BAD_ARG_E;
-    }
-    numlen = key->dp->size;
-
-    if (*outLen < numlen) {
-        *outLen = numlen;
-        return BUFFER_E;
-    }
-    *outLen = numlen;
-    XMEMSET(out, 0, *outLen);
-
-#ifdef WOLFSSL_ATECC508A
-   /* TODO: Implement equiv call to ATECC508A */
-   return BAD_COND_E;
-
-#else
-
-    return mp_to_unsigned_bin(&key->k, out + (numlen -
-                                           mp_unsigned_bin_size(&key->k)));
-#endif /* WOLFSSL_ATECC508A */
-}
-
-
-/* export ecc key to component form, d is optional if only exporting public
- * return MP_OKAY on success */
-static int wc_ecc_export_raw(ecc_key* key, byte* qx, word32* qxLen,
-                             byte* qy, word32* qyLen, byte* d, word32* dLen)
-{
-    int  err;
-    byte exportPriv = 0;
-    word32 numLen;
-
-    if (key == NULL || qx == NULL || qxLen == NULL || qy == NULL ||
-        qyLen == NULL) {
-        return BAD_FUNC_ARG;
-    }
-
-    if (key->type == ECC_PRIVATEKEY_ONLY) {
-        return ECC_PRIVATEONLY_E;
-    }
-
-    if (wc_ecc_is_valid_idx(key->idx) == 0) {
-        return ECC_BAD_ARG_E;
-    }
-    numLen = key->dp->size;
-
-    if (d != NULL) {
-        if (dLen == NULL || key->type != ECC_PRIVATEKEY)
-            return BAD_FUNC_ARG;
-        exportPriv = 1;
-    }
-
-    /* check public buffer sizes */
-    if ((*qxLen < numLen) || (*qyLen < numLen)) {
-        *qxLen = numLen;
-        *qyLen = numLen;
-        return BUFFER_E;
-    }
-
-    *qxLen = numLen;
-    *qyLen = numLen;
-
-    XMEMSET(qx, 0, *qxLen);
-    XMEMSET(qy, 0, *qyLen);
-
-    /* private d component */
-    if (exportPriv == 1) {
-
-        /* check private buffer size */
-        if (*dLen < numLen) {
-            *dLen = numLen;
-            return BUFFER_E;
-        }
-
-        *dLen = numLen;
-        XMEMSET(d, 0, *dLen);
-
-    #ifdef WOLFSSL_ATECC508A
-       /* TODO: Implement equiv call to ATECC508A */
-       return BAD_COND_E;
-
-    #else
-
-        /* private key, d */
-        err = mp_to_unsigned_bin(&key->k, d +
-                            (numLen - mp_unsigned_bin_size(&key->k)));
-        if (err != MP_OKAY)
-            return err;
-    #endif /* WOLFSSL_ATECC508A */
-    }
-
-#ifdef WOLFSSL_ATECC508A
-    /* TODO: Implement equiv call to ATECC508A */
-    return BAD_COND_E;
-
-#else
-
-    /* public x component */
-    err = mp_to_unsigned_bin(key->pubkey.x, qx +
-                            (numLen - mp_unsigned_bin_size(key->pubkey.x)));
-    if (err != MP_OKAY)
-        return err;
-
-    /* public y component */
-    err = mp_to_unsigned_bin(key->pubkey.y, qy +
-                            (numLen - mp_unsigned_bin_size(key->pubkey.y)));
-    if (err != MP_OKAY)
-        return err;
-
-    return 0;
-#endif /* WOLFSSL_ATECC508A */
-}
-
-
-/* export public key to raw elements including public (Qx,Qy)
+}
+
+    return wc_ecc_export_ex(key, NULL, NULL, NULL, NULL, out, outLen,
+        WC_TYPE_UNSIGNED_BIN);
+}
+
+/* export public key to raw elements including public (Qx,Qy) as unsigned bin
  * return MP_OKAY on success, negative on error */
 int wc_ecc_export_public_raw(ecc_key* key, byte* qx, word32* qxLen,
                              byte* qy, word32* qyLen)
 {
-    return wc_ecc_export_raw(key, qx, qxLen, qy, qyLen, NULL, NULL);
-}
-
-
-/* export ecc key to raw elements including public (Qx,Qy) and private (d)
+    if (qx == NULL || qxLen == NULL || qy == NULL || qyLen == NULL) {
+        return BAD_FUNC_ARG;
+}
+
+    return wc_ecc_export_ex(key, qx, qxLen, qy, qyLen, NULL, NULL,
+        WC_TYPE_UNSIGNED_BIN);
+}
+
+/* export ecc key to raw elements including public (Qx,Qy) and
+ *   private (d) as unsigned bin
  * return MP_OKAY on success, negative on error */
 int wc_ecc_export_private_raw(ecc_key* key, byte* qx, word32* qxLen,
                               byte* qy, word32* qyLen, byte* d, word32* dLen)
 {
-    /* sanitize d and dLen, other args are checked later */
-    if (d == NULL || dLen == NULL)
-        return BAD_FUNC_ARG;
-
-    return wc_ecc_export_raw(key, qx, qxLen, qy, qyLen, d, dLen);
+    return wc_ecc_export_ex(key, qx, qxLen, qy, qyLen, d, dLen,
+        WC_TYPE_UNSIGNED_BIN);
 }
 
@@ -5307,14 +6592,17 @@
 {
     int ret;
+    word32 idx = 0;
+
+    if (key == NULL || priv == NULL)
+        return BAD_FUNC_ARG;
 
     /* public optional, NULL if only importing private */
     if (pub != NULL) {
         ret = wc_ecc_import_x963_ex(pub, pubSz, key, curve_id);
+        if (ret < 0)
+            ret = wc_EccPublicKeyDecode(pub, &idx, key, pubSz);
         key->type = ECC_PRIVATEKEY;
     }
     else {
-        if (key == NULL || priv == NULL)
-            return BAD_FUNC_ARG;
-
         /* make sure required variables are reset */
         wc_ecc_reset(key);
@@ -5328,12 +6616,19 @@
         return ret;
 
-
 #ifdef WOLFSSL_ATECC508A
-    /* TODO: Implement equiv call to ATECC508A */
-    return BAD_COND_E;
+    /* Hardware does not support loading private keys */
+    return NOT_COMPILED_IN;
 
 #else
 
     ret = mp_read_unsigned_bin(&key->k, priv, privSz);
+#ifdef HAVE_WOLF_BIGINT
+    if (ret == 0 &&
+                  wc_bigint_from_unsigned_bin(&key->k.raw, priv, privSz) != 0) {
+        mp_clear(&key->k);
+        ret = ASN_GETINT_E;
+    }
+#endif /* HAVE_WOLF_BIGINT */
+
 
 #endif /* WOLFSSL_ATECC508A */
@@ -5369,33 +6664,125 @@
 {
     int err;
-    mp_int rtmp;
-    mp_int stmp;
+#ifdef WOLFSSL_SMALL_STACK
+    mp_int* rtmp = NULL;
+    mp_int* stmp = NULL;
+#else
+    mp_int  rtmp[1];
+    mp_int  stmp[1];
+#endif
 
     if (r == NULL || s == NULL || out == NULL || outlen == NULL)
         return ECC_BAD_ARG_E;
 
-    err = mp_init_multi(&rtmp, &stmp, NULL, NULL, NULL, NULL);
-    if (err != MP_OKAY)
+#ifdef WOLFSSL_SMALL_STACK
+    rtmp = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+    if (rtmp == NULL)
+        return MEMORY_E;
+    stmp = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+    if (stmp == NULL) {
+        XFREE(rtmp, NULL, DYNAMIC_TYPE_ECC);
+        return MEMORY_E;
+    }
+#endif
+
+    err = mp_init_multi(rtmp, stmp, NULL, NULL, NULL, NULL);
+    if (err != MP_OKAY) {
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(stmp, NULL, DYNAMIC_TYPE_ECC);
+        XFREE(rtmp, NULL, DYNAMIC_TYPE_ECC);
+    #endif
         return err;
-
-    err = mp_read_radix(&rtmp, r, 16);
+    }
+
+    err = mp_read_radix(rtmp, r, MP_RADIX_HEX);
     if (err == MP_OKAY)
-        err = mp_read_radix(&stmp, s, 16);
+        err = mp_read_radix(stmp, s, MP_RADIX_HEX);
 
     /* convert mp_ints to ECDSA sig, initializes rtmp and stmp internally */
     if (err == MP_OKAY)
-        err = StoreECC_DSA_Sig(out, outlen, &rtmp, &stmp);
+        err = StoreECC_DSA_Sig(out, outlen, rtmp, stmp);
 
     if (err == MP_OKAY) {
-        if (mp_iszero(&rtmp) == MP_YES || mp_iszero(&stmp) == MP_YES)
+        if (mp_iszero(rtmp) == MP_YES || mp_iszero(stmp) == MP_YES)
             err = MP_ZERO_E;
     }
 
-    mp_clear(&rtmp);
-    mp_clear(&stmp);
+    mp_clear(rtmp);
+    mp_clear(stmp);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(stmp, NULL, DYNAMIC_TYPE_ECC);
+    XFREE(rtmp, NULL, DYNAMIC_TYPE_ECC);
+#endif
 
     return err;
 }
 
+/**
+   Convert ECC R,S raw unsigned bin to signature
+   r       R component of signature
+   rSz     R size
+   s       S component of signature
+   sSz     S size
+   out     DER-encoded ECDSA signature
+   outlen  [in/out] output buffer size, output signature size
+   return  MP_OKAY on success
+*/
+int wc_ecc_rs_raw_to_sig(const byte* r, word32 rSz, const byte* s, word32 sSz,
+    byte* out, word32* outlen)
+{
+    int err;
+#ifdef WOLFSSL_SMALL_STACK
+    mp_int* rtmp = NULL;
+    mp_int* stmp = NULL;
+#else
+    mp_int  rtmp[1];
+    mp_int  stmp[1];
+#endif
+
+    if (r == NULL || s == NULL || out == NULL || outlen == NULL)
+        return ECC_BAD_ARG_E;
+
+#ifdef WOLFSSL_SMALL_STACK
+    rtmp = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+    if (rtmp == NULL)
+        return MEMORY_E;
+    stmp = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+    if (stmp == NULL) {
+        XFREE(rtmp, NULL, DYNAMIC_TYPE_ECC);
+        return MEMORY_E;
+    }
+#endif
+
+    err = mp_init_multi(rtmp, stmp, NULL, NULL, NULL, NULL);
+    if (err != MP_OKAY) {
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(stmp, NULL, DYNAMIC_TYPE_ECC);
+        XFREE(rtmp, NULL, DYNAMIC_TYPE_ECC);
+    #endif
+    return err;
+}
+
+    err = mp_read_unsigned_bin(rtmp, r, rSz);
+    if (err == MP_OKAY)
+        err = mp_read_unsigned_bin(stmp, s, sSz);
+
+    /* convert mp_ints to ECDSA sig, initializes rtmp and stmp internally */
+    if (err == MP_OKAY)
+        err = StoreECC_DSA_Sig(out, outlen, rtmp, stmp);
+
+    if (err == MP_OKAY) {
+        if (mp_iszero(rtmp) == MP_YES || mp_iszero(stmp) == MP_YES)
+            err = MP_ZERO_E;
+    }
+
+    mp_clear(rtmp);
+    mp_clear(stmp);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(stmp, NULL, DYNAMIC_TYPE_ECC);
+    XFREE(rtmp, NULL, DYNAMIC_TYPE_ECC);
+#endif
+
+    return err;
+}
 
 /**
@@ -5414,15 +6801,31 @@
     int err;
     word32 x = 0;
-    mp_int rtmp;
-    mp_int stmp;
+#ifdef WOLFSSL_SMALL_STACK
+    mp_int* rtmp = NULL;
+    mp_int* stmp = NULL;
+#else
+    mp_int  rtmp[1];
+    mp_int  stmp[1];
+#endif
 
     if (sig == NULL || r == NULL || rLen == NULL || s == NULL || sLen == NULL)
         return ECC_BAD_ARG_E;
 
-    err = DecodeECC_DSA_Sig(sig, sigLen, &rtmp, &stmp);
+#ifdef WOLFSSL_SMALL_STACK
+    rtmp = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+    if (rtmp == NULL)
+        return MEMORY_E;
+    stmp = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC);
+    if (stmp == NULL) {
+        XFREE(rtmp, NULL, DYNAMIC_TYPE_ECC);
+        return MEMORY_E;
+    }
+#endif
+
+    err = DecodeECC_DSA_Sig(sig, sigLen, rtmp, stmp);
 
     /* extract r */
     if (err == MP_OKAY) {
-        x = mp_unsigned_bin_size(&rtmp);
+        x = mp_unsigned_bin_size(rtmp);
         if (*rLen < x)
             err = BUFFER_E;
@@ -5430,5 +6833,5 @@
         if (err == MP_OKAY) {
             *rLen = x;
-            err = mp_to_unsigned_bin(&rtmp, r);
+            err = mp_to_unsigned_bin(rtmp, r);
         }
     }
@@ -5436,5 +6839,5 @@
     /* extract s */
     if (err == MP_OKAY) {
-        x = mp_unsigned_bin_size(&stmp);
+        x = mp_unsigned_bin_size(stmp);
         if (*sLen < x)
             err = BUFFER_E;
@@ -5442,10 +6845,14 @@
         if (err == MP_OKAY) {
             *sLen = x;
-            err = mp_to_unsigned_bin(&stmp, s);
+            err = mp_to_unsigned_bin(stmp, s);
         }
     }
 
-    mp_clear(&rtmp);
-    mp_clear(&stmp);
+    mp_clear(rtmp);
+    mp_clear(stmp);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(stmp, NULL, DYNAMIC_TYPE_ECC);
+    XFREE(rtmp, NULL, DYNAMIC_TYPE_ECC);
+#endif
 
     return err;
@@ -5455,5 +6862,5 @@
 #ifdef HAVE_ECC_KEY_IMPORT
 static int wc_ecc_import_raw_private(ecc_key* key, const char* qx,
-          const char* qy, const char* d, int curve_id)
+          const char* qy, const char* d, int curve_id, int encType)
 {
     int err = MP_OKAY;
@@ -5472,10 +6879,4 @@
         return err;
     }
-
-#ifdef WOLFSSL_ATECC508A
-    /* TODO: Implement equiv call to ATECC508A */
-    err = BAD_COND_E;
-
-#else
 
     /* init key */
@@ -5496,19 +6897,52 @@
 
     /* read Qx */
-    if (err == MP_OKAY)
-        err = mp_read_radix(key->pubkey.x, qx, 16);
+    if (err == MP_OKAY) {
+        if (encType == WC_TYPE_HEX_STR)
+            err = mp_read_radix(key->pubkey.x, qx, MP_RADIX_HEX);
+        else
+            err = mp_read_unsigned_bin(key->pubkey.x, (const byte*)qx,
+                key->dp->size);
+    }
 
     /* read Qy */
-    if (err == MP_OKAY)
-        err = mp_read_radix(key->pubkey.y, qy, 16);
+    if (err == MP_OKAY) {
+        if (encType == WC_TYPE_HEX_STR)
+            err = mp_read_radix(key->pubkey.y, qy, MP_RADIX_HEX);
+        else
+            err = mp_read_unsigned_bin(key->pubkey.y, (const byte*)qy,
+                key->dp->size);
+
+    }
 
     if (err == MP_OKAY)
         err = mp_set(key->pubkey.z, 1);
+
+#ifdef WOLFSSL_ATECC508A
+    /* For SECP256R1 only save raw public key for hardware */
+    if (err == MP_OKAY && curve_id == ECC_SECP256R1) {
+        word32 keySz = key->dp->size;
+        err = wc_export_int(key->pubkey.x, key->pubkey_raw,
+            &keySz, keySz, WC_TYPE_UNSIGNED_BIN);
+        if (err == MP_OKAY)
+            err = wc_export_int(key->pubkey.y, &key->pubkey_raw[keySz],
+                &keySz, keySz, WC_TYPE_UNSIGNED_BIN);
+    }
+#endif
 
     /* import private key */
     if (err == MP_OKAY) {
         if (d != NULL) {
+        #ifdef WOLFSSL_ATECC508A
+            /* Hardware doesn't support loading private key */
+            err = NOT_COMPILED_IN;
+        #else
             key->type = ECC_PRIVATEKEY;
-            err = mp_read_radix(&key->k, d, 16);
+
+            if (encType == WC_TYPE_HEX_STR)
+                err = mp_read_radix(&key->k, d, MP_RADIX_HEX);
+            else
+                err = mp_read_unsigned_bin(&key->k, (const byte*)d,
+                    key->dp->size);
+        #endif /* WOLFSSL_ATECC508A */
         } else {
             key->type = ECC_PUBLICKEY;
@@ -5527,5 +6961,4 @@
         mp_clear(&key->k);
     }
-#endif /* WOLFSSL_ATECC508A */
 
     return err;
@@ -5545,6 +6978,15 @@
                    const char* d, int curve_id)
 {
-    return wc_ecc_import_raw_private(key, qx, qy, d, curve_id);
-
+    return wc_ecc_import_raw_private(key, qx, qy, d, curve_id,
+        WC_TYPE_HEX_STR);
+
+}
+
+/* Import x, y and optional private (d) as unsigned binary */
+int wc_ecc_import_unsigned(ecc_key* key, byte* qx, byte* qy,
+                   byte* d, int curve_id)
+{
+    return wc_ecc_import_raw_private(key, (const char*)qx, (const char*)qy,
+        (const char*)d, curve_id, WC_TYPE_UNSIGNED_BIN);
 }
 
@@ -5581,5 +7023,6 @@
         err = ASN_PARSE_E;
     } else {
-        return wc_ecc_import_raw_private(key, qx, qy, d, ecc_sets[x].id);
+        return wc_ecc_import_raw_private(key, qx, qy, d, ecc_sets[x].id,
+            WC_TYPE_HEX_STR);
     }
 
@@ -5596,4 +7039,8 @@
 }
 
+int wc_ecc_sig_size_calc(int sz)
+{
+    return (sz * 2) + SIG_HEADER_SZ + ECC_MAX_PAD_SZ;
+}
 
 /* worst case estimate, check actual return from wc_ecc_sign_hash for actual
@@ -5605,5 +7052,5 @@
         return sz;
 
-    return (sz * 2) + SIG_HEADER_SZ + ECC_MAX_PAD_SZ;
+    return wc_ecc_sig_size_calc(sz);
 }
 
@@ -5633,4 +7080,6 @@
 #endif
 
+
+#ifndef WOLFSSL_SP_MATH
 
 /** Our FP cache */
@@ -6182,4 +7631,5 @@
 };
 
+
 /* find a hole and free as required, return -1 if no hole found */
 static int find_hole(void)
@@ -6271,5 +7721,7 @@
    return MP_OKAY;
 }
-
+#endif
+
+#ifndef WOLFSSL_SP_MATH
 /* build the LUT by spacing the bits of the input by #modulus/FP_LUT bits apart
  *
@@ -6441,5 +7893,6 @@
       if (y == 66) --x;
 
-      if ((err = mp_read_radix(&order, ecc_sets[x].order, 16)) != MP_OKAY) {
+      if ((err = mp_read_radix(&order, ecc_sets[x].order,
+                                                MP_RADIX_HEX)) != MP_OKAY) {
          goto done;
       }
@@ -6492,5 +7945,5 @@
 
       while ((unsigned)x < y) {
-         z = kb[x]; kb[x] = kb[y]; kb[y] = z;
+         z = kb[x]; kb[x] = kb[y]; kb[y] = (byte)z;
          ++x; --y;
       }
@@ -6559,6 +8012,8 @@
    return err;
 }
+#endif
 
 #ifdef ECC_SHAMIR
+#ifndef WOLFSSL_SP_MATH
 /* perform a fixed point ECC mulmod */
 static int accel_fp_mul2add(int idx1, int idx2,
@@ -6592,5 +8047,6 @@
       if (y == 66) --x;
 
-      if ((err = mp_read_radix(&order, ecc_sets[x].order, 16)) != MP_OKAY) {
+      if ((err = mp_read_radix(&order, ecc_sets[x].order,
+                                                MP_RADIX_HEX)) != MP_OKAY) {
          goto done;
       }
@@ -6623,5 +8079,6 @@
       if (y == 66) --x;
 
-      if ((err = mp_read_radix(&order, ecc_sets[x].order, 16)) != MP_OKAY) {
+      if ((err = mp_read_radix(&order, ecc_sets[x].order,
+                                                MP_RADIX_HEX)) != MP_OKAY) {
          goto done;
       }
@@ -6678,5 +8135,5 @@
    mp_clear(&tka);
    while ((unsigned)x < y) {
-      z = kb[0][x]; kb[0][x] = kb[0][y]; kb[0][y] = z;
+      z = kb[0][x]; kb[0][x] = kb[0][y]; kb[0][y] = (byte)z;
       ++x; --y;
    }
@@ -6699,5 +8156,5 @@
 
       while ((unsigned)x < y) {
-         z = kb[1][x]; kb[1][x] = kb[1][y]; kb[1][y] = z;
+         z = kb[1][x]; kb[1][x] = kb[1][y]; kb[1][y] = (byte)z;
          ++x; --y;
       }
@@ -6919,4 +8376,5 @@
     return err;
 }
+#endif
 #endif /* ECC_SHAMIR */
 
@@ -6934,8 +8392,13 @@
     mp_int* modulus, int map, void* heap)
 {
+#ifndef WOLFSSL_SP_MATH
    int   idx, err = MP_OKAY;
    mp_digit mp;
    mp_int   mu;
    int      mpSetup = 0;
+
+   if (k == NULL || G == NULL || R == NULL || a == NULL || modulus == NULL) {
+       return ECC_BAD_ARG_E;
+   }
 
    if (mp_init(&mu) != MP_OKAY)
@@ -7006,6 +8469,14 @@
 
     return err;
-}
-
+#else
+    if (k == NULL || G == NULL || R == NULL || a == NULL || modulus == NULL) {
+        return ECC_BAD_ARG_E;
+    }
+
+    return sp_ecc_mulmod_256(k, G, R, map, heap);
+#endif
+}
+
+#ifndef WOLFSSL_SP_MATH
 /* helper function for freeing the cache ...
    must be called with the cache mutex locked */
@@ -7027,8 +8498,10 @@
    }
 }
+#endif
 
 /** Free the Fixed Point cache */
 void wc_ecc_fp_free(void)
 {
+#ifndef WOLFSSL_SP_MATH
 #ifndef HAVE_THREAD_LS
    if (initMutex == 0) {
@@ -7048,4 +8521,5 @@
    }
 #endif /* HAVE_THREAD_LS */
+#endif
 }
 
@@ -7407,12 +8881,19 @@
                {
                    Aes aes;
+                   ret = wc_AesInit(&aes, NULL, INVALID_DEVID);
+                   if (ret == 0) {
                    ret = wc_AesSetKey(&aes, encKey, KEY_SIZE_128, encIv,
                                                                 AES_ENCRYPTION);
-                   if (ret != 0)
-                       break;
+                       if (ret == 0) {
                    ret = wc_AesCbcEncrypt(&aes, out, msg, msgSz);
                 #if defined(WOLFSSL_ASYNC_CRYPT)
-                   ret = wc_AsyncWait(ret, &aes.asyncDev, WC_ASYNC_FLAG_NONE);
+                           ret = wc_AsyncWait(ret, &aes.asyncDev,
+                                              WC_ASYNC_FLAG_NONE);
                 #endif
+               }
+                       wc_AesFree(&aes);
+                   }
+                   if (ret != 0)
+                      break;
                }
                break;
@@ -7637,4 +9118,5 @@
 #ifndef WOLFSSL_ATECC508A
 
+#ifndef WOLFSSL_SP_MATH
 int do_mp_jacobi(mp_int* a, mp_int* n, int* c);
 
@@ -7760,4 +9242,21 @@
 int mp_sqrtmod_prime(mp_int* n, mp_int* prime, mp_int* ret)
 {
+#ifdef SQRTMOD_USE_MOD_EXP
+  int res;
+
+  mp_int e;
+
+  res = mp_init(&e);
+  if (res == MP_OKAY)
+      res = mp_add_d(prime, 1, &e);
+  if (res == MP_OKAY)
+      res = mp_div_2d(&e, 2, &e, NULL);
+  if (res == MP_OKAY)
+      res = mp_exptmod(n, &e, prime, ret);
+
+  mp_clear(&e);
+
+  return res;
+#else
   int res, legendre, done = 0;
   mp_int t1, C, Q, S, Z, M, T, R, two;
@@ -7938,5 +9437,7 @@
 
   return res;
-}
+#endif
+}
+#endif
 #endif /* !WOLFSSL_ATECC508A */
 
@@ -7961,12 +9462,6 @@
    }
 
-#ifdef WOLFSSL_ATECC508A
-   /* TODO: Implement equiv call to ATECC508A */
-   ret = BAD_COND_E;
-
-#else
-
    /* store first byte */
-   out[0] = mp_isodd(key->pubkey.y) == MP_YES ? 0x03 : 0x02;
+   out[0] = mp_isodd(key->pubkey.y) == MP_YES ? ECC_POINT_COMP_ODD : ECC_POINT_COMP_EVEN;
 
    /* pad and store x */
@@ -7975,6 +9470,4 @@
                        out+1 + (numlen - mp_unsigned_bin_size(key->pubkey.x)));
    *outLen = 1 + numlen;
-
-#endif /* WOLFSSL_ATECC508A */
 
    return ret;
@@ -8045,5 +9538,5 @@
 #ifdef HAVE_X963_KDF
 
-static INLINE void IncrementX963KdfCounter(byte* inOutCtr)
+static WC_INLINE void IncrementX963KdfCounter(byte* inOutCtr)
 {
     int i;
@@ -8110,16 +9603,10 @@
         ret = wc_HashUpdate(hash, type, secret, secretSz);
         if (ret != 0) {
-#ifdef WOLFSSL_SMALL_STACK
-            XFREE(hash, NULL, DYNAMIC_TYPE_HASHES);
-#endif
-            return ret;
+            break;
         }
 
         ret = wc_HashUpdate(hash, type, counter, sizeof(counter));
         if (ret != 0) {
-#ifdef WOLFSSL_SMALL_STACK
-            XFREE(hash, NULL, DYNAMIC_TYPE_HASHES);
-#endif
-            return ret;
+            break;
         }
 
@@ -8127,8 +9614,5 @@
             ret = wc_HashUpdate(hash, type, sinfo, sinfoSz);
             if (ret != 0) {
-#ifdef WOLFSSL_SMALL_STACK
-                XFREE(hash, NULL, DYNAMIC_TYPE_HASHES);
-#endif
-                return ret;
+                break;
             }
         }
@@ -8136,8 +9620,5 @@
         ret = wc_HashFinal(hash, type, tmp);
         if (ret != 0) {
-#ifdef WOLFSSL_SMALL_STACK
-            XFREE(hash, NULL, DYNAMIC_TYPE_HASHES);
-#endif
-            return ret;
+            break;
         }
 
@@ -8149,9 +9630,11 @@
     }
 
+    wc_HashFree(hash, type);
+
 #ifdef WOLFSSL_SMALL_STACK
      XFREE(hash, NULL, DYNAMIC_TYPE_HASHES);
 #endif
 
-    return 0;
+    return ret;
 }
 #endif /* HAVE_X963_KDF */
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/error.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/error.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/error.c	(revision 372)
@@ -34,13 +34,7 @@
 #endif
 
+#ifndef NO_ERROR_STRINGS
 const char* wc_GetErrorString(int error)
 {
-#ifdef NO_ERROR_STRINGS
-
-    (void)error;
-    return "no support for error strings built in";
-
-#else
-
     switch (error) {
 
@@ -207,4 +201,7 @@
         return "X.509 Critical extension ignored or invalid";
 
+    case ASN_ALT_NAME_E:
+        return "ASN alternate name error";
+
     case ECC_BAD_ARG_E :
         return "ECC input argument wrong type, invalid input";
@@ -267,4 +264,7 @@
         return "ASN OCSP sig error, confirm failure";
 
+    case ASN_NO_PEM_HEADER:
+        return "ASN no PEM Header Error";
+
     case BAD_STATE_E:
         return "Bad state operation";
@@ -282,4 +282,7 @@
         return "PKCS#7 error: no matching recipient found";
 
+    case WC_PKCS7_WANT_READ_E:
+        return "PKCS#7 operations wants more input, call again";
+
     case FIPS_NOT_ALLOWED_E:
         return "FIPS mode not allowed error";
@@ -435,11 +438,74 @@
         return "Invalid use of private only ECC key";
 
+    case WC_HW_E:
+        return "Error with hardware crypto use";
+
+    case WC_HW_WAIT_E:
+        return "Hardware waiting on resource";
+
+    case PSS_SALTLEN_E:
+        return "PSS - Length of salt is too big for hash algorithm";
+
+    case PRIME_GEN_E:
+        return "Unable to find a prime for RSA key";
+
+    case BER_INDEF_E:
+        return "Unable to decode an indefinite length encoded message";
+
+    case RSA_OUT_OF_RANGE_E:
+        return "Ciphertext to decrypt is out of range";
+
+    case RSAPSS_PAT_FIPS_E:
+        return "wolfcrypt FIPS RSA-PSS Pairwise Agreement Test Failure";
+
+    case ECDSA_PAT_FIPS_E:
+        return "wolfcrypt FIPS ECDSA Pairwise Agreement Test Failure";
+
+    case DH_KAT_FIPS_E:
+        return "wolfcrypt FIPS DH Known Answer Test Failure";
+
+    case AESCCM_KAT_FIPS_E:
+        return "AESCCM Known Answer Test check FIPS error";
+
+    case SHA3_KAT_FIPS_E:
+        return "SHA-3 Known Answer Test check FIPS error";
+
+    case ECDHE_KAT_FIPS_E:
+        return "wolfcrypt FIPS ECDHE Known Answer Test Failure";
+
+    case AES_GCM_OVERFLOW_E:
+        return "AES-GCM invocation counter overflow";
+
+    case AES_CCM_OVERFLOW_E:
+        return "AES-CCM invocation counter overflow";
+
+    case RSA_KEY_PAIR_E:
+        return "RSA Key Pair-Wise Consistency check fail";
+
+    case DH_CHECK_PRIV_E:
+        return "DH Check Private Key failure";
+
+    case WC_AFALG_SOCK_E:
+        return "AF_ALG socket error";
+
+    case WC_DEVCRYPTO_E:
+        return "Error with /dev/crypto";
+
+    case ZLIB_INIT_ERROR:
+        return "zlib init error";
+
+    case ZLIB_COMPRESS_ERROR:
+        return "zlib compress error";
+
+    case ZLIB_DECOMPRESS_ERROR:
+        return "zlib decompress error";
+
+    case PKCS7_NO_SIGNER_E:
+        return "No signer in PKCS#7 signed data";
+
     default:
         return "unknown error number";
 
     }
-
-#endif /* NO_ERROR_STRINGS */
-
 }
 
@@ -448,2 +514,4 @@
     XSTRNCPY(buffer, wc_GetErrorString(error), WOLFSSL_MAX_ERROR_SZ);
 }
+#endif /* !NO_ERROR_STRINGS */
+
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/hash.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/hash.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/hash.c	(revision 372)
@@ -47,5 +47,73 @@
     SHA512h = 416
 };
-#endif
+#endif /* !NO_ASN */
+
+#ifdef HAVE_SELFTEST
+enum {
+    /* CAVP selftest includes these in hmac.h instead of sha3.h,
+       copied here for that build */
+    WC_SHA3_224_BLOCK_SIZE = 144,
+    WC_SHA3_256_BLOCK_SIZE = 136,
+    WC_SHA3_384_BLOCK_SIZE = 104,
+    WC_SHA3_512_BLOCK_SIZE = 72,
+};
+#endif
+
+
+/* function converts int hash type to enum */
+enum wc_HashType wc_HashTypeConvert(int hashType)
+{
+    /* Default to hash type none as error */
+    enum wc_HashType eHashType = WC_HASH_TYPE_NONE;
+#if defined(HAVE_FIPS) || defined(HAVE_SELFTEST)
+    /* original FIPSv1  and CAVP selftest require a mapping for unique hash
+       type to wc_HashType */
+    switch (hashType) {
+    #ifndef NO_MD5
+        case WC_MD5:
+            eHashType = WC_HASH_TYPE_MD5;
+            break;
+    #endif /* !NO_MD5 */
+    #ifndef NO_SHA
+        case WC_SHA:
+            eHashType = WC_HASH_TYPE_SHA;
+            break;
+    #endif /* !NO_SHA */
+
+    #ifdef WOLFSSL_SHA224
+        case WC_SHA224:
+            eHashType = WC_HASH_TYPE_SHA224;
+            break;
+    #endif /* WOLFSSL_SHA224 */
+
+    #ifndef NO_SHA256
+        case WC_SHA256:
+            eHashType = WC_HASH_TYPE_SHA256;
+            break;
+    #endif /* !NO_SHA256 */
+
+    #ifdef WOLFSSL_SHA384
+        case WC_SHA384:
+            eHashType = WC_HASH_TYPE_SHA384;
+            break;
+    #endif /* WOLFSSL_SHA384 */
+    #ifdef WOLFSSL_SHA512
+        case WC_SHA512:
+            eHashType = WC_HASH_TYPE_SHA512;
+            break;
+    #endif /* WOLFSSL_SHA512 */
+        default:
+            eHashType = WC_HASH_TYPE_NONE;
+            break;
+    }
+#else
+    /* current master uses same unique types as wc_HashType */
+    if (hashType > 0 && hashType <= WC_HASH_TYPE_MAX) {
+        eHashType = (enum wc_HashType)hashType;
+    }
+#endif
+    return eHashType;
+}
+
 
 int wc_HashGetOID(enum wc_HashType hash_type)
@@ -71,5 +139,5 @@
             break;
         case WC_HASH_TYPE_SHA224:
-        #if defined(WOLFSSL_SHA224)
+        #ifdef WOLFSSL_SHA224
             oid = SHA224h;
         #endif
@@ -81,5 +149,5 @@
             break;
         case WC_HASH_TYPE_SHA384:
-        #if defined(WOLFSSL_SHA512) && defined(WOLFSSL_SHA384)
+        #ifdef WOLFSSL_SHA384
             oid = SHA384h;
         #endif
@@ -93,4 +161,9 @@
         /* Not Supported */
         case WC_HASH_TYPE_MD4:
+        case WC_HASH_TYPE_SHA3_224:
+        case WC_HASH_TYPE_SHA3_256:
+        case WC_HASH_TYPE_SHA3_384:
+        case WC_HASH_TYPE_SHA3_512:
+        case WC_HASH_TYPE_BLAKE2B:
         case WC_HASH_TYPE_NONE:
         default:
@@ -100,5 +173,53 @@
     return oid;
 }
-#endif
+
+enum wc_HashType wc_OidGetHash(int oid)
+{
+    enum wc_HashType hash_type = WC_HASH_TYPE_NONE;
+    switch (oid)
+    {
+    #ifdef WOLFSSL_MD2
+        case MD2h:
+            hash_type = WC_HASH_TYPE_MD2;
+            break;
+    #endif
+        case MD5h:
+        #ifndef NO_MD5
+            hash_type = WC_HASH_TYPE_MD5;
+#endif
+            break;
+        case SHAh:
+        #ifndef NO_SHA
+            hash_type = WC_HASH_TYPE_SHA;
+        #endif
+            break;
+        case SHA224h:
+        #ifdef WOLFSSL_SHA224
+            hash_type = WC_HASH_TYPE_SHA224;
+        #endif
+            break;
+        case SHA256h:
+        #ifndef NO_SHA256
+            hash_type = WC_HASH_TYPE_SHA256;
+        #endif
+            break;
+        case SHA384h:
+        #ifdef WOLFSSL_SHA384
+            hash_type = WC_HASH_TYPE_SHA384;
+        #endif
+            break;
+        case SHA512h:
+        #ifdef WOLFSSL_SHA512
+            hash_type = WC_HASH_TYPE_SHA512;
+        #endif
+            break;
+        default:
+            break;
+    }
+    return hash_type;
+}
+#endif /* !NO_ASN || !NO_DH || HAVE_ECC */
+
+
 
 /* Get Hash digest size */
@@ -108,4 +229,14 @@
     switch(hash_type)
     {
+        case WC_HASH_TYPE_MD2:
+        #ifdef WOLFSSL_MD2
+            dig_size = MD2_DIGEST_SIZE;
+        #endif
+            break;
+        case WC_HASH_TYPE_MD4:
+        #ifndef NO_MD4
+            dig_size = MD4_DIGEST_SIZE;
+        #endif
+            break;
         case WC_HASH_TYPE_MD5:
 #ifndef NO_MD5
@@ -129,5 +260,5 @@
             break;
         case WC_HASH_TYPE_SHA384:
-#if defined(WOLFSSL_SHA512) && defined(WOLFSSL_SHA384)
+        #ifdef WOLFSSL_SHA384
             dig_size = WC_SHA384_DIGEST_SIZE;
 #endif
@@ -138,13 +269,33 @@
 #endif
             break;
-        case WC_HASH_TYPE_MD5_SHA:
+        case WC_HASH_TYPE_MD5_SHA: /* Old TLS Specific */
 #if !defined(NO_MD5) && !defined(NO_SHA)
-            dig_size = WC_MD5_DIGEST_SIZE + WC_SHA_DIGEST_SIZE;
+            dig_size = (int)WC_MD5_DIGEST_SIZE + (int)WC_SHA_DIGEST_SIZE;
+        #endif
+            break;
+
+        case WC_HASH_TYPE_SHA3_224:
+        #ifdef WOLFSSL_SHA3
+            dig_size = WC_SHA3_224_DIGEST_SIZE;
+        #endif
+            break;
+        case WC_HASH_TYPE_SHA3_256:
+        #ifdef WOLFSSL_SHA3
+            dig_size = WC_SHA3_256_DIGEST_SIZE;
+        #endif
+            break;
+        case WC_HASH_TYPE_SHA3_384:
+        #ifdef WOLFSSL_SHA3
+            dig_size = WC_SHA3_384_DIGEST_SIZE;
+        #endif
+            break;
+        case WC_HASH_TYPE_SHA3_512:
+        #ifdef WOLFSSL_SHA3
+            dig_size = WC_SHA3_512_DIGEST_SIZE;
 #endif
             break;
 
         /* Not Supported */
-        case WC_HASH_TYPE_MD2:
-        case WC_HASH_TYPE_MD4:
+        case WC_HASH_TYPE_BLAKE2B:
         case WC_HASH_TYPE_NONE:
         default:
@@ -153,4 +304,88 @@
     }
     return dig_size;
+}
+
+
+/* Get Hash block size */
+int wc_HashGetBlockSize(enum wc_HashType hash_type)
+{
+    int block_size = HASH_TYPE_E; /* Default to hash type error */
+    switch (hash_type)
+    {
+        case WC_HASH_TYPE_MD2:
+        #ifdef WOLFSSL_MD2
+            block_size = MD2_BLOCK_SIZE;
+        #endif
+            break;
+        case WC_HASH_TYPE_MD4:
+        #ifndef NO_MD4
+            block_size = MD4_BLOCK_SIZE;
+        #endif
+            break;
+        case WC_HASH_TYPE_MD5:
+        #ifndef NO_MD5
+            block_size = WC_MD5_BLOCK_SIZE;
+        #endif
+            break;
+        case WC_HASH_TYPE_SHA:
+        #ifndef NO_SHA
+            block_size = WC_SHA_BLOCK_SIZE;
+        #endif
+            break;
+        case WC_HASH_TYPE_SHA224:
+        #ifdef WOLFSSL_SHA224
+            block_size = WC_SHA224_BLOCK_SIZE;
+        #endif
+            break;
+        case WC_HASH_TYPE_SHA256:
+        #ifndef NO_SHA256
+            block_size = WC_SHA256_BLOCK_SIZE;
+        #endif
+            break;
+        case WC_HASH_TYPE_SHA384:
+        #ifdef WOLFSSL_SHA384
+            block_size = WC_SHA384_BLOCK_SIZE;
+        #endif
+            break;
+        case WC_HASH_TYPE_SHA512:
+        #ifdef WOLFSSL_SHA512
+            block_size = WC_SHA512_BLOCK_SIZE;
+        #endif
+            break;
+        case WC_HASH_TYPE_MD5_SHA: /* Old TLS Specific */
+        #if !defined(NO_MD5) && !defined(NO_SHA)
+            block_size = (int)WC_MD5_BLOCK_SIZE + (int)WC_SHA_BLOCK_SIZE;
+        #endif
+            break;
+
+        case WC_HASH_TYPE_SHA3_224:
+        #ifdef WOLFSSL_SHA3
+            block_size = WC_SHA3_224_BLOCK_SIZE;
+        #endif
+            break;
+        case WC_HASH_TYPE_SHA3_256:
+        #ifdef WOLFSSL_SHA3
+            block_size = WC_SHA3_256_BLOCK_SIZE;
+        #endif
+            break;
+        case WC_HASH_TYPE_SHA3_384:
+        #ifdef WOLFSSL_SHA3
+            block_size = WC_SHA3_384_BLOCK_SIZE;
+        #endif
+            break;
+        case WC_HASH_TYPE_SHA3_512:
+        #ifdef WOLFSSL_SHA3
+            block_size = WC_SHA3_512_BLOCK_SIZE;
+        #endif
+            break;
+
+        /* Not Supported */
+        case WC_HASH_TYPE_BLAKE2B:
+        case WC_HASH_TYPE_NONE:
+        default:
+            block_size = BAD_FUNC_ARG;
+            break;
+    }
+    return block_size;
 }
 
@@ -197,5 +432,5 @@
             break;
         case WC_HASH_TYPE_SHA384:
-#if defined(WOLFSSL_SHA512) && defined(WOLFSSL_SHA384)
+#ifdef WOLFSSL_SHA384
             ret = wc_Sha384Hash(data, data_len, hash);
 #endif
@@ -218,4 +453,9 @@
         case WC_HASH_TYPE_MD2:
         case WC_HASH_TYPE_MD4:
+        case WC_HASH_TYPE_SHA3_224:
+        case WC_HASH_TYPE_SHA3_256:
+        case WC_HASH_TYPE_SHA3_384:
+        case WC_HASH_TYPE_SHA3_512:
+        case WC_HASH_TYPE_BLAKE2B:
         case WC_HASH_TYPE_NONE:
         default:
@@ -236,6 +476,5 @@
         case WC_HASH_TYPE_MD5:
 #ifndef NO_MD5
-            wc_InitMd5(&hash->md5);
-            ret = 0;
+            ret = wc_InitMd5(&hash->md5);
 #endif
             break;
@@ -270,4 +509,9 @@
         case WC_HASH_TYPE_MD2:
         case WC_HASH_TYPE_MD4:
+        case WC_HASH_TYPE_SHA3_224:
+        case WC_HASH_TYPE_SHA3_256:
+        case WC_HASH_TYPE_SHA3_384:
+        case WC_HASH_TYPE_SHA3_512:
+        case WC_HASH_TYPE_BLAKE2B:
         case WC_HASH_TYPE_NONE:
         default:
@@ -289,6 +533,5 @@
         case WC_HASH_TYPE_MD5:
 #ifndef NO_MD5
-            wc_Md5Update(&hash->md5, data, dataSz);
-            ret = 0;
+            ret = wc_Md5Update(&hash->md5, data, dataSz);
 #endif
             break;
@@ -296,6 +539,4 @@
 #ifndef NO_SHA
             ret = wc_ShaUpdate(&hash->sha, data, dataSz);
-            if (ret != 0)
-                return ret;
 #endif
             break;
@@ -325,4 +566,9 @@
         case WC_HASH_TYPE_MD2:
         case WC_HASH_TYPE_MD4:
+        case WC_HASH_TYPE_SHA3_224:
+        case WC_HASH_TYPE_SHA3_256:
+        case WC_HASH_TYPE_SHA3_384:
+        case WC_HASH_TYPE_SHA3_512:
+        case WC_HASH_TYPE_BLAKE2B:
         case WC_HASH_TYPE_NONE:
         default:
@@ -343,6 +589,5 @@
         case WC_HASH_TYPE_MD5:
 #ifndef NO_MD5
-            wc_Md5Final(&hash->md5, out);
-            ret = 0;
+            ret = wc_Md5Final(&hash->md5, out);
 #endif
             break;
@@ -377,4 +622,9 @@
         case WC_HASH_TYPE_MD2:
         case WC_HASH_TYPE_MD4:
+        case WC_HASH_TYPE_SHA3_224:
+        case WC_HASH_TYPE_SHA3_256:
+        case WC_HASH_TYPE_SHA3_384:
+        case WC_HASH_TYPE_SHA3_512:
+        case WC_HASH_TYPE_BLAKE2B:
         case WC_HASH_TYPE_NONE:
         default:
@@ -385,4 +635,66 @@
 }
 
+int wc_HashFree(wc_HashAlg* hash, enum wc_HashType type)
+{
+    int ret = HASH_TYPE_E; /* Default to hash type error */
+
+    if (hash == NULL)
+        return BAD_FUNC_ARG;
+
+    switch (type) {
+        case WC_HASH_TYPE_MD5:
+#ifndef NO_MD5
+            wc_Md5Free(&hash->md5);
+            ret = 0;
+#endif
+            break;
+        case WC_HASH_TYPE_SHA:
+#ifndef NO_SHA
+            wc_ShaFree(&hash->sha);
+            ret = 0;
+#endif
+            break;
+        case WC_HASH_TYPE_SHA224:
+#ifdef WOLFSSL_SHA224
+            wc_Sha224Free(&hash->sha224);
+            ret = 0;
+#endif
+            break;
+        case WC_HASH_TYPE_SHA256:
+#ifndef NO_SHA256
+            wc_Sha256Free(&hash->sha256);
+            ret = 0;
+#endif
+            break;
+        case WC_HASH_TYPE_SHA384:
+#ifdef WOLFSSL_SHA384
+            wc_Sha384Free(&hash->sha384);
+            ret = 0;
+#endif
+            break;
+        case WC_HASH_TYPE_SHA512:
+#ifdef WOLFSSL_SHA512
+            wc_Sha512Free(&hash->sha512);
+            ret = 0;
+#endif
+            break;
+
+        /* not supported */
+        case WC_HASH_TYPE_MD5_SHA:
+        case WC_HASH_TYPE_MD2:
+        case WC_HASH_TYPE_MD4:
+        case WC_HASH_TYPE_SHA3_224:
+        case WC_HASH_TYPE_SHA3_256:
+        case WC_HASH_TYPE_SHA3_384:
+        case WC_HASH_TYPE_SHA3_512:
+        case WC_HASH_TYPE_BLAKE2B:
+        case WC_HASH_TYPE_NONE:
+        default:
+            ret = BAD_FUNC_ARG;
+    };
+
+    return ret;
+}
+
 
 #if !defined(WOLFSSL_TI_HASH)
@@ -404,10 +716,15 @@
     #endif
 
-        ret = wc_InitMd5(md5);
-        if (ret == 0) {
-            ret = wc_Md5Update(md5, data, len);
-            if (ret == 0) {
-                ret = wc_Md5Final(md5, hash);
+        if ((ret = wc_InitMd5(md5)) != 0) {
+            WOLFSSL_MSG("InitMd5 failed");
+        }
+        else {
+            if ((ret = wc_Md5Update(md5, data, len)) != 0) {
+                WOLFSSL_MSG("Md5Update failed");
             }
+            else if ((ret = wc_Md5Final(md5, hash)) != 0) {
+                WOLFSSL_MSG("Md5Final failed");
+            }
+            wc_Md5Free(md5);
         }
 
@@ -437,9 +754,14 @@
 
         if ((ret = wc_InitSha(sha)) != 0) {
-            WOLFSSL_MSG("wc_InitSha failed");
+            WOLFSSL_MSG("InitSha failed");
         }
         else {
-            wc_ShaUpdate(sha, data, len);
-            wc_ShaFinal(sha, hash);
+            if ((ret = wc_ShaUpdate(sha, data, len)) != 0) {
+                WOLFSSL_MSG("ShaUpdate failed");
+            }
+            else if ((ret = wc_ShaFinal(sha, hash)) != 0) {
+                WOLFSSL_MSG("ShaFinal failed");
+            }
+            wc_ShaFree(sha);
         }
 
@@ -472,5 +794,6 @@
         WOLFSSL_MSG("InitSha224 failed");
     }
-    else if ((ret = wc_Sha224Update(sha224, data, len)) != 0) {
+        else {
+            if ((ret = wc_Sha224Update(sha224, data, len)) != 0) {
         WOLFSSL_MSG("Sha224Update failed");
     }
@@ -478,4 +801,6 @@
         WOLFSSL_MSG("Sha224Final failed");
     }
+            wc_Sha224Free(sha224);
+        }
 
 #ifdef WOLFSSL_SMALL_STACK
@@ -507,5 +832,6 @@
             WOLFSSL_MSG("InitSha256 failed");
         }
-        else if ((ret = wc_Sha256Update(sha256, data, len)) != 0) {
+        else {
+            if ((ret = wc_Sha256Update(sha256, data, len)) != 0) {
             WOLFSSL_MSG("Sha256Update failed");
         }
@@ -513,4 +839,7 @@
             WOLFSSL_MSG("Sha256Final failed");
         }
+            wc_Sha256Free(sha256);
+        }
+
 
     #ifdef WOLFSSL_SMALL_STACK
@@ -545,5 +874,6 @@
             WOLFSSL_MSG("InitSha512 failed");
         }
-        else if ((ret = wc_Sha512Update(sha512, data, len)) != 0) {
+        else {
+            if ((ret = wc_Sha512Update(sha512, data, len)) != 0) {
             WOLFSSL_MSG("Sha512Update failed");
         }
@@ -551,4 +881,6 @@
             WOLFSSL_MSG("Sha512Final failed");
         }
+            wc_Sha512Free(sha512);
+        }
 
     #ifdef WOLFSSL_SMALL_STACK
@@ -558,4 +890,5 @@
         return ret;
     }
+#endif /* WOLFSSL_SHA512 */
 
     #if defined(WOLFSSL_SHA384)
@@ -579,5 +912,6 @@
                 WOLFSSL_MSG("InitSha384 failed");
             }
-            else if ((ret = wc_Sha384Update(sha384, data, len)) != 0) {
+        else {
+            if ((ret = wc_Sha384Update(sha384, data, len)) != 0) {
                 WOLFSSL_MSG("Sha384Update failed");
             }
@@ -585,4 +919,6 @@
                 WOLFSSL_MSG("Sha384Final failed");
             }
+            wc_Sha384Free(sha384);
+        }
 
         #ifdef WOLFSSL_SMALL_STACK
@@ -593,3 +929,2 @@
         }
     #endif /* WOLFSSL_SHA384 */
-#endif /* WOLFSSL_SHA512 */
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/hc128.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/hc128.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/hc128.c	(revision 372)
@@ -273,5 +273,5 @@
 
 
-static INLINE int DoKey(HC128* ctx, const byte* key, const byte* iv)
+static WC_INLINE int DoKey(HC128* ctx, const byte* key, const byte* iv)
 {
   word32 i;
@@ -336,5 +336,5 @@
 
 /* The following defines the encryption of data stream */
-static INLINE int DoProcess(HC128* ctx, byte* output, const byte* input,
+static WC_INLINE int DoProcess(HC128* ctx, byte* output, const byte* input,
                             word32 msglen)
 {
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/hmac.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/hmac.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/hmac.c	(revision 372)
@@ -1,3 +1,3 @@
-/* hmac.h
+/* hmac.c
  *
  * Copyright (C) 2006-2017 wolfSSL Inc.
@@ -30,4 +30,16 @@
 #ifndef NO_HMAC
 
+#if defined(HAVE_FIPS) && \
+    defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+
+    /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+    #define FIPS_NO_WRAPPERS
+
+    #ifdef USE_WINDOWS_API
+        #pragma code_seg(".fipsA$b")
+        #pragma const_seg(".fipsB$b")
+    #endif
+#endif
+
 #include <wolfssl/wolfcrypt/hmac.h>
 
@@ -41,5 +53,8 @@
 
 /* fips wrapper calls, user can call direct */
-#ifdef HAVE_FIPS
+/* If building for old FIPS. */
+#if defined(HAVE_FIPS) && \
+    (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))
+
     /* does init */
     int wc_HmacSetKey(Hmac* hmac, int type, const byte* key, word32 keySz)
@@ -47,5 +62,6 @@
         if (hmac == NULL || (key == NULL && keySz != 0) ||
            !(type == WC_MD5 || type == WC_SHA || type == WC_SHA256 ||
-                type == WC_SHA384 || type == WC_SHA512 || type == BLAKE2B_ID)) {
+                type == WC_SHA384 || type == WC_SHA512 ||
+                type == BLAKE2B_ID)) {
             return BAD_FUNC_ARG;
         }
@@ -101,8 +117,5 @@
     #endif /* HAVE_HKDF */
 
-#else /* else build without fips */
-
-
-#include <wolfssl/wolfcrypt/error-crypt.h>
+#else /* else build without fips, or for new fips */
 
 
@@ -111,6 +124,9 @@
     int ret;
 
-    if (!(type == WC_MD5 || type == WC_SHA || type == WC_SHA224 ||
-            type == WC_SHA256 || type == WC_SHA384 || type == WC_SHA512 ||
+    if (!(type == WC_MD5 || type == WC_SHA ||
+            type == WC_SHA224 || type == WC_SHA256 ||
+            type == WC_SHA384 || type == WC_SHA512 ||
+            type == WC_SHA3_224 || type == WC_SHA3_256 ||
+            type == WC_SHA3_384 || type == WC_SHA3_512 ||
             type == BLAKE2B_ID)) {
         return BAD_FUNC_ARG;
@@ -142,5 +158,4 @@
     #endif /* !NO_SHA256 */
 
-    #ifdef WOLFSSL_SHA512
     #ifdef WOLFSSL_SHA384
         case WC_SHA384:
@@ -148,4 +163,5 @@
             break;
     #endif /* WOLFSSL_SHA384 */
+    #ifdef WOLFSSL_SHA512
         case WC_SHA512:
             ret = WC_SHA512_DIGEST_SIZE;
@@ -159,4 +175,23 @@
     #endif /* HAVE_BLAKE2 */
 
+    #ifdef WOLFSSL_SHA3
+        case WC_SHA3_224:
+            ret = WC_SHA3_224_DIGEST_SIZE;
+            break;
+
+        case WC_SHA3_256:
+            ret = WC_SHA3_256_DIGEST_SIZE;
+            break;
+
+        case WC_SHA3_384:
+            ret = WC_SHA3_384_DIGEST_SIZE;
+            break;
+
+        case WC_SHA3_512:
+            ret = WC_SHA3_512_DIGEST_SIZE;
+            break;
+
+    #endif
+
         default:
             ret = BAD_FUNC_ARG;
@@ -167,5 +202,5 @@
 }
 
-static int _InitHmac(Hmac* hmac, int type, void* heap)
+int _InitHmac(Hmac* hmac, int type, void* heap)
 {
     int ret = 0;
@@ -196,5 +231,4 @@
     #endif /* !NO_SHA256 */
 
-    #ifdef WOLFSSL_SHA512
     #ifdef WOLFSSL_SHA384
         case WC_SHA384:
@@ -202,4 +236,5 @@
             break;
     #endif /* WOLFSSL_SHA384 */
+    #ifdef WOLFSSL_SHA512
         case WC_SHA512:
             ret = wc_InitSha512(&hmac->hash.sha512);
@@ -212,4 +247,19 @@
             break;
     #endif /* HAVE_BLAKE2 */
+
+    #ifdef WOLFSSL_SHA3
+        case WC_SHA3_224:
+            ret = wc_InitSha3_224(&hmac->hash.sha3, heap, INVALID_DEVID);
+            break;
+        case WC_SHA3_256:
+            ret = wc_InitSha3_256(&hmac->hash.sha3, heap, INVALID_DEVID);
+            break;
+        case WC_SHA3_384:
+            ret = wc_InitSha3_384(&hmac->hash.sha3, heap, INVALID_DEVID);
+            break;
+        case WC_SHA3_512:
+            ret = wc_InitSha3_512(&hmac->hash.sha3, heap, INVALID_DEVID);
+            break;
+    #endif
 
         default:
@@ -238,29 +288,20 @@
 
     if (hmac == NULL || (key == NULL && length != 0) ||
-        !(type == WC_MD5 || type == WC_SHA || type == WC_SHA224 ||
-            type == WC_SHA256 || type == WC_SHA384 || type == WC_SHA512 ||
+       !(type == WC_MD5 || type == WC_SHA ||
+            type == WC_SHA224 || type == WC_SHA256 ||
+            type == WC_SHA384 || type == WC_SHA512 ||
+            type == WC_SHA3_224 || type == WC_SHA3_256 ||
+            type == WC_SHA3_384 || type == WC_SHA3_512 ||
             type == BLAKE2B_ID)) {
         return BAD_FUNC_ARG;
     }
 
+    /* if set key has already been run then make sure and free existing */
+    if (hmac->macType != 0) {
+        wc_HmacFree(hmac);
+        }
+
     hmac->innerHashKeyed = 0;
     hmac->macType = (byte)type;
-
-#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_HMAC)
-    if (hmac->asyncDev.marker == WOLFSSL_ASYNC_MARKER_HMAC) {
-    #if defined(HAVE_CAVIUM)
-        if (length > HMAC_BLOCK_SIZE) {
-            return WC_KEY_SIZE_E;
-        }
-
-        if (key != NULL) {
-            XMEMCPY(hmac->ipad, key, length);
-        }
-        hmac->keyLen = (word16)length;
-
-        return 0; /* nothing to do here */
-    #endif /* HAVE_CAVIUM */
-    }
-#endif /* WOLFSSL_ASYNC_CRYPT */
 
     ret = _InitHmac(hmac, type, heap);
@@ -362,5 +403,4 @@
     #endif /* !NO_SHA256 */
 
-    #ifdef WOLFSSL_SHA512
     #ifdef WOLFSSL_SHA384
         case WC_SHA384:
@@ -383,4 +423,5 @@
             break;
     #endif /* WOLFSSL_SHA384 */
+    #ifdef WOLFSSL_SHA512
         case WC_SHA512:
             hmac_block_size = WC_SHA512_BLOCK_SIZE;
@@ -424,4 +465,79 @@
     #endif /* HAVE_BLAKE2 */
 
+    #ifdef WOLFSSL_SHA3
+        case WC_SHA3_224:
+            hmac_block_size = WC_SHA3_224_BLOCK_SIZE;
+            if (length <= WC_SHA3_224_BLOCK_SIZE) {
+                if (key != NULL) {
+                    XMEMCPY(ip, key, length);
+                }
+            }
+            else {
+                ret = wc_Sha3_224_Update(&hmac->hash.sha3, key, length);
+                if (ret != 0)
+                    break;
+                ret = wc_Sha3_224_Final(&hmac->hash.sha3, ip);
+                if (ret != 0)
+                    break;
+
+                length = WC_SHA3_224_DIGEST_SIZE;
+            }
+            break;
+        case WC_SHA3_256:
+            hmac_block_size = WC_SHA3_256_BLOCK_SIZE;
+            if (length <= WC_SHA3_256_BLOCK_SIZE) {
+                if (key != NULL) {
+                    XMEMCPY(ip, key, length);
+                }
+            }
+            else {
+                ret = wc_Sha3_256_Update(&hmac->hash.sha3, key, length);
+                if (ret != 0)
+                    break;
+                ret = wc_Sha3_256_Final(&hmac->hash.sha3, ip);
+                if (ret != 0)
+                    break;
+
+                length = WC_SHA3_256_DIGEST_SIZE;
+            }
+            break;
+        case WC_SHA3_384:
+            hmac_block_size = WC_SHA3_384_BLOCK_SIZE;
+            if (length <= WC_SHA3_384_BLOCK_SIZE) {
+                if (key != NULL) {
+                    XMEMCPY(ip, key, length);
+                }
+            }
+            else {
+                ret = wc_Sha3_384_Update(&hmac->hash.sha3, key, length);
+                if (ret != 0)
+                    break;
+                ret = wc_Sha3_384_Final(&hmac->hash.sha3, ip);
+                if (ret != 0)
+                    break;
+
+                length = WC_SHA3_384_DIGEST_SIZE;
+            }
+            break;
+        case WC_SHA3_512:
+            hmac_block_size = WC_SHA3_512_BLOCK_SIZE;
+            if (length <= WC_SHA3_512_BLOCK_SIZE) {
+                if (key != NULL) {
+                    XMEMCPY(ip, key, length);
+                }
+            }
+            else {
+                ret = wc_Sha3_512_Update(&hmac->hash.sha3, key, length);
+                if (ret != 0)
+                    break;
+                ret = wc_Sha3_512_Final(&hmac->hash.sha3, ip);
+                if (ret != 0)
+                    break;
+
+                length = WC_SHA3_512_DIGEST_SIZE;
+            }
+            break;
+    #endif /* WOLFSSL_SHA3 */
+
         default:
             return BAD_FUNC_ARG;
@@ -430,5 +546,9 @@
 #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_HMAC)
     if (hmac->asyncDev.marker == WOLFSSL_ASYNC_MARKER_HMAC) {
-    #if defined(HAVE_INTEL_QA)
+    #if defined(HAVE_INTEL_QA) || defined(HAVE_CAVIUM)
+        #ifdef HAVE_INTEL_QA
+        if (IntelQaHmacGetType(hmac->macType, NULL) == 0)
+        #endif
+        {
         if (length > hmac_block_size)
             length = hmac_block_size;
@@ -437,4 +557,5 @@
 
         return ret;
+        }
         /* no need to pad below */
     #endif
@@ -489,5 +610,4 @@
     #endif /* !NO_SHA256 */
 
-    #ifdef WOLFSSL_SHA512
     #ifdef WOLFSSL_SHA384
         case WC_SHA384:
@@ -496,4 +616,5 @@
             break;
     #endif /* WOLFSSL_SHA384 */
+    #ifdef WOLFSSL_SHA512
         case WC_SHA512:
             ret = wc_Sha512Update(&hmac->hash.sha512, (byte*)hmac->ipad,
@@ -508,4 +629,23 @@
             break;
     #endif /* HAVE_BLAKE2 */
+
+    #ifdef WOLFSSL_SHA3
+        case WC_SHA3_224:
+            ret = wc_Sha3_224_Update(&hmac->hash.sha3, (byte*)hmac->ipad,
+                                                       WC_SHA3_224_BLOCK_SIZE);
+            break;
+        case WC_SHA3_256:
+            ret = wc_Sha3_256_Update(&hmac->hash.sha3, (byte*)hmac->ipad,
+                                                       WC_SHA3_256_BLOCK_SIZE);
+            break;
+        case WC_SHA3_384:
+            ret = wc_Sha3_384_Update(&hmac->hash.sha3, (byte*)hmac->ipad,
+                                                       WC_SHA3_384_BLOCK_SIZE);
+            break;
+        case WC_SHA3_512:
+            ret = wc_Sha3_512_Update(&hmac->hash.sha3, (byte*)hmac->ipad,
+                                                       WC_SHA3_512_BLOCK_SIZE);
+            break;
+    #endif /* WOLFSSL_SHA3 */
 
         default:
@@ -533,6 +673,8 @@
         return NitroxHmacUpdate(hmac, msg, length);
     #elif defined(HAVE_INTEL_QA)
+        if (IntelQaHmacGetType(hmac->macType, NULL) == 0) {
         return IntelQaHmac(&hmac->asyncDev, hmac->macType,
             (byte*)hmac->ipad, hmac->keyLen, NULL, msg, length);
+        }
     #endif
     }
@@ -570,5 +712,4 @@
     #endif /* !NO_SHA256 */
 
-    #ifdef WOLFSSL_SHA512
     #ifdef WOLFSSL_SHA384
         case WC_SHA384:
@@ -576,4 +717,5 @@
             break;
     #endif /* WOLFSSL_SHA384 */
+    #ifdef WOLFSSL_SHA512
         case WC_SHA512:
             ret = wc_Sha512Update(&hmac->hash.sha512, msg, length);
@@ -586,4 +728,19 @@
             break;
     #endif /* HAVE_BLAKE2 */
+
+    #ifdef WOLFSSL_SHA3
+        case WC_SHA3_224:
+            ret = wc_Sha3_224_Update(&hmac->hash.sha3, msg, length);
+            break;
+        case WC_SHA3_256:
+            ret = wc_Sha3_256_Update(&hmac->hash.sha3, msg, length);
+            break;
+        case WC_SHA3_384:
+            ret = wc_Sha3_384_Update(&hmac->hash.sha3, msg, length);
+            break;
+        case WC_SHA3_512:
+            ret = wc_Sha3_512_Update(&hmac->hash.sha3, msg, length);
+            break;
+    #endif /* WOLFSSL_SHA3 */
 
         default:
@@ -610,8 +767,10 @@
 
     #if defined(HAVE_CAVIUM)
-        return NitroxHmacFinal(hmac, hmac->macType, hash, hashLen);
+        return NitroxHmacFinal(hmac, hash, hashLen);
     #elif defined(HAVE_INTEL_QA)
+        if (IntelQaHmacGetType(hmac->macType, NULL) == 0) {
         return IntelQaHmac(&hmac->asyncDev, hmac->macType,
             (byte*)hmac->ipad, hmac->keyLen, hash, NULL, hashLen);
+        }
     #endif
     }
@@ -697,5 +856,4 @@
     #endif /* !NO_SHA256 */
 
-    #ifdef WOLFSSL_SHA512
     #ifdef WOLFSSL_SHA384
         case WC_SHA384:
@@ -714,4 +872,5 @@
             break;
     #endif /* WOLFSSL_SHA384 */
+    #ifdef WOLFSSL_SHA512
         case WC_SHA512:
             ret = wc_Sha512Final(&hmac->hash.sha512, (byte*)hmac->innerHash);
@@ -748,4 +907,63 @@
     #endif /* HAVE_BLAKE2 */
 
+    #ifdef WOLFSSL_SHA3
+        case WC_SHA3_224:
+            ret = wc_Sha3_224_Final(&hmac->hash.sha3, (byte*)hmac->innerHash);
+            if (ret != 0)
+                break;
+            ret = wc_Sha3_224_Update(&hmac->hash.sha3, (byte*)hmac->opad,
+                                                       WC_SHA3_224_BLOCK_SIZE);
+            if (ret != 0)
+                break;
+            ret = wc_Sha3_224_Update(&hmac->hash.sha3, (byte*)hmac->innerHash,
+                                                          WC_SHA3_224_DIGEST_SIZE);
+            if (ret != 0)
+                break;
+            ret = wc_Sha3_224_Final(&hmac->hash.sha3, hash);
+            break;
+        case WC_SHA3_256:
+            ret = wc_Sha3_256_Final(&hmac->hash.sha3, (byte*)hmac->innerHash);
+            if (ret != 0)
+                break;
+            ret = wc_Sha3_256_Update(&hmac->hash.sha3, (byte*)hmac->opad,
+                                                       WC_SHA3_256_BLOCK_SIZE);
+            if (ret != 0)
+                break;
+            ret = wc_Sha3_256_Update(&hmac->hash.sha3, (byte*)hmac->innerHash,
+                                                          WC_SHA3_256_DIGEST_SIZE);
+            if (ret != 0)
+                break;
+            ret = wc_Sha3_256_Final(&hmac->hash.sha3, hash);
+            break;
+        case WC_SHA3_384:
+            ret = wc_Sha3_384_Final(&hmac->hash.sha3, (byte*)hmac->innerHash);
+            if (ret != 0)
+                break;
+            ret = wc_Sha3_384_Update(&hmac->hash.sha3, (byte*)hmac->opad,
+                                                       WC_SHA3_384_BLOCK_SIZE);
+            if (ret != 0)
+                break;
+            ret = wc_Sha3_384_Update(&hmac->hash.sha3, (byte*)hmac->innerHash,
+                                                          WC_SHA3_384_DIGEST_SIZE);
+            if (ret != 0)
+                break;
+            ret = wc_Sha3_384_Final(&hmac->hash.sha3, hash);
+            break;
+        case WC_SHA3_512:
+            ret = wc_Sha3_512_Final(&hmac->hash.sha3, (byte*)hmac->innerHash);
+            if (ret != 0)
+                break;
+            ret = wc_Sha3_512_Update(&hmac->hash.sha3, (byte*)hmac->opad,
+                                                       WC_SHA3_512_BLOCK_SIZE);
+            if (ret != 0)
+                break;
+            ret = wc_Sha3_512_Update(&hmac->hash.sha3, (byte*)hmac->innerHash,
+                                                          WC_SHA3_512_DIGEST_SIZE);
+            if (ret != 0)
+                break;
+            ret = wc_Sha3_512_Final(&hmac->hash.sha3, hash);
+            break;
+    #endif /* WOLFSSL_SHA3 */
+
         default:
             ret = BAD_FUNC_ARG;
@@ -774,8 +992,4 @@
 #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_HMAC)
     hmac->keyLen = 0;
-    #ifdef HAVE_CAVIUM
-        hmac->dataLen = 0;
-        hmac->data    = NULL;        /* buffered input data */
-    #endif /* HAVE_CAVIUM */
 
     ret = wolfAsync_DevCtxInit(&hmac->asyncDev, WOLFSSL_ASYNC_MARKER_HMAC,
@@ -794,17 +1008,109 @@
         return;
 
+    switch (hmac->macType) {
+    #ifndef NO_MD5
+        case WC_MD5:
+            wc_Md5Free(&hmac->hash.md5);
+            break;
+    #endif /* !NO_MD5 */
+
+    #ifndef NO_SHA
+        case WC_SHA:
+            wc_ShaFree(&hmac->hash.sha);
+            break;
+    #endif /* !NO_SHA */
+
+    #ifdef WOLFSSL_SHA224
+        case WC_SHA224:
+            wc_Sha224Free(&hmac->hash.sha224);
+            break;
+    #endif /* WOLFSSL_SHA224 */
+
+    #ifndef NO_SHA256
+        case WC_SHA256:
+            wc_Sha256Free(&hmac->hash.sha256);
+            break;
+    #endif /* !NO_SHA256 */
+
+    #ifdef WOLFSSL_SHA384
+        case WC_SHA384:
+            wc_Sha384Free(&hmac->hash.sha384);
+            break;
+    #endif /* WOLFSSL_SHA384 */
+    #ifdef WOLFSSL_SHA512
+        case WC_SHA512:
+            wc_Sha512Free(&hmac->hash.sha512);
+            break;
+    #endif /* WOLFSSL_SHA512 */
+
+    #ifdef HAVE_BLAKE2
+        case BLAKE2B_ID:
+            break;
+    #endif /* HAVE_BLAKE2 */
+
+    #ifdef WOLFSSL_SHA3
+        case WC_SHA3_224:
+            wc_Sha3_224_Free(&hmac->hash.sha3);
+            break;
+        case WC_SHA3_256:
+            wc_Sha3_256_Free(&hmac->hash.sha3);
+            break;
+        case WC_SHA3_384:
+            wc_Sha3_384_Free(&hmac->hash.sha3);
+            break;
+        case WC_SHA3_512:
+            wc_Sha3_512_Free(&hmac->hash.sha3);
+            break;
+    #endif /* WOLFSSL_SHA3 */
+
+        default:
+            break;
+    }
+
 #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_HMAC)
     wolfAsync_DevCtxFree(&hmac->asyncDev, WOLFSSL_ASYNC_MARKER_HMAC);
-
-#ifdef HAVE_CAVIUM
-    XFREE(hmac->data, hmac->heap, DYNAMIC_TYPE_HMAC);
-    hmac->data = NULL;
-#endif /* HAVE_CAVIUM */
 #endif /* WOLFSSL_ASYNC_CRYPT */
+
+    switch (hmac->macType) {
+    #ifndef NO_MD5
+        case WC_MD5:
+            wc_Md5Free(&hmac->hash.md5);
+            break;
+    #endif /* !NO_MD5 */
+
+    #ifndef NO_SHA
+        case WC_SHA:
+            wc_ShaFree(&hmac->hash.sha);
+            break;
+    #endif /* !NO_SHA */
+
+    #ifdef WOLFSSL_SHA224
+        case WC_SHA224:
+            wc_Sha224Free(&hmac->hash.sha224);
+            break;
+    #endif /* WOLFSSL_SHA224 */
+
+    #ifndef NO_SHA256
+        case WC_SHA256:
+            wc_Sha256Free(&hmac->hash.sha256);
+            break;
+    #endif /* !NO_SHA256 */
+
+    #ifdef WOLFSSL_SHA512
+    #ifdef WOLFSSL_SHA384
+        case WC_SHA384:
+            wc_Sha384Free(&hmac->hash.sha384);
+            break;
+    #endif /* WOLFSSL_SHA384 */
+        case WC_SHA512:
+            wc_Sha512Free(&hmac->hash.sha512);
+            break;
+    #endif /* WOLFSSL_SHA512 */
+    }
 }
 
 int wolfSSL_GetHmacMaxSize(void)
 {
-    return MAX_DIGEST_SIZE;
+    return WC_MAX_DIGEST_SIZE;
 }
 
@@ -824,5 +1130,5 @@
                         const byte* inKey, word32 inKeySz, byte* out)
     {
-        byte   tmp[MAX_DIGEST_SIZE]; /* localSalt helper */
+        byte   tmp[WC_MAX_DIGEST_SIZE]; /* localSalt helper */
         Hmac   myHmac;
         int    ret;
@@ -869,5 +1175,5 @@
                        const byte* info, word32 infoSz, byte* out, word32 outSz)
     {
-        byte   tmp[MAX_DIGEST_SIZE];
+        byte   tmp[WC_MAX_DIGEST_SIZE];
         Hmac   myHmac;
         int    ret = 0;
@@ -930,5 +1236,5 @@
                        byte* out,         word32 outSz)
     {
-        byte   prk[MAX_DIGEST_SIZE];
+        byte   prk[WC_MAX_DIGEST_SIZE];
         int    hashSz = wc_HmacSizeByType(type);
         int    ret;
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/integer.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/integer.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/integer.c	(revision 372)
@@ -46,4 +46,6 @@
 #ifndef USE_FAST_MATH
 
+#ifndef WOLFSSL_SP_MATH
+
 #include <wolfssl/wolfcrypt/integer.h>
 
@@ -320,4 +322,15 @@
 }
 
+int mp_to_unsigned_bin_len(mp_int * a, unsigned char *b, int c)
+{
+    int i, len;
+
+    len = mp_unsigned_bin_size(a);
+
+    /* pad front w/ zeros to match length */
+    for (i = 0; i < c - len; i++)
+        b[i] = 0x00;
+    return mp_to_unsigned_bin(a, b + i);
+}
 
 /* creates "a" then copies b into it */
@@ -3977,5 +3990,6 @@
 
 
-#if defined(WOLFSSL_KEY_GEN) || defined(HAVE_ECC)
+#if defined(WOLFSSL_KEY_GEN) || defined(HAVE_ECC) || !defined(NO_RSA) || \
+    !defined(NO_DSA) | !defined(NO_DH)
 
 /* c = a * a (mod b) */
@@ -4003,5 +4017,6 @@
 #if defined(HAVE_ECC) || !defined(NO_PWDBASED) || defined(WOLFSSL_SNIFFER) || \
     defined(WOLFSSL_HAVE_WOLFSCEP) || defined(WOLFSSL_KEY_GEN) || \
-    defined(OPENSSL_EXTRA) || defined(WC_RSA_BLINDING)
+    defined(OPENSSL_EXTRA) || defined(WC_RSA_BLINDING) || \
+    (!defined(NO_RSA) && !defined(NO_RSA_BOUNDS_CHECK))
 
 /* single digit addition */
@@ -4170,5 +4185,7 @@
 
 
-#if defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) || defined(HAVE_ECC)
+#if defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) || defined(HAVE_ECC) || \
+    defined(DEBUG_WOLFSSL) || !defined(NO_RSA) || !defined(NO_DSA) || \
+    !defined(NO_DH)
 
 static const int lnz[16] = {
@@ -4316,7 +4333,7 @@
 }
 
-#endif /* defined(WOLFSSL_KEY_GEN)||defined(HAVE_COMP_KEY)||defined(HAVE_ECC) */
-
-#ifdef WOLFSSL_KEY_GEN
+#endif /* WOLFSSL_KEY_GEN || HAVE_COMP_KEY || HAVE_ECC || DEBUG_WOLFSSL */
+
+#if defined(WOLFSSL_KEY_GEN) || !defined(NO_DH) || !defined(NO_DSA) || !defined(NO_RSA)
 
 const mp_digit ltm_prime_tab[PRIME_SIZE] = {
@@ -4474,4 +4491,159 @@
 }
 
+/*
+ * Sets result to 1 if probably prime, 0 otherwise
+ */
+int mp_prime_is_prime (mp_int * a, int t, int *result)
+{
+  mp_int  b;
+  int     ix, err, res;
+
+  /* default to no */
+  *result = MP_NO;
+
+  /* valid value of t? */
+  if (t <= 0 || t > PRIME_SIZE) {
+        return MP_VAL;
+    }
+
+  /* is the input equal to one of the primes in the table? */
+  for (ix = 0; ix < PRIME_SIZE; ix++) {
+      if (mp_cmp_d(a, ltm_prime_tab[ix]) == MP_EQ) {
+         *result = 1;
+         return MP_OKAY;
+      }
+    }
+
+  /* first perform trial division */
+  if ((err = mp_prime_is_divisible (a, &res)) != MP_OKAY) {
+            return err;
+        }
+
+  /* return if it was trivially divisible */
+  if (res == MP_YES) {
+    return MP_OKAY;
+  }
+
+  /* now perform the miller-rabin rounds */
+  if ((err = mp_init (&b)) != MP_OKAY) {
+            return err;
+        }
+
+  for (ix = 0; ix < t; ix++) {
+    /* set the prime */
+    if ((err = mp_set (&b, ltm_prime_tab[ix])) != MP_OKAY) {
+        goto LBL_B;
+        }
+
+    if ((err = mp_prime_miller_rabin (a, &b, &res)) != MP_OKAY) {
+      goto LBL_B;
+    }
+
+    if (res == MP_NO) {
+      goto LBL_B;
+    }
+  }
+
+  /* passed the test */
+  *result = MP_YES;
+LBL_B:mp_clear (&b);
+  return err;
+}
+
+
+/*
+ * Sets result to 1 if probably prime, 0 otherwise
+ */
+int mp_prime_is_prime_ex (mp_int * a, int t, int *result, WC_RNG *rng)
+{
+  mp_int  b, c;
+  int     ix, err, res;
+  byte*   base = NULL;
+  word32  baseSz = 0;
+
+  /* default to no */
+  *result = MP_NO;
+
+  /* valid value of t? */
+  if (t <= 0 || t > PRIME_SIZE) {
+    return MP_VAL;
+  }
+
+  /* is the input equal to one of the primes in the table? */
+  for (ix = 0; ix < PRIME_SIZE; ix++) {
+      if (mp_cmp_d(a, ltm_prime_tab[ix]) == MP_EQ) {
+         *result = MP_YES;
+         return MP_OKAY;
+      }
+  }
+
+  /* first perform trial division */
+  if ((err = mp_prime_is_divisible (a, &res)) != MP_OKAY) {
+    return err;
+  }
+
+  /* return if it was trivially divisible */
+  if (res == MP_YES) {
+    return MP_OKAY;
+  }
+
+  /* now perform the miller-rabin rounds */
+  if ((err = mp_init (&b)) != MP_OKAY) {
+    return err;
+  }
+  if ((err = mp_init (&c)) != MP_OKAY) {
+      mp_clear(&b);
+    return err;
+  }
+
+  baseSz = mp_count_bits(a);
+  baseSz = (baseSz / 8) + ((baseSz % 8) ? 1 : 0);
+
+  base = (byte*)XMALLOC(baseSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+  if (base == NULL) {
+      err = MP_MEM;
+      goto LBL_B;
+  }
+
+  if ((err = mp_sub_d(a, 2, &c)) != MP_OKAY) {
+      goto LBL_B;
+  }
+
+ /* now do a miller rabin with up to t random numbers, this should
+  * give a (1/4)^t chance of a false prime. */
+  for (ix = 0; ix < t; ix++) {
+    /* Set a test candidate. */
+    if ((err = wc_RNG_GenerateBlock(rng, base, baseSz)) != 0) {
+        goto LBL_B;
+    }
+
+    if ((err = mp_read_unsigned_bin(&b, base, baseSz)) != MP_OKAY) {
+        goto LBL_B;
+    }
+
+    if (mp_cmp_d(&b, 2) != MP_GT || mp_cmp(&b, &c) != MP_LT)
+        continue;
+
+    if ((err = mp_prime_miller_rabin (a, &b, &res)) != MP_OKAY) {
+      goto LBL_B;
+    }
+
+    if (res == MP_NO) {
+      goto LBL_B;
+    }
+  }
+
+  /* passed the test */
+  *result = MP_YES;
+LBL_B:mp_clear (&b);
+      mp_clear (&c);
+      XFREE(base, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+  return err;
+}
+
+#endif /* WOLFSSL_KEY_GEN NO_DH NO_DSA NO_RSA */
+
+#ifdef WOLFSSL_KEY_GEN
+
 static const int USE_BBS = 1;
 
@@ -4527,5 +4699,9 @@
 
         /* test */
-        if ((err = mp_prime_is_prime(N, 8, &res)) != MP_OKAY) {
+        /* Running Miller-Rabin up to 3 times gives us a 2^{-80} chance
+         * of a 1024-bit candidate being a false positive, when it is our
+         * prime candidate. (Note 4.49 of Handbook of Applied Cryptography.)
+         * Using 8 because we've always used 8. */
+        if ((err = mp_prime_is_prime_ex(N, 8, &res, rng)) != MP_OKAY) {
             XFREE(buf, heap, DYNAMIC_TYPE_RSA);
             return err;
@@ -4537,64 +4713,4 @@
 
     return MP_OKAY;
-}
-
-/*
- * Sets result to 1 if probably prime, 0 otherwise
- */
-int mp_prime_is_prime (mp_int * a, int t, int *result)
-{
-  mp_int  b;
-  int     ix, err, res;
-
-  /* default to no */
-  *result = MP_NO;
-
-  /* valid value of t? */
-  if (t <= 0 || t > PRIME_SIZE) {
-    return MP_VAL;
-  }
-
-  /* is the input equal to one of the primes in the table? */
-  for (ix = 0; ix < PRIME_SIZE; ix++) {
-      if (mp_cmp_d(a, ltm_prime_tab[ix]) == MP_EQ) {
-         *result = 1;
-         return MP_OKAY;
-      }
-  }
-
-  /* first perform trial division */
-  if ((err = mp_prime_is_divisible (a, &res)) != MP_OKAY) {
-    return err;
-  }
-
-  /* return if it was trivially divisible */
-  if (res == MP_YES) {
-    return MP_OKAY;
-  }
-
-  /* now perform the miller-rabin rounds */
-  if ((err = mp_init (&b)) != MP_OKAY) {
-    return err;
-  }
-
-  for (ix = 0; ix < t; ix++) {
-    /* set the prime */
-    if ((err = mp_set (&b, ltm_prime_tab[ix])) != MP_OKAY) {
-        goto LBL_B;
-    }
-
-    if ((err = mp_prime_miller_rabin (a, &b, &res)) != MP_OKAY) {
-      goto LBL_B;
-    }
-
-    if (res == MP_NO) {
-      goto LBL_B;
-    }
-  }
-
-  /* passed the test */
-  *result = MP_YES;
-LBL_B:mp_clear (&b);
-  return err;
 }
 
@@ -4729,5 +4845,7 @@
 
 
-#if defined(HAVE_ECC) || defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY)
+#if !defined(NO_DSA) || defined(HAVE_ECC) || defined(WOLFSSL_KEY_GEN) || \
+    defined(HAVE_COMP_KEY) || defined(WOLFSSL_DEBUG_MATH) || \
+    defined(DEBUG_WOLFSSL) || defined(OPENSSL_EXTRA)
 
 /* chars used in radix conversions */
@@ -4736,5 +4854,5 @@
 #endif
 
-#ifdef HAVE_ECC
+#if !defined(NO_DSA) || defined(HAVE_ECC)
 /* read a string [ASCII] in a given radix */
 int mp_read_radix (mp_int * a, const char *str, int radix)
@@ -4747,5 +4865,5 @@
 
   /* make sure the radix is ok */
-  if (radix < 2 || radix > 64) {
+  if (radix < MP_RADIX_BIN || radix > MP_RADIX_MAX) {
     return MP_VAL;
   }
@@ -4806,8 +4924,7 @@
   return MP_OKAY;
 }
-#endif /* HAVE_ECC */
-
-#if defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) || \
-    defined(WOLFSSL_DEBUG_MATH)
+#endif /* !defined(NO_DSA) || defined(HAVE_ECC) */
+
+#ifdef WC_MP_TO_RADIX
 
 /* returns size of ASCII representation */
@@ -4821,5 +4938,5 @@
 
     /* special case for binary */
-    if (radix == 2) {
+    if (radix == MP_RADIX_BIN) {
         *size = mp_count_bits (a) + (a->sign == MP_NEG ? 1 : 0) + 1;
         return MP_OKAY;
@@ -4827,5 +4944,5 @@
 
     /* make sure the radix is in range */
-    if (radix < 2 || radix > 64) {
+    if (radix < MP_RADIX_BIN || radix > MP_RADIX_MAX) {
         return MP_VAL;
     }
@@ -4876,5 +4993,5 @@
 
     /* check range of the radix */
-    if (radix < 2 || radix > 64) {
+    if (radix < MP_RADIX_BIN || radix > MP_RADIX_MAX) {
         return MP_VAL;
     }
@@ -4934,5 +5051,5 @@
     desc, a, a->used, a->sign, size, (int)sizeof(mp_digit));
 
-  mp_toradix(a, buffer, 16);
+  mp_tohex(a, buffer);
   printf("  %s\n  ", buffer);
 
@@ -4949,5 +5066,7 @@
 #endif /* WOLFSSL_DEBUG_MATH */
 
-#endif /* defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) || defined(WOLFSSL_DEBUG_MATH) */
+#endif /* WC_MP_TO_RADIX */
+
+#endif /* WOLFSSL_SP_MATH */
 
 #endif /* USE_FAST_MATH */
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/logging.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/logging.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/logging.c	(revision 372)
@@ -31,13 +31,7 @@
 #include <wolfssl/wolfcrypt/logging.h>
 #include <wolfssl/wolfcrypt/error-crypt.h>
-
-
-#ifdef __cplusplus
-    extern "C" {
-#endif
-    WOLFSSL_API int  wolfSSL_Debugging_ON(void);
-    WOLFSSL_API void wolfSSL_Debugging_OFF(void);
-#ifdef __cplusplus
-    }
+#if defined(OPENSSL_EXTRA) && !defined(WOLFCRYPT_ONLY)
+/* avoid adding WANT_READ and WANT_WRITE to error queue */
+#include <wolfssl/error-ssl.h>
 #endif
 
@@ -58,11 +52,67 @@
 };
 volatile struct wc_error_queue* wc_errors;
+static struct wc_error_queue* wc_current_node;
 static struct wc_error_queue* wc_last_node;
 /* pointer to last node in queue to make insertion O(1) */
 #endif
 
-
-
-#if defined(DEBUG_WOLFSSL)
+#ifdef WOLFSSL_FUNC_TIME
+/* WARNING: This code is only to be used for debugging performance.
+ *          The code is not thread-safe.
+ *          Do not use WOLFSSL_FUNC_TIME in production code.
+ */
+static double wc_func_start[WC_FUNC_COUNT];
+static double wc_func_time[WC_FUNC_COUNT] = { 0, };
+static const char* wc_func_name[WC_FUNC_COUNT] = {
+    "SendHelloRequest",
+    "DoHelloRequest",
+    "SendClientHello",
+    "DoClientHello",
+    "SendServerHello",
+    "DoServerHello",
+    "SendEncryptedExtensions",
+    "DoEncryptedExtensions",
+    "SendCertificateRequest",
+    "DoCertificateRequest",
+    "SendCertificate",
+    "DoCertificate",
+    "SendCertificateVerify",
+    "DoCertificateVerify",
+    "SendFinished",
+    "DoFinished",
+    "SendKeyUpdate",
+    "DoKeyUpdate",
+    "SendEarlyData",
+    "DoEarlyData",
+    "SendNewSessionTicket",
+    "DoNewSessionTicket",
+    "SendServerHelloDone",
+    "DoServerHelloDone",
+    "SendTicket",
+    "DoTicket",
+    "SendClientKeyExchange",
+    "DoClientKeyExchange",
+    "SendCertificateStatus",
+    "DoCertificateStatus",
+    "SendServerKeyExchange",
+    "DoServerKeyExchange",
+    "SendEarlyData",
+    "DoEarlyData",
+};
+
+#include <sys/time.h>
+
+/* WARNING: This function is not portable. */
+static WC_INLINE double current_time(int reset)
+{
+    struct timeval tv;
+    gettimeofday(&tv, 0);
+    (void)reset;
+
+    return (double)tv.tv_sec + (double)tv.tv_usec / 1000000;
+}
+#endif /* WOLFSSL_FUNC_TIME */
+
+#ifdef DEBUG_WOLFSSL
 
 /* Set these to default values initially. */
@@ -70,18 +120,18 @@
 static int loggingEnabled = 0;
 
+#if defined(WOLFSSL_APACHE_MYNEWT)
+#include "log/log.h"
+static struct log mynewt_log;
+#endif /* WOLFSSL_APACHE_MYNEWT */
+
 #endif /* DEBUG_WOLFSSL */
 
 
+/* allow this to be set to NULL, so logs can be redirected to default output */
 int wolfSSL_SetLoggingCb(wolfSSL_Logging_cb f)
 {
 #ifdef DEBUG_WOLFSSL
-    int res = 0;
-
-    if (f)
         log_function = f;
-    else
-        res = BAD_FUNC_ARG;
-
-    return res;
+    return 0;
 #else
     (void)f;
@@ -95,4 +145,7 @@
 #ifdef DEBUG_WOLFSSL
     loggingEnabled = 1;
+#if defined(WOLFSSL_APACHE_MYNEWT)
+    log_register("wolfcrypt", &mynewt_log, &log_console_handler, NULL, LOG_SYSLEVEL);
+#endif /* WOLFSSL_APACHE_MYNEWT */
     return 0;
 #else
@@ -109,4 +162,42 @@
 }
 
+#ifdef WOLFSSL_FUNC_TIME
+/* WARNING: This code is only to be used for debugging performance.
+ *          The code is not thread-safe.
+ *          Do not use WOLFSSL_FUNC_TIME in production code.
+ */
+void WOLFSSL_START(int funcNum)
+{
+    double now = current_time(0) * 1000.0;
+#ifdef WOLFSSL_FUNC_TIME_LOG
+    fprintf(stderr, "%17.3f: START - %s\n", now, wc_func_name[funcNum]);
+#endif
+    wc_func_start[funcNum] = now;
+}
+
+void WOLFSSL_END(int funcNum)
+{
+    double now = current_time(0) * 1000.0;
+    wc_func_time[funcNum] += now - wc_func_start[funcNum];
+#ifdef WOLFSSL_FUNC_TIME_LOG
+    fprintf(stderr, "%17.3f: END   - %s\n", now, wc_func_name[funcNum]);
+#endif
+}
+
+void WOLFSSL_TIME(int count)
+{
+    int i;
+    double avg, total = 0;
+
+    for (i = 0; i < WC_FUNC_COUNT; i++) {
+        if (wc_func_time[i] > 0) {
+            avg = wc_func_time[i] / count;
+            fprintf(stderr, "%8.3f ms: %s\n", avg, wc_func_name[i]);
+            total += avg;
+        }
+    }
+    fprintf(stderr, "%8.3f ms\n", total);
+}
+#endif
 
 #ifdef DEBUG_WOLFSSL
@@ -122,5 +213,12 @@
     int sprintf(char* buf, const char *fmt, ...);
 #elif defined(MICRIUM)
+    #if (BSP_SER_COMM_EN  == DEF_ENABLED)
     #include <bsp_ser.h>
+    #endif
+#elif defined(WOLFSSL_USER_LOG)
+    /* user includes their own headers */
+#elif defined(WOLFSSL_ESPIDF)
+    #include "esp_types.h"
+    #include "esp_log.h"
 #else
     #include <stdio.h>   /* for default printf stuff */
@@ -136,6 +234,10 @@
         log_function(logLevel, logMessage);
     else {
-        if (loggingEnabled) {
-#if defined(THREADX) && !defined(THREADX_NO_DC_PRINTF)
+#if defined(WOLFSSL_USER_LOG)
+        WOLFSSL_USER_LOG(logMessage);
+#elif defined(WOLFSSL_LOG_PRINTF)
+        printf("%s\n", logMessage);
+
+#elif defined(THREADX) && !defined(THREADX_NO_DC_PRINTF)
             dc_log_printf("%s\n", logMessage);
 #elif defined(MICRIUM)
@@ -145,6 +247,4 @@
             printf("%s\n", logMessage);
             fflush(stdout) ;
-#elif defined(WOLFSSL_LOG_PRINTF)
-            printf("%s\n", logMessage);
 #elif defined(WOLFSSL_UTASKER)
             fnDebugMsg((char*)logMessage);
@@ -152,4 +252,10 @@
 #elif defined(MQX_USE_IO_OLD)
             fprintf(_mqxio_stderr, "%s\n", logMessage);
+
+#elif defined(WOLFSSL_APACHE_MYNEWT)
+        LOG_DEBUG(&mynewt_log, LOG_MODULE_DEFAULT, "%s\n", logMessage);
+#elif defined(WOLFSSL_ESPIDF)
+        extern char* TAG;
+        ESP_LOGI(TAG, "%s", logMessage);
 #else
             fprintf(stderr, "%s\n", logMessage);
@@ -157,7 +263,6 @@
         }
     }
-}
-
-
+
+#ifndef WOLFSSL_DEBUG_ERRORS_ONLY
 void WOLFSSL_MSG(const char* msg)
 {
@@ -208,6 +313,6 @@
 {
     if (loggingEnabled) {
-        char buffer[80];
-        sprintf(buffer, "wolfSSL Entering %s", msg);
+        char buffer[WOLFSSL_MAX_ERROR_SZ];
+        XSNPRINTF(buffer, sizeof(buffer), "wolfSSL Entering %s", msg);
         wolfssl_log(ENTER_LOG , buffer);
     }
@@ -218,9 +323,11 @@
 {
     if (loggingEnabled) {
-        char buffer[80];
-        sprintf(buffer, "wolfSSL Leaving %s, return %d", msg, ret);
+        char buffer[WOLFSSL_MAX_ERROR_SZ];
+        XSNPRINTF(buffer, sizeof(buffer), "wolfSSL Leaving %s, return %d",
+                msg, ret);
         wolfssl_log(LEAVE_LOG , buffer);
     }
 }
+#endif /* !WOLFSSL_DEBUG_ERRORS_ONLY */
 #endif  /* DEBUG_WOLFSSL */
 
@@ -230,6 +337,8 @@
  * name where WOLFSSL_ERROR is called at.
  */
-#if (defined(DEBUG_WOLFSSL) || defined(WOLFSSL_NGINX)) || defined(WOLFSSL_HAPROXY)
-    #if (defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE))
+#if defined(DEBUG_WOLFSSL) || defined(OPENSSL_ALL) || \
+    defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+
+#if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE)
 void WOLFSSL_ERROR_LINE(int error, const char* func, unsigned int line,
             const char* file, void* usrCtx)
@@ -238,9 +347,10 @@
     #endif
 {
-    #if defined(DEBUG_WOLFSSL) && !defined(WOLFSSL_NGINX)
-    if (loggingEnabled && error != WC_PENDING_E)
+#ifdef WOLFSSL_ASYNC_CRYPT
+    if (error != WC_PENDING_E)
     #endif
     {
-        char buffer[80];
+        char buffer[WOLFSSL_MAX_ERROR_SZ];
+
         #if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE)
             (void)usrCtx; /* a user ctx for future flexibility */
@@ -249,9 +359,17 @@
             if (wc_LockMutex(&debug_mutex) != 0) {
                 WOLFSSL_MSG("Lock debug mutex failed");
-                sprintf(buffer, "wolfSSL error occurred, error = %d", error);
+            XSNPRINTF(buffer, sizeof(buffer),
+                    "wolfSSL error occurred, error = %d", error);
             }
             else {
-                if (error < 0) error = error - (2*error); /*get absolute value*/
-                sprintf(buffer, "wolfSSL error occurred, error = %d line:%d file:%s",
+            #if defined(OPENSSL_EXTRA) && !defined(WOLFCRYPT_ONLY)
+            /* If running in compatibility mode do not add want read and
+               want right to error queue */
+            if (error != WANT_READ && error != WANT_WRITE) {
+            #endif
+            if (error < 0)
+                error = error - (2 * error); /* get absolute value */
+            XSNPRINTF(buffer, sizeof(buffer),
+                    "wolfSSL error occurred, error = %d line:%d file:%s",
                     error, line, file);
                 if (wc_AddErrorNode(error, line, buffer, (char*)file) != 0) {
@@ -260,14 +378,35 @@
                      * to unlock mutex and log what buffer was created. */
                 }
+            #if defined(OPENSSL_EXTRA) && !defined(WOLFCRYPT_ONLY)
+            }
+            else {
+                XSNPRINTF(buffer, sizeof(buffer),
+                    "wolfSSL error occurred, error = %d", error);
+
+            }
+            #endif
 
                 wc_UnLockMutex(&debug_mutex);
             }
         #else
-            sprintf(buffer, "wolfSSL error occurred, error = %d", error);
+        XSNPRINTF(buffer, sizeof(buffer),
+                "wolfSSL error occurred, error = %d", error);
         #endif
+
         #ifdef DEBUG_WOLFSSL
+        if (loggingEnabled)
         wolfssl_log(ERROR_LOG , buffer);
         #endif
     }
+}
+
+void WOLFSSL_ERROR_MSG(const char* msg)
+{
+#ifdef DEBUG_WOLFSSL
+    if (loggingEnabled)
+        wolfssl_log(ERROR_LOG , msg);
+#else
+    (void)msg;
+#endif
 }
 
@@ -283,4 +422,5 @@
     }
     wc_errors          = NULL;
+    wc_current_node    = NULL;
     wc_last_node       = NULL;
 
@@ -304,6 +444,4 @@
 
 
-#if defined(DEBUG_WOLFSSL) || defined(WOLFSSL_NGINX) || \
-    defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_MYSQL_COMPATIBLE)
 /* peek at an error node
  *
@@ -367,4 +505,51 @@
 
 
+/* Pulls the current node from error queue and increments current state.
+ * Note: this does not delete nodes because input arguments are pointing to
+ *       node buffers.
+ *
+ * file   pointer to file that error was in. Can be NULL to return no file.
+ * reason error string giving reason for error. Can be NULL to return no reason.
+ * line   return line number of where error happened.
+ *
+ * returns the error value on success and BAD_MUTEX_E or BAD_STATE_E on failure
+ */
+int wc_PullErrorNode(const char **file, const char **reason, int *line)
+{
+    struct wc_error_queue* err;
+    int value;
+
+    if (wc_LockMutex(&debug_mutex) != 0) {
+        WOLFSSL_MSG("Lock debug mutex failed");
+        return BAD_MUTEX_E;
+    }
+
+    err = wc_current_node;
+    if (err == NULL) {
+        WOLFSSL_MSG("No Errors in queue");
+        wc_UnLockMutex(&debug_mutex);
+        return BAD_STATE_E;
+    }
+
+    if (file != NULL) {
+        *file = err->file;
+    }
+
+    if (reason != NULL) {
+        *reason = err->error;
+    }
+
+    if (line != NULL) {
+        *line = err->line;
+    }
+
+    value = err->value;
+    wc_current_node = err->next;
+    wc_UnLockMutex(&debug_mutex);
+
+    return value;
+}
+
+
 /* create new error node and add it to the queue
  * buffers are assumed to be of size WOLFSSL_MAX_ERROR_SZ for this internal
@@ -416,8 +601,14 @@
                 /* check for unexpected case before over writing wc_errors */
                 WOLFSSL_MSG("ERROR in adding new node to logging queue!!\n");
+                /* In the event both wc_last_node and wc_errors are NULL, err
+                 * goes unassigned to external wc_errors, wc_last_node. Free
+                 * err in this instance since wc_ClearErrorNodes will not
+                 */
+                XFREE(err, wc_error_heap, DYNAMIC_TYPE_LOG);
             }
             else {
                 wc_errors    = err;
                 wc_last_node = err;
+                wc_current_node = err;
             }
         }
@@ -426,4 +617,10 @@
             err->prev = wc_last_node;
             wc_last_node = err;
+
+            /* check the case where have read to the end of the queue and the
+             * current node to read needs updated */
+            if (wc_current_node == NULL) {
+                wc_current_node = err;
+            }
         }
     }
@@ -465,5 +662,4 @@
 }
 
-#endif /* DEBUG_WOLFSSL || WOLFSSL_NGINX */
 
 /* Clears out the list of error nodes.
@@ -471,4 +667,7 @@
 void wc_ClearErrorNodes(void)
 {
+#if defined(DEBUG_WOLFSSL) || defined(WOLFSSL_NGINX) || \
+    defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE)
+
     if (wc_LockMutex(&debug_mutex) != 0) {
         WOLFSSL_MSG("Lock debug mutex failed");
@@ -491,5 +690,7 @@
     wc_errors    = NULL;
     wc_last_node = NULL;
+    wc_current_node = NULL;
     wc_UnLockMutex(&debug_mutex);
+#endif /* DEBUG_WOLFSSL || WOLFSSL_NGINX */
 }
 
@@ -505,14 +706,48 @@
 }
 
+
+/* frees all nodes in the queue
+ *
+ * id  this is the thread id
+ */
+int wc_ERR_remove_state(void)
+{
+    struct wc_error_queue* current;
+    struct wc_error_queue* next;
+
+    if (wc_LockMutex(&debug_mutex) != 0) {
+        WOLFSSL_MSG("Lock debug mutex failed");
+        return BAD_MUTEX_E;
+    }
+
+    /* free all nodes from error queue */
+    current = (struct wc_error_queue*)wc_errors;
+    while (current != NULL) {
+        next = current->next;
+        XFREE(current, current->heap, DYNAMIC_TYPE_LOG);
+        current = next;
+    }
+
+    wc_errors          = NULL;
+    wc_last_node       = NULL;
+
+    wc_UnLockMutex(&debug_mutex);
+
+    return 0;
+}
+
+
 #if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM)
 /* empties out the error queue into the file */
-void wc_ERR_print_errors_fp(FILE* fp)
+void wc_ERR_print_errors_fp(XFILE fp)
 {
     WOLFSSL_ENTER("wc_ERR_print_errors_fp");
 
-    if (wc_LockMutex(&debug_mutex) != 0) {
+        if (wc_LockMutex(&debug_mutex) != 0)
+        {
         WOLFSSL_MSG("Lock debug mutex failed");
     }
-    else {
+        else
+        {
         /* free all nodes from error queue and print them to file */
         {
@@ -521,5 +756,6 @@
 
             current = (struct wc_error_queue*)wc_errors;
-            while (current != NULL) {
+                while (current != NULL)
+                {
                 next = current->next;
                 fprintf(fp, "%s\n", current->error);
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/md4.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/md4.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/md4.c	(revision 372)
@@ -131,5 +131,5 @@
 
 
-static INLINE void AddLength(Md4* md4, word32 len)
+static WC_INLINE void AddLength(Md4* md4, word32 len)
 {
     word32 tmp = md4->loLen;
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/md5.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/md5.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/md5.c	(revision 372)
@@ -47,66 +47,20 @@
 
 
-static INLINE void AddLength(wc_Md5* md5, word32 len);
-
 /* Hardware Acceleration */
 #if defined(STM32_HASH)
 
-    /*
-     * STM32F2/F4/F7 hardware MD5 support through the HASH_* API's from the
-     * Standard Peripheral Library or CubeMX (See note in README).
-     */
-
+    /* Supports CubeMX HAL or Standard Peripheral Library */
 	#define HAVE_MD5_CUST_API
-
-    /* STM32 register size, bytes */
-    #ifdef WOLFSSL_STM32_CUBEMX
-        #define MD5_REG_SIZE  WC_MD5_BLOCK_SIZE
-    #else
-        #define MD5_REG_SIZE  4
-        /* STM32 struct notes:
-         * md5->buffer  = first 4 bytes used to hold partial block if needed
-         * md5->buffLen = num bytes currently stored in md5->buffer
-         * md5->loLen   = num bytes that have been written to STM32 FIFO
-         */
-    #endif
-    #define MD5_HW_TIMEOUT 0xFF
 
     int wc_InitMd5_ex(wc_Md5* md5, void* heap, int devId)
     {
-        if (md5 == NULL)
+        if (md5 == NULL) {
             return BAD_FUNC_ARG;
-
+        }
+
+        (void)devId;
         (void)heap;
-        (void)devId;
-
-        md5->heap = heap;
-        XMEMSET(md5->buffer, 0, sizeof(md5->buffer));
-        md5->buffLen = 0;
-        md5->loLen = 0;
-        md5->hiLen = 0;
-
-        /* initialize HASH peripheral */
-    #ifdef WOLFSSL_STM32_CUBEMX
-        HAL_HASH_DeInit(&md5->hashHandle);
-        md5->hashHandle.Init.DataType = HASH_DATATYPE_8B;
-        if (HAL_HASH_Init(&md5->hashHandle) != HAL_OK) {
-            return ASYNC_INIT_E;
-        }
-        /* reset the hash control register */
-        /* required because Cube MX is not clearing algo bits */
-        HASH->CR &= ~HASH_CR_ALGO;
-    #else
-		HASH_DeInit();
-
-        /* reset the control register */
-        HASH->CR &= ~ (HASH_CR_ALGO | HASH_CR_DATATYPE | HASH_CR_MODE);
-
-		/* configure algo used, algo mode, datatype */
-		HASH->CR |= (HASH_AlgoSelection_MD5 | HASH_AlgoMode_HASH
-				   | HASH_DataType_8b);
-
-		/* reset HASH processor */
-		HASH->CR |= HASH_CR_INIT;
-    #endif
+
+        wc_Stm32_Hash_Init(&md5->stmCtx);
 
         return 0;
@@ -115,6 +69,5 @@
     int wc_Md5Update(wc_Md5* md5, const byte* data, word32 len)
     {
-        int ret = 0;
-        byte* local;
+        int ret;
 
         if (md5 == NULL || (data == NULL && len > 0)) {
@@ -122,32 +75,9 @@
         }
 
-        /* do block size increments */
-        local = (byte*)md5->buffer;
-
-        /* check that internal buffLen is valid */
-        if (md5->buffLen >= MD5_REG_SIZE)
-            return BUFFER_E;
-
-        while (len) {
-            word32 add = min(len, MD5_REG_SIZE - md5->buffLen);
-            XMEMCPY(&local[md5->buffLen], data, add);
-
-            md5->buffLen += add;
-            data         += add;
-            len          -= add;
-
-            if (md5->buffLen == MD5_REG_SIZE) {
-            #ifdef WOLFSSL_STM32_CUBEMX
-                if (HAL_HASH_MD5_Accumulate(
-                        &md5->hashHandle, local, MD5_REG_SIZE) != HAL_OK) {
-                    ret = ASYNC_OP_E;
-                }
-            #else
-                HASH_DataIn(*(uint32_t*)local);
-            #endif
-
-                AddLength(md5, MD5_REG_SIZE);
-                md5->buffLen = 0;
-            }
+        ret = wolfSSL_CryptHwMutexLock();
+        if (ret == 0) {
+            ret = wc_Stm32_Hash_Update(&md5->stmCtx, HASH_AlgoSelection_MD5,
+                data, len);
+            wolfSSL_CryptHwMutexUnLock();
         }
         return ret;
@@ -156,46 +86,16 @@
     int wc_Md5Final(wc_Md5* md5, byte* hash)
     {
-        int ret = 0;
-
-        if (md5 == NULL || hash == NULL)
+        int ret;
+
+        if (md5 == NULL || hash == NULL) {
             return BAD_FUNC_ARG;
-
-    #ifdef WOLFSSL_STM32_CUBEMX
-        if (HAL_HASH_MD5_Start(&md5->hashHandle,
-                (byte*)md5->buffer, md5->buffLen,
-                (byte*)md5->digest, MD5_HW_TIMEOUT) != HAL_OK) {
-            ret = ASYNC_OP_E;
-        }
-    #else
-        __IO uint16_t nbvalidbitsdata = 0;
-
-        /* finish reading any trailing bytes into FIFO */
-        if (md5->buffLen > 0) {
-			HASH_DataIn(*(uint32_t*)md5->buffer);
-            AddLength(md5, md5->buffLen);
-        }
-
-        /* calculate number of valid bits in last word of input data */
-        nbvalidbitsdata = 8 * (md5->loLen % MD5_REG_SIZE);
-
-        /* configure number of valid bits in last word of the data */
-        HASH_SetLastWordValidBitsNbr(nbvalidbitsdata);
-
-        /* start HASH processor */
-        HASH_StartDigest();
-
-        /* wait until Busy flag == RESET */
-        while (HASH_GetFlagStatus(HASH_FLAG_BUSY) != RESET) {}
-
-        /* read message digest */
-        md5->digest[0] = HASH->HR[0];
-        md5->digest[1] = HASH->HR[1];
-        md5->digest[2] = HASH->HR[2];
-        md5->digest[3] = HASH->HR[3];
-
-        ByteReverseWords(md5->digest, md5->digest, WC_MD5_DIGEST_SIZE);
-    #endif /* WOLFSSL_STM32_CUBEMX */
-
-        XMEMCPY(hash, md5->digest, WC_MD5_DIGEST_SIZE);
+        }
+
+        ret = wolfSSL_CryptHwMutexLock();
+        if (ret == 0) {
+            ret = wc_Stm32_Hash_Final(&md5->stmCtx, HASH_AlgoSelection_MD5,
+                hash, WC_MD5_DIGEST_SIZE);
+            wolfSSL_CryptHwMutexUnLock();
+        }
 
         (void)wc_InitMd5(md5);  /* reset state */
@@ -226,4 +126,7 @@
     #define HAVE_MD5_CUST_API
 
+#elif defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_HASH)
+    /* functions implemented in wolfcrypt/src/port/caam/caam_sha.c */
+    #define HAVE_MD5_CUST_API
 #else
     #define NEED_SOFT_MD5
@@ -330,6 +233,7 @@
 #endif /* NEED_SOFT_MD5 */
 
-#if !defined(HAVE_MD5_CUST_API) || defined(STM32_HASH)
-static INLINE void AddLength(wc_Md5* md5, word32 len)
+#ifndef HAVE_MD5_CUST_API
+
+static WC_INLINE void AddLength(wc_Md5* md5, word32 len)
 {
     word32 tmp = md5->loLen;
@@ -338,7 +242,5 @@
     }
 }
-#endif
-
-#ifndef HAVE_MD5_CUST_API
+
 static int _InitMd5(wc_Md5* md5)
 {
@@ -498,4 +400,8 @@
     wolfAsync_DevCtxFree(&md5->asyncDev, WOLFSSL_ASYNC_MARKER_MD5);
 #endif /* WOLFSSL_ASYNC_CRYPT */
+
+#ifdef WOLFSSL_PIC32MZ_HASH
+    wc_Md5Pic32Free(md5);
+#endif
 }
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/memory.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/memory.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/memory.c	(revision 372)
@@ -35,4 +35,24 @@
 #endif
 
+
+/*
+Possible memory options:
+ * NO_WOLFSSL_MEMORY:               Disables wolf memory callback support. When not defined settings.h defines USE_WOLFSSL_MEMORY.
+ * WOLFSSL_STATIC_MEMORY:           Turns on the use of static memory buffers and functions.
+                                        This allows for using static memory instead of dynamic.
+ * WOLFSSL_STATIC_ALIGN:            Define defaults to 16 to indicate static memory alignment.
+ * HAVE_IO_POOL:                    Enables use of static thread safe memory pool for input/output buffers.
+ * XMALLOC_OVERRIDE:                Allows override of the XMALLOC, XFREE and XREALLOC macros.
+ * XMALLOC_USER:                    Allows custom XMALLOC, XFREE and XREALLOC functions to be defined.
+ * WOLFSSL_NO_MALLOC:               Disables the fall-back case to use STDIO malloc/free when no callbacks are set.
+ * WOLFSSL_TRACK_MEMORY:            Enables memory tracking for total stats and list of allocated memory.
+ * WOLFSSL_DEBUG_MEMORY:            Enables extra function and line number args for memory callbacks.
+ * WOLFSSL_DEBUG_MEMORY_PRINT:      Enables printing of each malloc/free.
+ * WOLFSSL_MALLOC_CHECK:            Reports malloc or alignment failure using WOLFSSL_STATIC_ALIGN
+ * WOLFSSL_FORCE_MALLOC_FAIL_TEST:  Used for internal testing to induce random malloc failures.
+ * WOLFSSL_HEAP_TEST:               Used for internal testing of heap hint
+ */
+
+
 #ifdef USE_WOLFSSL_MEMORY
 
@@ -41,5 +61,21 @@
 #include <wolfssl/wolfcrypt/logging.h>
 
-#if defined(WOLFSSL_MALLOC_CHECK) || defined(WOLFSSL_TRACK_MEMORY_FULL)
+#if defined(WOLFSSL_DEBUG_MEMORY) && defined(WOLFSSL_DEBUG_MEMORY_PRINT)
+#include <stdio.h>
+#endif
+
+#ifdef WOLFSSL_FORCE_MALLOC_FAIL_TEST
+    static int gMemFailCountSeed;
+    static int gMemFailCount;
+    void wolfSSL_SetMemFailCount(int memFailCount)
+    {
+        if (gMemFailCountSeed == 0) {
+            gMemFailCountSeed = memFailCount;
+            gMemFailCount = memFailCount;
+        }
+    }
+#endif
+#if defined(WOLFSSL_MALLOC_CHECK) || defined(WOLFSSL_TRACK_MEMORY_FULL) || \
+                                                     defined(WOLFSSL_MEMORY_LOG)
     #include <stdio.h>
 #endif
@@ -47,7 +83,7 @@
 
 /* Set these to default values initially. */
-static wolfSSL_Malloc_cb  malloc_function = 0;
-static wolfSSL_Free_cb    free_function = 0;
-static wolfSSL_Realloc_cb realloc_function = 0;
+static wolfSSL_Malloc_cb  malloc_function = NULL;
+static wolfSSL_Free_cb    free_function = NULL;
+static wolfSSL_Realloc_cb realloc_function = NULL;
 
 int wolfSSL_SetAllocators(wolfSSL_Malloc_cb  mf,
@@ -55,22 +91,8 @@
                           wolfSSL_Realloc_cb rf)
 {
-    int res = 0;
-
-    if (mf)
         malloc_function = mf;
-    else
-        res = BAD_FUNC_ARG;
-
-    if (ff)
         free_function = ff;
-    else
-        res = BAD_FUNC_ARG;
-
-    if (rf)
         realloc_function = rf;
-    else
-        res = BAD_FUNC_ARG;
-
-    return res;
+    return 0;
 }
 
@@ -102,10 +124,41 @@
     }
     else {
+    #ifndef WOLFSSL_NO_MALLOC
         res = malloc(size);
-    }
+    #else
+        WOLFSSL_MSG("No malloc available");
+    #endif
+    }
+
+#ifdef WOLFSSL_DEBUG_MEMORY
+#if defined(WOLFSSL_DEBUG_MEMORY_PRINT) && !defined(WOLFSSL_TRACK_MEMORY)
+    printf("Alloc: %p -> %u at %s:%d\n", res, (word32)size, func, line);
+#else
+    (void)func;
+    (void)line;
+#endif
+#endif
 
     #ifdef WOLFSSL_MALLOC_CHECK
         if (res == NULL)
-            puts("wolfSSL_malloc failed");
+        WOLFSSL_MSG("wolfSSL_malloc failed");
+#endif
+
+#ifdef WOLFSSL_FORCE_MALLOC_FAIL_TEST
+    if (res && --gMemFailCount == 0) {
+        printf("\n---FORCED MEM FAIL TEST---\n");
+        if (free_function) {
+        #ifdef WOLFSSL_DEBUG_MEMORY
+            free_function(res, func, line);
+        #else
+            free_function(res);
+        #endif
+        }
+        else {
+            free(res); /* clear */
+        }
+        gMemFailCount = gMemFailCountSeed; /* reset */
+        return NULL;
+    }
     #endif
 
@@ -119,4 +172,13 @@
 #endif
 {
+#ifdef WOLFSSL_DEBUG_MEMORY
+#if defined(WOLFSSL_DEBUG_MEMORY_PRINT) && !defined(WOLFSSL_TRACK_MEMORY)
+    printf("Free: %p at %s:%d\n", ptr, func, line);
+#else
+    (void)func;
+    (void)line;
+#endif
+#endif
+
     if (free_function) {
     #ifdef WOLFSSL_DEBUG_MEMORY
@@ -127,5 +189,9 @@
     }
     else {
+    #ifndef WOLFSSL_NO_MALLOC
         free(ptr);
+    #else
+        WOLFSSL_MSG("No free available");
+    #endif
     }
 }
@@ -147,5 +213,9 @@
     }
     else {
+    #ifndef WOLFSSL_NO_MALLOC
         res = realloc(ptr, size);
+    #else
+        WOLFSSL_MSG("No realloc available");
+    #endif
     }
 
@@ -534,5 +604,9 @@
         #else
         #ifndef WOLFSSL_NO_MALLOC
+            #ifdef FREERTOS
+                res = pvPortMalloc(size);
+            #else
             res = malloc(size);
+            #endif
         #else
             WOLFSSL_MSG("No heap hint found to use and no malloc");
@@ -668,5 +742,9 @@
         #endif
         #ifndef WOLFSSL_NO_MALLOC
+            #ifdef FREERTOS
+                vPortFree(ptr);
+            #else
             free(ptr);
+            #endif
         #else
             WOLFSSL_MSG("Error trying to call free when turned off");
@@ -923,2 +1001,99 @@
 #endif /* HAVE_IO_POOL */
 
+#ifdef WOLFSSL_MEMORY_LOG
+void *xmalloc(size_t n, void* heap, int type, const char* func,
+              const char* file, unsigned int line)
+{
+    void*   p;
+    word32* p32;
+
+    if (malloc_function)
+        p32 = malloc_function(n + sizeof(word32) * 4);
+    else
+        p32 = malloc(n + sizeof(word32) * 4);
+
+    p32[0] = n;
+    p = (void*)(p32 + 4);
+
+    fprintf(stderr, "Alloc: %p -> %u (%d) at %s:%s:%d\n", p, (word32)n, type,
+                                                              func, file, line);
+
+    (void)heap;
+
+    return p;
+}
+void *xrealloc(void *p, size_t n, void* heap, int type, const char* func,
+               const char* file, unsigned int line)
+{
+    void*   newp = NULL;
+    word32* p32;
+    word32* oldp32 = NULL;
+    word32  oldLen;
+
+    if (p != NULL) {
+        oldp32 = (word32*)p;
+        oldp32 -= 4;
+        oldLen = oldp32[0];
+    }
+
+    if (realloc_function)
+        p32 = realloc_function(oldp32, n + sizeof(word32) * 4);
+    else
+        p32 = realloc(oldp32, n + sizeof(word32) * 4);
+
+    if (p32 != NULL) {
+        p32[0] = n;
+        newp = (void*)(p32 + 4);
+
+        fprintf(stderr, "Alloc: %p -> %u (%d) at %s:%s:%d\n", newp, (word32)n,
+                                                        type, func, file, line);
+        if (p != NULL) {
+            fprintf(stderr, "Free: %p -> %u (%d) at %s:%s:%d\n", p, oldLen,
+                                                        type, func, file, line);
+        }
+    }
+
+    (void)heap;
+
+    return newp;
+}
+void xfree(void *p, void* heap, int type, const char* func, const char* file,
+           unsigned int line)
+{
+    word32* p32 = (word32*)p;
+
+    if (p != NULL) {
+        p32 -= 4;
+
+        fprintf(stderr, "Free: %p -> %u (%d) at %s:%s:%d\n", p, p32[0], type,
+                                                              func, file, line);
+
+        if (free_function)
+            free_function(p32);
+        else
+            free(p32);
+    }
+
+    (void)heap;
+}
+#endif /* WOLFSSL_MEMORY_LOG */
+
+#ifdef WOLFSSL_STACK_LOG
+/* Note: this code only works with GCC using -finstrument-functions. */
+void __attribute__((no_instrument_function))
+     __cyg_profile_func_enter(void *func,  void *caller)
+{
+    register void* sp asm("sp");
+    fprintf(stderr, "ENTER: %016lx %p\n", (size_t)func, sp);
+    (void)caller;
+}
+
+void __attribute__((no_instrument_function))
+     __cyg_profile_func_exit(void *func, void *caller)
+{
+    register void* sp asm("sp");
+    fprintf(stderr, "EXIT: %016lx %p\n", (size_t)func, sp);
+    (void)caller;
+}
+#endif
+
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/misc.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/misc.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/misc.c	(revision 372)
@@ -47,5 +47,7 @@
 /* Check for if compiling misc.c when not needed. */
 #if !defined(WOLFSSL_MISC_INCLUDED) && !defined(NO_INLINE)
+    #ifndef WOLFSSL_IGNORE_FILE_WARN
     #warning misc.c does not need to be compiled when using inline (NO_INLINE not defined)
+    #endif
 
 #else
@@ -65,10 +67,10 @@
     #pragma intrinsic(_lrotl, _lrotr)
 
-    STATIC INLINE word32 rotlFixed(word32 x, word32 y)
+    STATIC WC_INLINE word32 rotlFixed(word32 x, word32 y)
     {
         return y ? _lrotl(x, y) : x;
     }
 
-    STATIC INLINE word32 rotrFixed(word32 x, word32 y)
+    STATIC WC_INLINE word32 rotrFixed(word32 x, word32 y)
     {
         return y ? _lrotr(x, y) : x;
@@ -77,5 +79,5 @@
 #else /* generic */
 
-    STATIC INLINE word32 rotlFixed(word32 x, word32 y)
+    STATIC WC_INLINE word32 rotlFixed(word32 x, word32 y)
     {
         return (x << y) | (x >> (sizeof(y) * 8 - y));
@@ -83,5 +85,5 @@
 
 
-    STATIC INLINE word32 rotrFixed(word32 x, word32 y)
+    STATIC WC_INLINE word32 rotrFixed(word32 x, word32 y)
     {
         return (x >> y) | (x << (sizeof(y) * 8 - y));
@@ -91,5 +93,5 @@
 
 
-STATIC INLINE word32 ByteReverseWord32(word32 value)
+STATIC WC_INLINE word32 ByteReverseWord32(word32 value)
 {
 #ifdef PPC_INTRINSICS
@@ -100,4 +102,7 @@
 #elif defined(KEIL_INTRINSICS)
     return (word32)__rev(value);
+#elif defined(WOLF_ALLOW_BUILTIN) && \
+        defined(__GNUC_PREREQ) && __GNUC_PREREQ(4, 3)
+    return (word32)__builtin_bswap32(value);
 #elif defined(FAST_ROTATE)
     /* 5 instructions with rotate instruction, 9 without */
@@ -112,5 +117,5 @@
 
 
-STATIC INLINE void ByteReverseWords(word32* out, const word32* in,
+STATIC WC_INLINE void ByteReverseWords(word32* out, const word32* in,
                                     word32 byteCount)
 {
@@ -123,8 +128,8 @@
 
 
-#ifdef WORD64_AVAILABLE
-
-
-STATIC INLINE word64 rotlFixed64(word64 x, word64 y)
+#if defined(WORD64_AVAILABLE) && !defined(WOLFSSL_NO_WORD64_OPS)
+
+
+STATIC WC_INLINE word64 rotlFixed64(word64 x, word64 y)
 {
     return (x << y) | (x >> (sizeof(y) * 8 - y));
@@ -132,5 +137,5 @@
 
 
-STATIC INLINE word64 rotrFixed64(word64 x, word64 y)
+STATIC WC_INLINE word64 rotrFixed64(word64 x, word64 y)
 {
     return (x >> y) | (x << (sizeof(y) * 8 - y));
@@ -138,9 +143,11 @@
 
 
-STATIC INLINE word64 ByteReverseWord64(word64 value)
-{
-#if defined(WOLFCRYPT_SLOW_WORD64)
-	return (word64)(ByteReverseWord32((word32)value)) << 32 |
-                    ByteReverseWord32((word32)(value>>32));
+STATIC WC_INLINE word64 ByteReverseWord64(word64 value)
+{
+#if defined(WOLF_ALLOW_BUILTIN) && defined(__GNUC_PREREQ) && __GNUC_PREREQ(4, 3)
+    return (word64)__builtin_bswap64(value);
+#elif defined(WOLFCRYPT_SLOW_WORD64)
+	return (word64)((word64)ByteReverseWord32((word32) value)) << 32 |
+                    (word64)ByteReverseWord32((word32)(value   >> 32));
 #else
 	value = ((value & W64LIT(0xFF00FF00FF00FF00)) >> 8) |
@@ -153,5 +160,5 @@
 
 
-STATIC INLINE void ByteReverseWords64(word64* out, const word64* in,
+STATIC WC_INLINE void ByteReverseWords64(word64* out, const word64* in,
                                       word32 byteCount)
 {
@@ -163,8 +170,8 @@
 }
 
-#endif /* WORD64_AVAILABLE */
-
-
-STATIC INLINE void XorWords(wolfssl_word* r, const wolfssl_word* a, word32 n)
+#endif /* WORD64_AVAILABLE && !WOLFSSL_NO_WORD64_OPS */
+
+#ifndef WOLFSSL_NO_XOR_OPS
+STATIC WC_INLINE void XorWords(wolfssl_word* r, const wolfssl_word* a, word32 n)
 {
     word32 i;
@@ -174,5 +181,5 @@
 
 
-STATIC INLINE void xorbuf(void* buf, const void* mask, word32 count)
+STATIC WC_INLINE void xorbuf(void* buf, const void* mask, word32 count)
 {
     if (((wolfssl_word)buf | (wolfssl_word)mask | count) % WOLFSSL_WORD_SIZE == 0)
@@ -187,23 +194,35 @@
     }
 }
-
-
+#endif
+
+#ifndef WOLFSSL_NO_FORCE_ZERO
 /* Make sure compiler doesn't skip */
-STATIC INLINE void ForceZero(const void* mem, word32 len)
+STATIC WC_INLINE void ForceZero(const void* mem, word32 len)
 {
     volatile byte* z = (volatile byte*)mem;
-#ifdef WOLFSSL_X86_64_BUILD
+
+#if defined(WOLFSSL_X86_64_BUILD) && defined(WORD64_AVAILABLE)
     volatile word64* w;
-
+    #ifndef WOLFSSL_UNALIGNED_64BIT_ACCESS
+        word32 l = (sizeof(word64) - ((size_t)z & (sizeof(word64)-1))) &
+                                                             (sizeof(word64)-1);
+
+        if (len < l) l = len;
+        len -= l;
+        while (l--) *z++ = 0;
+    #endif
     for (w = (volatile word64*)z; len >= sizeof(*w); len -= sizeof(*w))
         *w++ = 0;
     z = (volatile byte*)w;
 #endif
+
     while (len--) *z++ = 0;
 }
-
-
+#endif
+
+
+#ifndef WOLFSSL_NO_CONST_CMP
 /* check all length bytes for equality, return 0 on success */
-STATIC INLINE int ConstantCompare(const byte* a, const byte* b, int length)
+STATIC WC_INLINE int ConstantCompare(const byte* a, const byte* b, int length)
 {
     int i;
@@ -216,4 +235,5 @@
     return compareSum;
 }
+#endif
 
 
@@ -223,5 +243,5 @@
         #define min min
     #endif
-    STATIC INLINE word32 min(word32 a, word32 b)
+    STATIC WC_INLINE word32 min(word32 a, word32 b)
     {
         return a > b ? b : a;
@@ -234,5 +254,5 @@
         #define max max
     #endif
-    STATIC INLINE word32 max(word32 a, word32 b)
+    STATIC WC_INLINE word32 max(word32 a, word32 b)
     {
         return a > b ? a : b;
@@ -240,6 +260,7 @@
 #endif /* !WOLFSSL_HAVE_MAX */
 
+#ifndef WOLFSSL_NO_INT_ENCODE
 /* converts a 32 bit integer to 24 bit */
-STATIC INLINE void c32to24(word32 in, word24 out)
+STATIC WC_INLINE void c32to24(word32 in, word24 out)
 {
     out[0] = (in >> 16) & 0xff;
@@ -249,50 +270,110 @@
 
 /* convert 16 bit integer to opaque */
-STATIC INLINE void c16toa(word16 u16, byte* c)
-{
-    c[0] = (u16 >> 8) & 0xff;
-    c[1] =  u16 & 0xff;
+STATIC WC_INLINE void c16toa(word16 wc_u16, byte* c)
+{
+    c[0] = (wc_u16 >> 8) & 0xff;
+    c[1] =  wc_u16 & 0xff;
 }
 
 /* convert 32 bit integer to opaque */
-STATIC INLINE void c32toa(word32 u32, byte* c)
-{
-    c[0] = (u32 >> 24) & 0xff;
-    c[1] = (u32 >> 16) & 0xff;
-    c[2] = (u32 >>  8) & 0xff;
-    c[3] =  u32 & 0xff;
-}
-
+STATIC WC_INLINE void c32toa(word32 wc_u32, byte* c)
+{
+    c[0] = (wc_u32 >> 24) & 0xff;
+    c[1] = (wc_u32 >> 16) & 0xff;
+    c[2] = (wc_u32 >>  8) & 0xff;
+    c[3] =  wc_u32 & 0xff;
+}
+#endif
+
+#ifndef WOLFSSL_NO_INT_DECODE
 /* convert a 24 bit integer into a 32 bit one */
-STATIC INLINE void c24to32(const word24 u24, word32* u32)
-{
-    *u32 = (u24[0] << 16) | (u24[1] << 8) | u24[2];
+STATIC WC_INLINE void c24to32(const word24 wc_u24, word32* wc_u32)
+{
+    *wc_u32 = (wc_u24[0] << 16) | (wc_u24[1] << 8) | wc_u24[2];
 }
 
 
 /* convert opaque to 24 bit integer */
-STATIC INLINE void ato24(const byte* c, word32* u24)
-{
-    *u24 = (c[0] << 16) | (c[1] << 8) | c[2];
+STATIC WC_INLINE void ato24(const byte* c, word32* wc_u24)
+{
+    *wc_u24 = (c[0] << 16) | (c[1] << 8) | c[2];
 }
 
 /* convert opaque to 16 bit integer */
-STATIC INLINE void ato16(const byte* c, word16* u16)
-{
-    *u16 = (word16) ((c[0] << 8) | (c[1]));
+STATIC WC_INLINE void ato16(const byte* c, word16* wc_u16)
+{
+    *wc_u16 = (word16) ((c[0] << 8) | (c[1]));
 }
 
 /* convert opaque to 32 bit integer */
-STATIC INLINE void ato32(const byte* c, word32* u32)
-{
-    *u32 = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
-}
-
-
-STATIC INLINE word32 btoi(byte b)
+STATIC WC_INLINE void ato32(const byte* c, word32* wc_u32)
+{
+    *wc_u32 = ((word32)c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
+}
+
+
+STATIC WC_INLINE word32 btoi(byte b)
 {
     return (word32)(b - 0x30);
 }
-
+#endif
+
+
+#ifndef WOLFSSL_NO_CT_OPS
+/* Constant time - mask set when a > b. */
+STATIC WC_INLINE byte ctMaskGT(int a, int b)
+{
+    return (((word32)a - b - 1) >> 31) - 1;
+}
+
+/* Constant time - mask set when a >= b. */
+STATIC WC_INLINE byte ctMaskGTE(int a, int b)
+{
+    return (((word32)a - b    ) >> 31) - 1;
+}
+
+/* Constant time - mask set when a < b. */
+STATIC WC_INLINE byte ctMaskLT(int a, int b)
+{
+    return (((word32)b - a - 1) >> 31) - 1;
+}
+
+/* Constant time - mask set when a <= b. */
+STATIC WC_INLINE byte ctMaskLTE(int a, int b)
+{
+    return (((word32)b - a    ) >> 31) - 1;
+}
+
+/* Constant time - mask set when a == b. */
+STATIC WC_INLINE byte ctMaskEq(int a, int b)
+{
+    return 0 - (a == b);
+}
+
+/* Constant time - mask set when a != b. */
+STATIC WC_INLINE byte ctMaskNotEq(int a, int b)
+{
+    return 0 - (a != b);
+}
+
+/* Constant time - select a when mask is set and b otherwise. */
+STATIC WC_INLINE byte ctMaskSel(byte m, byte a, byte b)
+{
+    return (b & ((byte)~(word32)m)) | (a & m);
+}
+
+/* Constant time - select integer a when mask is set and integer b otherwise. */
+STATIC WC_INLINE int ctMaskSelInt(byte m, int a, int b)
+{
+    return (b & (~(signed int)(signed char)m)) |
+           (a & ( (signed int)(signed char)m));
+}
+
+/* Constant time - bit set when a <= b. */
+STATIC WC_INLINE byte ctSetLTE(int a, int b)
+{
+    return ((word32)a - b - 1) >> 31;
+}
+#endif
 
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/pwdbased.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/pwdbased.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/pwdbased.c	(revision 372)
@@ -31,9 +31,7 @@
 #include <wolfssl/wolfcrypt/pwdbased.h>
 #include <wolfssl/wolfcrypt/hmac.h>
+#include <wolfssl/wolfcrypt/hash.h>
 #include <wolfssl/wolfcrypt/integer.h>
 #include <wolfssl/wolfcrypt/error-crypt.h>
-#if defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384)
-    #include <wolfssl/wolfcrypt/sha512.h>
-#endif
 
 #ifdef NO_INLINE
@@ -45,118 +43,125 @@
 
 
-#ifndef NO_SHA
-/* PBKDF1 needs at least SHA available */
+/* PKCS#5 v1.5 with non standard extension to optionally derive the extra data (IV) */
+int wc_PBKDF1_ex(byte* key, int keyLen, byte* iv, int ivLen,
+    const byte* passwd, int passwdLen, const byte* salt, int saltLen,
+    int iterations, int hashType, void* heap)
+{
+    int  err;
+    int  keyLeft, ivLeft, i;
+    int  digestLeft, store;
+    int  keyOutput = 0;
+    int  diestLen;
+    byte digest[WC_MAX_DIGEST_SIZE];
+#ifdef WOLFSSL_SMALL_STACK
+    wc_HashAlg* hash = NULL;
+#else
+    wc_HashAlg  hash[1];
+#endif
+    enum wc_HashType hashT;
+
+    (void)heap;
+
+    if (key == NULL || keyLen < 0 || passwdLen < 0 || saltLen < 0 || ivLen < 0){
+        return BAD_FUNC_ARG;
+    }
+
+    if (iterations <= 0)
+        iterations = 1;
+
+    hashT = wc_HashTypeConvert(hashType);
+    err = wc_HashGetDigestSize(hashT);
+    if (err < 0)
+        return err;
+    diestLen = err;
+
+    /* initialize hash */
+#ifdef WOLFSSL_SMALL_STACK
+    hash = (wc_HashAlg*)XMALLOC(sizeof(wc_HashAlg), heap,
+                                DYNAMIC_TYPE_HASHCTX);
+    if (hash == NULL)
+        return MEMORY_E;
+#endif
+
+    err = wc_HashInit(hash, hashT);
+    if (err != 0) {
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(hash, heap, DYNAMIC_TYPE_HASHCTX);
+    #endif
+        return err;
+            }
+
+    keyLeft = keyLen;
+    ivLeft  = ivLen;
+    while (keyOutput < (keyLen + ivLen)) {
+        digestLeft = diestLen;
+        /* D_(i - 1) */
+        if (keyOutput) { /* first time D_0 is empty */
+            err = wc_HashUpdate(hash, hashT, digest, diestLen);
+            if (err != 0) break;
+            }
+
+        /* data */
+        err = wc_HashUpdate(hash, hashT, passwd, passwdLen);
+        if (err != 0) break;
+
+        /* salt */
+        if (salt) {
+            err = wc_HashUpdate(hash, hashT, salt, saltLen);
+            if (err != 0) break;
+    }
+
+        err = wc_HashFinal(hash, hashT, digest);
+        if (err != 0) break;
+
+        /* count */
+    for (i = 1; i < iterations; i++) {
+            err = wc_HashUpdate(hash, hashT, digest, diestLen);
+            if (err != 0) break;
+
+            err = wc_HashFinal(hash, hashT, digest);
+            if (err != 0) break;
+            }
+
+        if (keyLeft) {
+            store = min(keyLeft, diestLen);
+            XMEMCPY(&key[keyLen - keyLeft], digest, store);
+
+            keyOutput  += store;
+            keyLeft    -= store;
+            digestLeft -= store;
+            }
+
+        if (ivLeft && digestLeft) {
+            store = min(ivLeft, digestLeft);
+            if (iv != NULL)
+                XMEMCPY(&iv[ivLen - ivLeft],
+                        &digest[diestLen - digestLeft], store);
+            keyOutput += store;
+            ivLeft    -= store;
+        }
+    }
+
+    wc_HashFree(hash, hashT);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(hash, heap, DYNAMIC_TYPE_HASHCTX);
+#endif
+
+    if (err != 0)
+        return err;
+
+    if (keyOutput != (keyLen + ivLen))
+        return BUFFER_E;
+
+    return err;
+    }
+
+/* PKCS#5 v1.5 */
 int wc_PBKDF1(byte* output, const byte* passwd, int pLen, const byte* salt,
            int sLen, int iterations, int kLen, int hashType)
 {
-    wc_Sha  sha;
-#ifndef NO_MD5
-    wc_Md5  md5;
-#endif
-    int  hLen = (int)WC_SHA_DIGEST_SIZE;
-    int  i, ret = 0;
-    byte buffer[WC_SHA_DIGEST_SIZE];  /* max size */
-
-    if (hashType != WC_MD5 && hashType != WC_SHA)
-        return BAD_FUNC_ARG;
-
-#ifndef NO_MD5
-    if (hashType == WC_MD5)
-        hLen = (int)WC_MD5_DIGEST_SIZE;
-#endif
-
-    if ((kLen > hLen) || (kLen < 0))
-        return BAD_FUNC_ARG;
-
-    if (iterations < 1)
-        return BAD_FUNC_ARG;
-
-    switch (hashType) {
-#ifndef NO_MD5
-        case WC_MD5:
-            ret = wc_InitMd5(&md5);
-            if (ret != 0) {
-                return ret;
-            }
-            ret = wc_Md5Update(&md5, passwd, pLen);
-            if (ret != 0) {
-                return ret;
-            }
-            ret = wc_Md5Update(&md5, salt,   sLen);
-            if (ret != 0) {
-                return ret;
-            }
-            ret = wc_Md5Final(&md5,  buffer);
-            if (ret != 0) {
-                return ret;
-            }
-            break;
-#endif /* NO_MD5 */
-        case WC_SHA:
-        default:
-            ret = wc_InitSha(&sha);
-            if (ret != 0)
-                return ret;
-            wc_ShaUpdate(&sha, passwd, pLen);
-            wc_ShaUpdate(&sha, salt,   sLen);
-            wc_ShaFinal(&sha,  buffer);
-            break;
-    }
-
-    for (i = 1; i < iterations; i++) {
-        if (hashType == WC_SHA) {
-            wc_ShaUpdate(&sha, buffer, hLen);
-            wc_ShaFinal(&sha,  buffer);
-        }
-#ifndef NO_MD5
-        else {
-            ret = wc_Md5Update(&md5, buffer, hLen);
-            if (ret != 0) {
-                return ret;
-            }
-            ret = wc_Md5Final(&md5,  buffer);
-            if (ret != 0) {
-                return ret;
-            }
-        }
-#endif
-    }
-    XMEMCPY(output, buffer, kLen);
-
-    return 0;
-}
-#endif /* NO_SHA */
-
-
-int GetDigestSize(int hashType)
-{
-    int hLen;
-
-    switch (hashType) {
-#ifndef NO_MD5
-        case WC_MD5:
-            hLen = WC_MD5_DIGEST_SIZE;
-            break;
-#endif
-#ifndef NO_SHA
-        case WC_SHA:
-            hLen = WC_SHA_DIGEST_SIZE;
-            break;
-#endif
-#ifndef NO_SHA256
-        case WC_SHA256:
-            hLen = WC_SHA256_DIGEST_SIZE;
-            break;
-#endif
-#ifdef WOLFSSL_SHA512
-        case WC_SHA512:
-            hLen = WC_SHA512_DIGEST_SIZE;
-            break;
-#endif
-        default:
-            return BAD_FUNC_ARG;
-    }
-
-    return hLen;
+    return wc_PBKDF1_ex(output, kLen, NULL, 0,
+        passwd, pLen, salt, sLen, iterations, hashType, NULL);
 }
 
@@ -168,29 +173,43 @@
     int    hLen;
     int    j, ret;
-    Hmac   hmac;
 #ifdef WOLFSSL_SMALL_STACK
     byte*  buffer;
-#else
-    byte   buffer[MAX_DIGEST_SIZE];
-#endif
-
-    hLen = GetDigestSize(hashType);
+    Hmac*  hmac;
+#else
+    byte   buffer[WC_MAX_DIGEST_SIZE];
+    Hmac   hmac[1];
+#endif
+    enum wc_HashType hashT;
+
+    if (output == NULL || pLen < 0 || sLen < 0 || kLen < 0) {
+        return BAD_FUNC_ARG;
+    }
+
+    if (iterations <= 0)
+        iterations = 1;
+
+    hashT = wc_HashTypeConvert(hashType);
+    hLen = wc_HashGetDigestSize(hashT);
     if (hLen < 0)
         return BAD_FUNC_ARG;
 
 #ifdef WOLFSSL_SMALL_STACK
-    buffer = (byte*)XMALLOC(MAX_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    buffer = (byte*)XMALLOC(WC_MAX_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
     if (buffer == NULL)
         return MEMORY_E;
-#endif
-
-    ret = wc_HmacInit(&hmac, NULL, INVALID_DEVID);
+    hmac = (Hmac*)XMALLOC(sizeof(Hmac), NULL, DYNAMIC_TYPE_HMAC);
+    if (buffer == NULL)
+        return MEMORY_E;
+#endif
+
+    ret = wc_HmacInit(hmac, NULL, INVALID_DEVID);
     if (ret == 0) {
-        ret = wc_HmacSetKey(&hmac, hashType, passwd, pLen);
+        /* use int hashType here, since HMAC FIPS uses the old unique value */
+        ret = wc_HmacSetKey(hmac, hashType, passwd, pLen);
 
         while (ret == 0 && kLen) {
             int currentLen;
 
-            ret = wc_HmacUpdate(&hmac, salt, sLen);
+            ret = wc_HmacUpdate(hmac, salt, sLen);
             if (ret != 0)
                 break;
@@ -200,5 +219,5 @@
                 byte b = (byte)(i >> ((3-j) * 8));
 
-                ret = wc_HmacUpdate(&hmac, &b, 1);
+                ret = wc_HmacUpdate(hmac, &b, 1);
                 if (ret != 0)
                     break;
@@ -209,5 +228,5 @@
                 break;
 
-            ret = wc_HmacFinal(&hmac, buffer);
+            ret = wc_HmacFinal(hmac, buffer);
             if (ret != 0)
                 break;
@@ -217,8 +236,8 @@
 
             for (j = 1; j < iterations; j++) {
-                ret = wc_HmacUpdate(&hmac, buffer, hLen);
+                ret = wc_HmacUpdate(hmac, buffer, hLen);
                 if (ret != 0)
                     break;
-                ret = wc_HmacFinal(&hmac, buffer);
+                ret = wc_HmacFinal(hmac, buffer);
                 if (ret != 0)
                     break;
@@ -234,9 +253,10 @@
             i++;
         }
-        wc_HmacFree(&hmac);
+        wc_HmacFree(hmac);
     }
 
 #ifdef WOLFSSL_SMALL_STACK
     XFREE(buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(hmac, NULL, DYNAMIC_TYPE_HMAC);
 #endif
 
@@ -244,181 +264,56 @@
 }
 
-#ifdef WOLFSSL_SHA512
-    #define PBKDF_DIGEST_SIZE WC_SHA512_BLOCK_SIZE
-#elif !defined(NO_SHA256)
-    #define PBKDF_DIGEST_SIZE WC_SHA256_BLOCK_SIZE
-#else
-    #define PBKDF_DIGEST_SIZE WC_SHA_DIGEST_SIZE
-#endif
-
-/* helper for wc_PKCS12_PBKDF(), sets block and digest sizes */
-int GetPKCS12HashSizes(int hashType, word32* v, word32* u)
-{
-    if (!v || !u)
-        return BAD_FUNC_ARG;
-
-    switch (hashType) {
-#ifndef NO_MD5
-        case WC_MD5:
-            *v = WC_MD5_BLOCK_SIZE;
-            *u = WC_MD5_DIGEST_SIZE;
-            break;
-#endif
-#ifndef NO_SHA
-        case WC_SHA:
-            *v = WC_SHA_BLOCK_SIZE;
-            *u = WC_SHA_DIGEST_SIZE;
-            break;
-#endif
-#ifndef NO_SHA256
-        case WC_SHA256:
-            *v = WC_SHA256_BLOCK_SIZE;
-            *u = WC_SHA256_DIGEST_SIZE;
-            break;
-#endif
-#ifdef WOLFSSL_SHA512
-        case WC_SHA512:
-            *v = WC_SHA512_BLOCK_SIZE;
-            *u = WC_SHA512_DIGEST_SIZE;
-            break;
-#endif
-        default:
-            return BAD_FUNC_ARG;
-    }
-
-    return 0;
-}
-
 /* helper for PKCS12_PBKDF(), does hash operation */
-int DoPKCS12Hash(int hashType, byte* buffer, word32 totalLen,
+static int DoPKCS12Hash(int hashType, byte* buffer, word32 totalLen,
                  byte* Ai, word32 u, int iterations)
 {
     int i;
     int ret = 0;
-
-    if (buffer == NULL || Ai == NULL)
+#ifdef WOLFSSL_SMALL_STACK
+    wc_HashAlg* hash = NULL;
+#else
+    wc_HashAlg  hash[1];
+#endif
+    enum wc_HashType hashT;
+
+    if (buffer == NULL || Ai == NULL) {
         return BAD_FUNC_ARG;
-
-    switch (hashType) {
-#ifndef NO_MD5
-        case WC_MD5:
-            {
-                wc_Md5 md5;
-                ret = wc_InitMd5(&md5);
-                if (ret != 0) {
-                    break;
                 }
-                ret = wc_Md5Update(&md5, buffer, totalLen);
-                if (ret != 0) {
-                    break;
+
+    hashT = wc_HashTypeConvert(hashType);
+
+    /* initialize hash */
+#ifdef WOLFSSL_SMALL_STACK
+    hash = (wc_HashAlg*)XMALLOC(sizeof(wc_HashAlg), NULL,
+                                DYNAMIC_TYPE_HASHCTX);
+    if (hash == NULL)
+        return MEMORY_E;
+#endif
+
+    ret = wc_HashInit(hash, hashT);
+                    if (ret != 0) {
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(hash, NULL, DYNAMIC_TYPE_HASHCTX);
+    #endif
+        return ret;
+            }
+
+    ret = wc_HashUpdate(hash, hashT, buffer, totalLen);
+
+    if (ret == 0)
+        ret = wc_HashFinal(hash, hashT, Ai);
+
+                for (i = 1; i < iterations; i++) {
+        if (ret == 0)
+            ret = wc_HashUpdate(hash, hashT, Ai, u);
+        if (ret == 0)
+            ret = wc_HashFinal(hash, hashT, Ai);
                 }
-                ret = wc_Md5Final(&md5, Ai);
-                if (ret != 0) {
-                    break;
-                }
-
-                for (i = 1; i < iterations; i++) {
-                    ret = wc_Md5Update(&md5, Ai, u);
-                    if (ret != 0) {
-                        break;
-                    }
-                    ret = wc_Md5Final(&md5, Ai);
-                    if (ret != 0) {
-                        break;
-                    }
-                }
-            }
-            break;
-#endif /* NO_MD5 */
-#ifndef NO_SHA
-        case WC_SHA:
-            {
-                wc_Sha sha;
-                ret = wc_InitSha(&sha);
-                if (ret != 0)
-                    break;
-                ret = wc_ShaUpdate(&sha, buffer, totalLen);
-                if (ret != 0) {
-                    break;
-                }
-                ret = wc_ShaFinal(&sha, Ai);
-                if (ret != 0) {
-                    break;
-                }
-
-                for (i = 1; i < iterations; i++) {
-                    ret = wc_ShaUpdate(&sha, Ai, u);
-                    if (ret != 0) {
-                        break;
-                    }
-                    ret = wc_ShaFinal(&sha, Ai);
-                    if (ret != 0) {
-                        break;
-                    }
-                }
-            }
-            break;
-#endif /* NO_SHA */
-#ifndef NO_SHA256
-        case WC_SHA256:
-            {
-                wc_Sha256 sha256;
-                ret = wc_InitSha256(&sha256);
-                if (ret != 0)
-                    break;
-
-                ret = wc_Sha256Update(&sha256, buffer, totalLen);
-                if (ret != 0)
-                    break;
-
-                ret = wc_Sha256Final(&sha256, Ai);
-                if (ret != 0)
-                    break;
-
-                for (i = 1; i < iterations; i++) {
-                    ret = wc_Sha256Update(&sha256, Ai, u);
-                    if (ret != 0)
-                        break;
-
-                    ret = wc_Sha256Final(&sha256, Ai);
-                    if (ret != 0)
-                        break;
-                }
-            }
-            break;
-#endif /* NO_SHA256 */
-#ifdef WOLFSSL_SHA512
-        case WC_SHA512:
-            {
-                wc_Sha512 sha512;
-                ret = wc_InitSha512(&sha512);
-                if (ret != 0)
-                    break;
-
-                ret = wc_Sha512Update(&sha512, buffer, totalLen);
-                if (ret != 0)
-                    break;
-
-                ret = wc_Sha512Final(&sha512, Ai);
-                if (ret != 0)
-                    break;
-
-                for (i = 1; i < iterations; i++) {
-                    ret = wc_Sha512Update(&sha512, Ai, u);
-                    if (ret != 0)
-                        break;
-
-                    ret = wc_Sha512Final(&sha512, Ai);
-                    if (ret != 0)
-                        break;
-                }
-            }
-            break;
-#endif /* WOLFSSL_SHA512 */
-
-        default:
-            ret = BAD_FUNC_ARG;
-            break;
-    }
+
+    wc_HashFree(hash, hashT);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(hash, NULL, DYNAMIC_TYPE_HASHCTX);
+#endif
 
     return ret;
@@ -426,6 +321,7 @@
 
 
-int wc_PKCS12_PBKDF(byte* output, const byte* passwd, int passLen,const byte* salt,
-                 int saltLen, int iterations, int kLen, int hashType, int id)
+int wc_PKCS12_PBKDF(byte* output, const byte* passwd, int passLen,
+    const byte* salt, int saltLen, int iterations, int kLen, int hashType,
+    int id)
 {
     return wc_PKCS12_PBKDF_ex(output, passwd, passLen, salt, saltLen,
@@ -456,29 +352,43 @@
     byte*  B;
 #else
-    byte   Ai[PBKDF_DIGEST_SIZE];
-    byte   B[PBKDF_DIGEST_SIZE];
-#endif
-
-    if (!iterations)
+    byte   Ai[WC_MAX_DIGEST_SIZE];
+    byte   B[WC_MAX_BLOCK_SIZE];
+#endif
+    enum wc_HashType hashT;
+
+    (void)heap;
+
+    if (output == NULL || passLen < 0 || saltLen < 0 || kLen < 0) {
+        return BAD_FUNC_ARG;
+    }
+
+    if (iterations <= 0)
         iterations = 1;
 
-    ret = GetPKCS12HashSizes(hashType, &v, &u);
+    hashT = wc_HashTypeConvert(hashType);
+    ret = wc_HashGetDigestSize(hashT);
     if (ret < 0)
-        return BAD_FUNC_ARG;
-
-#ifdef WOLFSSL_SMALL_STACK
-    Ai = (byte*)XMALLOC(PBKDF_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return ret;
+    u = ret;
+
+    ret = wc_HashGetBlockSize(hashT);
+    if (ret < 0)
+        return ret;
+    v = ret;
+
+#ifdef WOLFSSL_SMALL_STACK
+    Ai = (byte*)XMALLOC(WC_MAX_DIGEST_SIZE, heap, DYNAMIC_TYPE_TMP_BUFFER);
     if (Ai == NULL)
         return MEMORY_E;
 
-    B = (byte*)XMALLOC(PBKDF_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    B = (byte*)XMALLOC(WC_MAX_BLOCK_SIZE, heap, DYNAMIC_TYPE_TMP_BUFFER);
     if (B == NULL) {
-        XFREE(Ai, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(Ai, heap, DYNAMIC_TYPE_TMP_BUFFER);
         return MEMORY_E;
     }
 #endif
 
-    XMEMSET(Ai, 0, PBKDF_DIGEST_SIZE);
-    XMEMSET(B,  0, PBKDF_DIGEST_SIZE);
+    XMEMSET(Ai, 0, WC_MAX_DIGEST_SIZE);
+    XMEMSET(B,  0, WC_MAX_BLOCK_SIZE);
 
     dLen = v;
@@ -496,6 +406,6 @@
         if (buffer == NULL) {
 #ifdef WOLFSSL_SMALL_STACK
-            XFREE(Ai, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-            XFREE(B,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(Ai, heap, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(B,  heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
             return MEMORY_E;
@@ -584,6 +494,6 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    XFREE(Ai, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-    XFREE(B,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(Ai, heap, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(B,  heap, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
 
@@ -740,5 +650,5 @@
 #else
         byte* t = x + (2*r - 1) * 64;
-        j = (t[0] | (t[1] << 8) | (t[2] << 16) | (t[3] << 24)) & (n-1);
+        j = (t[0] | (t[1] << 8) | (t[2] << 16) | ((word32)t[3] << 24)) & (n-1);
 #endif
 #ifdef WORD64_AVAILABLE
@@ -828,5 +738,5 @@
 #endif
 
-#undef PBKDF_DIGEST_SIZE
+#undef WC_MAX_DIGEST_SIZE
 
 #endif /* NO_PWDBASED */
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/rabbit.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/rabbit.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/rabbit.c	(revision 372)
@@ -146,5 +146,5 @@
 
 /* Key setup */
-static INLINE int DoKey(Rabbit* ctx, const byte* key, const byte* iv)
+static WC_INLINE int DoKey(Rabbit* ctx, const byte* key, const byte* iv)
 {
     /* Temporary variables */
@@ -248,5 +248,5 @@
 
 /* Encrypt/decrypt a message of any size */
-static INLINE int DoProcess(Rabbit* ctx, byte* output, const byte* input,
+static WC_INLINE int DoProcess(Rabbit* ctx, byte* output, const byte* input,
                             word32 msglen)
 {
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/random.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/random.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/random.c	(revision 372)
@@ -26,4 +26,5 @@
 
 #include <wolfssl/wolfcrypt/settings.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
 
 /* on HPUX 11 you may need to install /dev/random see
@@ -32,9 +33,25 @@
 */
 
+#if defined(HAVE_FIPS) && \
+	defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+
+    /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+    #define FIPS_NO_WRAPPERS
+
+    #ifdef USE_WINDOWS_API
+        #pragma code_seg(".fipsA$c")
+        #pragma const_seg(".fipsB$c")
+    #endif
+#endif
+
+
 #include <wolfssl/wolfcrypt/random.h>
 #include <wolfssl/wolfcrypt/cpuid.h>
 
 
-#ifdef HAVE_FIPS
+/* If building for old FIPS. */
+#if defined(HAVE_FIPS) && \
+    (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))
+
 int wc_GenerateSeed(OS_Seed* os, byte* seed, word32 sz)
 {
@@ -73,19 +90,17 @@
     }
 
-    int wc_RNG_HealthTest(int reseed,
-                                        const byte* entropyA, word32 entropyASz,
-                                        const byte* entropyB, word32 entropyBSz,
+    int wc_RNG_HealthTest(int reseed, const byte* seedA, word32 seedASz,
+                                      const byte* seedB, word32 seedBSz,
                                         byte* output, word32 outputSz)
     {
-        return RNG_HealthTest_fips(reseed, entropyA, entropyASz,
-                              entropyB, entropyBSz, output, outputSz);
+        return RNG_HealthTest_fips(reseed, seedA, seedASz,
+                              seedB, seedBSz, output, outputSz);
     }
 #endif /* HAVE_HASHDRBG */
 
-#else /* else build without fips */
+#else /* else build without fips, or for new fips */
 
 #ifndef WC_NO_RNG /* if not FIPS and RNG is disabled then do not compile */
 
-#include <wolfssl/wolfcrypt/error-crypt.h>
 #include <wolfssl/wolfcrypt/sha256.h>
 
@@ -127,4 +142,6 @@
 #elif defined(WOLFSSL_EMBOS)
 #elif defined(MICRIUM)
+#elif defined(WOLFSSL_NUCLEUS)
+#elif defined(WOLFSSL_PB)
 #else
     /* include headers that may be needed to get good seed */
@@ -148,4 +165,8 @@
     static int wc_GenerateRand_IntelRD(OS_Seed* os, byte* output, word32 sz);
     #endif
+
+#ifdef USE_WINDOWS_API
+    #include <immintrin.h>
+#endif /* USE_WINDOWS_API */
 #endif
 
@@ -156,15 +177,72 @@
 #define MAX_REQUEST_LEN   (0x10000)
 #define RESEED_INTERVAL   WC_RESEED_INTERVAL
-#define SECURITY_STRENGTH (256)
-#define ENTROPY_SZ        (SECURITY_STRENGTH/8)
-#define NONCE_SZ          (ENTROPY_SZ/2)
-#define ENTROPY_NONCE_SZ  (ENTROPY_SZ+NONCE_SZ)
+
+
+/* For FIPS builds, the user should not be adjusting the values. */
+#if defined(HAVE_FIPS) && \
+    defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+    #if defined(RNG_SECURITY_STRENGTH) \
+            || defined(ENTROPY_SCALE_FACTOR) \
+            || defined(SEED_BLOCK_SZ)
+
+        #error "Do not change the RNG parameters for FIPS builds."
+    #endif
+#endif
+
+
+/* The security strength for the RNG is the target number of bits of
+ * entropy you are looking for in a seed. */
+#ifndef RNG_SECURITY_STRENGTH
+    #if defined(HAVE_FIPS) && \
+	    defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+        /* SHA-256 requires a minimum of 256-bits of entropy. The goal
+         * of 1024 will provide 4 times that. */
+        #define RNG_SECURITY_STRENGTH (1024)
+    #else
+        /* If not using FIPS or using old FIPS, set the number down a bit.
+         * More is better, but more is also slower. */
+        #define RNG_SECURITY_STRENGTH (256)
+    #endif
+#endif
+
+#ifndef ENTROPY_SCALE_FACTOR
+    /* The entropy scale factor should be the whole number inverse of the
+     * minimum bits of entropy per bit of NDRNG output. */
+    #if defined(HAVE_INTEL_RDSEED) || defined(HAVE_INTEL_RDRAND)
+        /* The value of 2 applies to Intel's RDSEED which provides about
+         * 0.5 bits minimum of entropy per bit. */
+        #define ENTROPY_SCALE_FACTOR 2
+    #else
+        /* Setting the default to 1. */
+        #define ENTROPY_SCALE_FACTOR 1
+    #endif
+#endif
+
+#ifndef SEED_BLOCK_SZ
+    /* The seed block size, is the size of the output of the underlying NDRNG.
+     * This value is used for testing the output of the NDRNG. */
+    #if defined(HAVE_INTEL_RDSEED) || defined(HAVE_INTEL_RDRAND)
+        /* RDSEED outputs in blocks of 64-bits. */
+        #define SEED_BLOCK_SZ sizeof(word64)
+    #else
+        /* Setting the default to 4. */
+        #define SEED_BLOCK_SZ 4
+    #endif
+#endif
+
+#define SEED_SZ        (RNG_SECURITY_STRENGTH*ENTROPY_SCALE_FACTOR/8)
+
+/* The maximum seed size will be the seed size plus a seed block for the
+ * test, and an additional half of the seed size. This additional half
+ * is in case the user does not supply a nonce. A nonce will be obtained
+ * from the NDRNG. */
+#define MAX_SEED_SZ    (SEED_SZ + SEED_SZ/2 + SEED_BLOCK_SZ)
+
 
 /* Internal return codes */
 #define DRBG_SUCCESS      0
-#define DRBG_ERROR        1
-#define DRBG_FAILURE      2
-#define DRBG_NEED_RESEED  3
-#define DRBG_CONT_FAILURE 4
+#define DRBG_FAILURE      1
+#define DRBG_NEED_RESEED  2
+#define DRBG_CONT_FAILURE 3
 
 /* RNG health states */
@@ -200,4 +278,7 @@
 #endif
     byte   matchCount;
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+    wc_Sha256 sha256;
+#endif
 } DRBG;
 
@@ -216,9 +297,17 @@
     int len;
     word32 bits = (outSz * 8); /* reverse byte order */
-    wc_Sha256 sha;
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+    wc_Sha256* sha = &drbg->sha256;
+#else
+    wc_Sha256 sha[1];
+#endif
+#ifdef WC_ASYNC_ENABLE_SHA256
     DECLARE_VAR(digest, byte, WC_SHA256_DIGEST_SIZE, drbg->heap);
+#else
+    byte digest[WC_SHA256_DIGEST_SIZE];
+#endif
 
     (void)drbg;
-#ifdef WOLFSSL_ASYNC_CRYPT
+#ifdef WC_ASYNC_ENABLE_SHA256
     if (digest == NULL)
         return DRBG_FAILURE;
@@ -232,8 +321,9 @@
 
     for (i = 0, ctr = 1; i < len; i++, ctr++) {
+#ifndef WOLFSSL_SMALL_STACK_CACHE
     #ifdef WOLFSSL_ASYNC_CRYPT
-        ret = wc_InitSha256_ex(&sha, drbg->heap, drbg->devId);
+        ret = wc_InitSha256_ex(sha, drbg->heap, drbg->devId);
     #else
-        ret = wc_InitSha256(&sha);
+        ret = wc_InitSha256(sha);
     #endif
         if (ret != 0)
@@ -241,23 +331,26 @@
 
         if (ret == 0)
-            ret = wc_Sha256Update(&sha, &ctr, sizeof(ctr));
+#endif
+            ret = wc_Sha256Update(sha, &ctr, sizeof(ctr));
         if (ret == 0)
-            ret = wc_Sha256Update(&sha, (byte*)&bits, sizeof(bits));
+            ret = wc_Sha256Update(sha, (byte*)&bits, sizeof(bits));
 
         if (ret == 0) {
             /* churning V is the only string that doesn't have the type added */
             if (type != drbgInitV)
-                ret = wc_Sha256Update(&sha, &type, sizeof(type));
+                ret = wc_Sha256Update(sha, &type, sizeof(type));
         }
         if (ret == 0)
-            ret = wc_Sha256Update(&sha, inA, inASz);
+            ret = wc_Sha256Update(sha, inA, inASz);
         if (ret == 0) {
             if (inB != NULL && inBSz > 0)
-                ret = wc_Sha256Update(&sha, inB, inBSz);
+                ret = wc_Sha256Update(sha, inB, inBSz);
         }
         if (ret == 0)
-            ret = wc_Sha256Final(&sha, digest);
-
-        wc_Sha256Free(&sha);
+            ret = wc_Sha256Final(sha, digest);
+
+#ifndef WOLFSSL_SMALL_STACK_CACHE
+        wc_Sha256Free(sha);
+#endif
         if (ret == 0) {
             if (outSz > OUTPUT_BLOCK_LEN) {
@@ -274,5 +367,7 @@
     ForceZero(digest, WC_SHA256_DIGEST_SIZE);
 
+#ifdef WC_ASYNC_ENABLE_SHA256
     FREE_VAR(digest, drbg->heap);
+#endif
 
     return (ret == 0) ? DRBG_SUCCESS : DRBG_FAILURE;
@@ -280,15 +375,17 @@
 
 /* Returns: DRBG_SUCCESS or DRBG_FAILURE */
-static int Hash_DRBG_Reseed(DRBG* drbg, const byte* entropy, word32 entropySz)
-{
-    byte seed[DRBG_SEED_LEN];
-
-    if (Hash_df(drbg, seed, sizeof(seed), drbgReseed, drbg->V, sizeof(drbg->V),
-                                          entropy, entropySz) != DRBG_SUCCESS) {
+static int Hash_DRBG_Reseed(DRBG* drbg, const byte* seed, word32 seedSz)
+{
+    byte newV[DRBG_SEED_LEN];
+
+    XMEMSET(newV, 0, DRBG_SEED_LEN);
+
+    if (Hash_df(drbg, newV, sizeof(newV), drbgReseed,
+                drbg->V, sizeof(drbg->V), seed, seedSz) != DRBG_SUCCESS) {
         return DRBG_FAILURE;
     }
 
-    XMEMCPY(drbg->V, seed, sizeof(drbg->V));
-    ForceZero(seed, sizeof(seed));
+    XMEMCPY(drbg->V, newV, sizeof(drbg->V));
+    ForceZero(newV, sizeof(newV));
 
     if (Hash_df(drbg, drbg->C, sizeof(drbg->C), drbgInitC, drbg->V,
@@ -303,5 +400,15 @@
 }
 
-static INLINE void array_add_one(byte* data, word32 dataSz)
+/* Returns: DRBG_SUCCESS and DRBG_FAILURE or BAD_FUNC_ARG on fail */
+int wc_RNG_DRBG_Reseed(WC_RNG* rng, const byte* seed, word32 seedSz)
+{
+    if (rng == NULL || seed == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    return Hash_DRBG_Reseed(rng->drbg, seed, seedSz);
+}
+
+static WC_INLINE void array_add_one(byte* data, word32 dataSz)
 {
     int i;
@@ -322,6 +429,14 @@
     int len;
     word32 checkBlock;
-    wc_Sha256 sha;
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+    wc_Sha256* sha = &drbg->sha256;
+#else
+    wc_Sha256 sha[1];
+#endif
+#ifdef WC_ASYNC_ENABLE_SHA256
     DECLARE_VAR(digest, byte, WC_SHA256_DIGEST_SIZE, drbg->heap);
+#else
+    byte digest[WC_SHA256_DIGEST_SIZE];
+#endif
 
     /* Special case: outSz is 0 and out is NULL. wc_Generate a block to save for
@@ -334,14 +449,18 @@
     XMEMCPY(data, V, sizeof(data));
     for (i = 0; i < len; i++) {
+#ifndef WOLFSSL_SMALL_STACK_CACHE
     #ifdef WOLFSSL_ASYNC_CRYPT
-        ret = wc_InitSha256_ex(&sha, drbg->heap, drbg->devId);
+        ret = wc_InitSha256_ex(sha, drbg->heap, drbg->devId);
     #else
-        ret = wc_InitSha256(&sha);
+        ret = wc_InitSha256(sha);
     #endif
         if (ret == 0)
-            ret = wc_Sha256Update(&sha, data, sizeof(data));
+#endif
+            ret = wc_Sha256Update(sha, data, sizeof(data));
         if (ret == 0)
-            ret = wc_Sha256Final(&sha, digest);
-        wc_Sha256Free(&sha);
+            ret = wc_Sha256Final(sha, digest);
+#ifndef WOLFSSL_SMALL_STACK_CACHE
+        wc_Sha256Free(sha);
+#endif
 
         if (ret == 0) {
@@ -379,10 +498,12 @@
     ForceZero(data, sizeof(data));
 
+#ifdef WC_ASYNC_ENABLE_SHA256
     FREE_VAR(digest, drbg->heap);
+#endif
 
     return (ret == 0) ? DRBG_SUCCESS : DRBG_FAILURE;
 }
 
-static INLINE void array_add(byte* d, word32 dLen, const byte* s, word32 sLen)
+static WC_INLINE void array_add(byte* d, word32 dLen, const byte* s, word32 sLen)
 {
     word16 carry = 0;
@@ -410,5 +531,9 @@
 {
     int ret;
-    wc_Sha256 sha;
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+    wc_Sha256* sha = &drbg->sha256;
+#else
+    wc_Sha256 sha[1];
+#endif
     byte type;
     word32 reseedCtr;
@@ -417,5 +542,9 @@
         return DRBG_NEED_RESEED;
     } else {
+    #ifdef WC_ASYNC_ENABLE_SHA256
         DECLARE_VAR(digest, byte, WC_SHA256_DIGEST_SIZE, drbg->heap);
+    #else
+        byte digest[WC_SHA256_DIGEST_SIZE];
+    #endif
         type = drbgGenerateH;
         reseedCtr = drbg->reseedCtr;
@@ -423,17 +552,21 @@
         ret = Hash_gen(drbg, out, outSz, drbg->V);
         if (ret == DRBG_SUCCESS) {
+#ifndef WOLFSSL_SMALL_STACK_CACHE
         #ifdef WOLFSSL_ASYNC_CRYPT
-            ret = wc_InitSha256_ex(&sha, drbg->heap, drbg->devId);
+            ret = wc_InitSha256_ex(sha, drbg->heap, drbg->devId);
         #else
-            ret = wc_InitSha256(&sha);
+            ret = wc_InitSha256(sha);
         #endif
             if (ret == 0)
-                ret = wc_Sha256Update(&sha, &type, sizeof(type));
+#endif
+                ret = wc_Sha256Update(sha, &type, sizeof(type));
             if (ret == 0)
-                ret = wc_Sha256Update(&sha, drbg->V, sizeof(drbg->V));
+                ret = wc_Sha256Update(sha, drbg->V, sizeof(drbg->V));
             if (ret == 0)
-                ret = wc_Sha256Final(&sha, digest);
-
-            wc_Sha256Free(&sha);
+                ret = wc_Sha256Final(sha, digest);
+
+#ifndef WOLFSSL_SMALL_STACK_CACHE
+            wc_Sha256Free(sha);
+#endif
 
             if (ret == 0) {
@@ -450,5 +583,7 @@
         }
         ForceZero(digest, WC_SHA256_DIGEST_SIZE);
+    #ifdef WC_ASYNC_ENABLE_SHA256
         FREE_VAR(digest, drbg->heap);
+    #endif
     }
 
@@ -472,4 +607,14 @@
 #endif
 
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+    #ifdef WOLFSSL_ASYNC_CRYPT
+        ret = wc_InitSha256_ex(&drbg->sha256, drbg->heap, drbg->devId);
+    #else
+        ret = wc_InitSha256(&drbg->sha256);
+    #endif
+    if (ret != 0)
+        return ret;
+#endif
+
     if (Hash_df(drbg, drbg->V, sizeof(drbg->V), drbgInitV, seed, seedSz,
                                               nonce, nonceSz) == DRBG_SUCCESS &&
@@ -493,4 +638,8 @@
     byte*  compareDrbg = (byte*)drbg;
 
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+    wc_Sha256Free(&drbg->sha256);
+#endif
+
     ForceZero(drbg, sizeof(DRBG));
 
@@ -500,13 +649,45 @@
     return (compareSum == 0) ? DRBG_SUCCESS : DRBG_FAILURE;
 }
+
+
+int wc_RNG_TestSeed(const byte* seed, word32 seedSz)
+{
+    int ret = DRBG_SUCCESS;
+
+    /* Check the seed for duplicate words. */
+    word32 seedIdx = 0;
+    word32 scratchSz = min(SEED_BLOCK_SZ, seedSz - SEED_BLOCK_SZ);
+
+    while (seedIdx < seedSz - SEED_BLOCK_SZ) {
+        if (ConstantCompare(seed + seedIdx,
+                            seed + seedIdx + scratchSz,
+                            scratchSz) == 0) {
+
+            ret = DRBG_CONT_FAILURE;
+        }
+        seedIdx += SEED_BLOCK_SZ;
+        scratchSz = min(SEED_BLOCK_SZ, (seedSz - seedIdx));
+    }
+
+    return ret;
+}
 #endif /* HAVE_HASHDRBG */
 /* End NIST DRBG Code */
 
 
-int wc_InitRng_ex(WC_RNG* rng, void* heap, int devId)
+static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz,
+                    void* heap, int devId)
 {
     int ret = RNG_FAILURE_E;
+#ifdef HAVE_HASHDRBG
+    word32 seedSz = SEED_SZ + SEED_BLOCK_SZ;
+#endif
+
+    (void)nonce;
+    (void)nonceSz;
 
     if (rng == NULL)
+        return BAD_FUNC_ARG;
+    if (nonce == NULL && nonceSz != 0)
         return BAD_FUNC_ARG;
 
@@ -552,6 +733,13 @@
 #else
 #ifdef HAVE_HASHDRBG
+    if (nonceSz == 0)
+        seedSz = MAX_SEED_SZ;
+
     if (wc_RNG_HealthTestLocal(0) == 0) {
-        DECLARE_VAR(entropy, byte, ENTROPY_NONCE_SZ, rng->heap);
+    #ifdef WC_ASYNC_ENABLE_SHA256
+        DECLARE_VAR(seed, byte, MAX_SEED_SZ, rng->heap);
+    #else
+        byte seed[MAX_SEED_SZ];
+    #endif
 
         rng->drbg =
@@ -561,17 +749,24 @@
             ret = MEMORY_E;
         }
-        /* This doesn't use a separate nonce. The entropy input will be
-         * the default size plus the size of the nonce making the seed
-         * size. */
-        else if (wc_GenerateSeed(&rng->seed, entropy, ENTROPY_NONCE_SZ) == 0 &&
-                 Hash_DRBG_Instantiate(rng->drbg, entropy, ENTROPY_NONCE_SZ,
-                                   NULL, 0, rng->heap, devId) == DRBG_SUCCESS) {
+        else {
+            ret = wc_GenerateSeed(&rng->seed, seed, seedSz);
+            if (ret != 0)
+                ret = DRBG_FAILURE;
+            else
+                ret = wc_RNG_TestSeed(seed, seedSz);
+
+            if (ret == DRBG_SUCCESS)
+                 ret = Hash_DRBG_Instantiate(rng->drbg,
+                            seed + SEED_BLOCK_SZ, seedSz - SEED_BLOCK_SZ,
+                            nonce, nonceSz, rng->heap, devId);
+
+            if (ret == DRBG_SUCCESS)
             ret = Hash_DRBG_Generate(rng->drbg, NULL, 0);
         }
-        else
-            ret = DRBG_FAILURE;
-
-        ForceZero(entropy, ENTROPY_NONCE_SZ);
-        FREE_VAR(entropy, rng->heap);
+
+        ForceZero(seed, seedSz);
+    #ifdef WC_ASYNC_ENABLE_SHA256
+        FREE_VAR(seed, rng->heap);
+    #endif
     }
     else
@@ -599,7 +794,27 @@
 }
 
+
 int wc_InitRng(WC_RNG* rng)
 {
-    return wc_InitRng_ex(rng, NULL, INVALID_DEVID);
+    return _InitRng(rng, NULL, 0, NULL, INVALID_DEVID);
+}
+
+
+int wc_InitRng_ex(WC_RNG* rng, void* heap, int devId)
+{
+    return _InitRng(rng, NULL, 0, heap, devId);
+}
+
+
+int wc_InitRngNonce(WC_RNG* rng, byte* nonce, word32 nonceSz)
+{
+    return _InitRng(rng, nonce, nonceSz, NULL, INVALID_DEVID);
+}
+
+
+int wc_InitRngNonce_ex(WC_RNG* rng, byte* nonce, word32 nonceSz,
+                       void* heap, int devId)
+{
+    return _InitRng(rng, nonce, nonceSz, heap, devId);
 }
 
@@ -623,5 +838,5 @@
     #ifdef HAVE_CAVIUM
         return NitroxRngGenerateBlock(rng, output, sz);
-    #elif defined(HAVE_INTEL_QA)
+    #elif defined(HAVE_INTEL_QA) && defined(QAT_ENABLE_RNG)
         return IntelQaDrbg(&rng->asyncDev, output, sz);
     #else
@@ -646,18 +861,22 @@
     if (ret == DRBG_NEED_RESEED) {
         if (wc_RNG_HealthTestLocal(1) == 0) {
-            byte entropy[ENTROPY_SZ];
-
-            if (wc_GenerateSeed(&rng->seed, entropy, ENTROPY_SZ) == 0 &&
-                Hash_DRBG_Reseed(rng->drbg, entropy, ENTROPY_SZ)
-                                                              == DRBG_SUCCESS) {
-
+            byte newSeed[SEED_SZ + SEED_BLOCK_SZ];
+
+            ret = wc_GenerateSeed(&rng->seed, newSeed,
+                                  SEED_SZ + SEED_BLOCK_SZ);
+            if (ret != 0)
+                ret = DRBG_FAILURE;
+            else
+                ret = wc_RNG_TestSeed(newSeed, SEED_SZ + SEED_BLOCK_SZ);
+
+            if (ret == DRBG_SUCCESS)
+                ret = Hash_DRBG_Reseed(rng->drbg, newSeed + SEED_BLOCK_SZ,
+                                       SEED_SZ);
+            if (ret == DRBG_SUCCESS)
                 ret = Hash_DRBG_Generate(rng->drbg, NULL, 0);
                 if (ret == DRBG_SUCCESS)
                     ret = Hash_DRBG_Generate(rng->drbg, output, sz);
-            }
-            else
-                ret = DRBG_FAILURE;
-
-            ForceZero(entropy, ENTROPY_SZ);
+
+            ForceZero(newSeed, sizeof(newSeed));
         }
         else
@@ -721,7 +940,20 @@
 
 #ifdef HAVE_HASHDRBG
-int wc_RNG_HealthTest(int reseed, const byte* entropyA, word32 entropyASz,
-                                  const byte* entropyB, word32 entropyBSz,
+int wc_RNG_HealthTest(int reseed, const byte* seedA, word32 seedASz,
+                                  const byte* seedB, word32 seedBSz,
                                   byte* output, word32 outputSz)
+{
+    return wc_RNG_HealthTest_ex(reseed, NULL, 0,
+                                seedA, seedASz, seedB, seedBSz,
+                                output, outputSz,
+                                NULL, INVALID_DEVID);
+}
+
+
+int wc_RNG_HealthTest_ex(int reseed, const byte* nonce, word32 nonceSz,
+                                  const byte* seedA, word32 seedASz,
+                                  const byte* seedB, word32 seedBSz,
+                                  byte* output, word32 outputSz,
+                                  void* heap, int devId)
 {
     int ret = -1;
@@ -731,9 +963,9 @@
 #endif
 
-    if (entropyA == NULL || output == NULL) {
+    if (seedA == NULL || output == NULL) {
         return BAD_FUNC_ARG;
     }
 
-    if (reseed != 0 && entropyB == NULL) {
+    if (reseed != 0 && seedB == NULL) {
         return BAD_FUNC_ARG;
     }
@@ -744,5 +976,5 @@
 
 #ifdef WOLFSSL_SMALL_STACK
-    drbg = (struct DRBG*)XMALLOC(sizeof(DRBG), NULL, DYNAMIC_TYPE_RNG);
+    drbg = (DRBG*)XMALLOC(sizeof(DRBG), NULL, DYNAMIC_TYPE_RNG);
     if (drbg == NULL) {
         return MEMORY_E;
@@ -752,11 +984,11 @@
 #endif
 
-    if (Hash_DRBG_Instantiate(drbg, entropyA, entropyASz, NULL, 0, NULL,
-                                                    INVALID_DEVID) != 0) {
+    if (Hash_DRBG_Instantiate(drbg, seedA, seedASz, nonce, nonceSz,
+                              heap, devId) != 0) {
         goto exit_rng_ht;
     }
 
     if (reseed) {
-        if (Hash_DRBG_Reseed(drbg, entropyB, entropyBSz) != 0) {
+        if (Hash_DRBG_Reseed(drbg, seedB, seedBSz) != 0) {
             goto exit_rng_ht;
         }
@@ -789,5 +1021,5 @@
 
 
-const byte entropyA[] = {
+const byte seedA[] = {
     0x63, 0x36, 0x33, 0x77, 0xe4, 0x1e, 0x86, 0x46, 0x8d, 0xeb, 0x0a, 0xb4,
     0xa8, 0xed, 0x68, 0x3f, 0x6a, 0x13, 0x4e, 0x47, 0xe0, 0x14, 0xc7, 0x00,
@@ -796,5 +1028,5 @@
 };
 
-const byte reseedEntropyA[] = {
+const byte reseedSeedA[] = {
     0xe6, 0x2b, 0x8a, 0x8e, 0xe8, 0xf1, 0x41, 0xb6, 0x98, 0x05, 0x66, 0xe3,
     0xbf, 0xe3, 0xc0, 0x49, 0x03, 0xda, 0xd4, 0xac, 0x2c, 0xdf, 0x9f, 0x22,
@@ -816,9 +1048,10 @@
 };
 
-const byte entropyB[] = {
+const byte seedB[] = {
     0xa6, 0x5a, 0xd0, 0xf3, 0x45, 0xdb, 0x4e, 0x0e, 0xff, 0xe8, 0x75, 0xc3,
     0xa2, 0xe7, 0x1f, 0x42, 0xc7, 0x12, 0x9d, 0x62, 0x0f, 0xf5, 0xc1, 0x19,
-    0xa9, 0xef, 0x55, 0xf0, 0x51, 0x85, 0xe0, 0xfb, 0x85, 0x81, 0xf9, 0x31,
-    0x75, 0x17, 0x27, 0x6e, 0x06, 0xe9, 0x60, 0x7d, 0xdb, 0xcb, 0xcc, 0x2e
+    0xa9, 0xef, 0x55, 0xf0, 0x51, 0x85, 0xe0, 0xfb, /* nonce next */
+    0x85, 0x81, 0xf9, 0x31, 0x75, 0x17, 0x27, 0x6e, 0x06, 0xe9, 0x60, 0x7d,
+    0xdb, 0xcb, 0xcc, 0x2e
 };
 
@@ -856,6 +1089,6 @@
 
     if (reseed) {
-        ret = wc_RNG_HealthTest(1, entropyA, sizeof(entropyA),
-                                reseedEntropyA, sizeof(reseedEntropyA),
+        ret = wc_RNG_HealthTest(1, seedA, sizeof(seedA),
+                                reseedSeedA, sizeof(reseedSeedA),
                                 check, RNG_HEALTH_TEST_CHECK_SIZE);
         if (ret == 0) {
@@ -866,5 +1099,5 @@
     }
     else {
-        ret = wc_RNG_HealthTest(0, entropyB, sizeof(entropyB),
+        ret = wc_RNG_HealthTest(0, seedB, sizeof(seedB),
                                 NULL, 0,
                                 check, RNG_HEALTH_TEST_CHECK_SIZE);
@@ -873,4 +1106,21 @@
                                 RNG_HEALTH_TEST_CHECK_SIZE) != 0)
                 ret = -1;
+        }
+
+        /* The previous test cases use a large seed instead of a seed and nonce.
+         * seedB is actually from a test case with a seed and nonce, and
+         * just concatenates them. The pivot point between seed and nonce is
+         * byte 32, feed them into the health test separately. */
+        if (ret == 0) {
+            ret = wc_RNG_HealthTest_ex(0,
+                                    seedB + 32, sizeof(seedB) - 32,
+                                    seedB, 32,
+                                    NULL, 0,
+                                    check, RNG_HEALTH_TEST_CHECK_SIZE,
+                                    NULL, INVALID_DEVID);
+            if (ret == 0) {
+                if (ConstantCompare(check, outputB, sizeof(outputB)) != 0)
+                    ret = -1;
+            }
         }
     }
@@ -995,6 +1245,8 @@
 #ifdef HAVE_INTEL_RDSEED
 
+#ifndef USE_WINDOWS_API
+
 /* return 0 on success */
-static INLINE int IntelRDseed64(word64* seed)
+    static WC_INLINE int IntelRDseed64(word64* seed)
 {
     unsigned char ok;
@@ -1004,6 +1256,21 @@
 }
 
+#else /* USE_WINDOWS_API */
+    /* The compiler Visual Studio uses does not allow inline assembly.
+     * It does allow for Intel intrinsic functions. */
+
 /* return 0 on success */
-static INLINE int IntelRDseed64_r(word64* rnd)
+    static WC_INLINE int IntelRDseed64(word64* seed)
+    {
+        int ok;
+
+        ok = _rdseed64_step(seed);
+        return (ok) ? 0 : -1;
+    }
+
+#endif /* USE_WINDOWS_API */
+
+/* return 0 on success */
+static WC_INLINE int IntelRDseed64_r(word64* rnd)
 {
     int i;
@@ -1041,4 +1308,5 @@
 
     XMEMCPY(output, &rndTmp, sz);
+    ForceZero(&rndTmp, sizeof(rndTmp));
 
     return 0;
@@ -1049,6 +1317,8 @@
 #ifdef HAVE_INTEL_RDRAND
 
+#ifndef USE_WINDOWS_API
+
 /* return 0 on success */
-static INLINE int IntelRDrand64(word64 *rnd)
+static WC_INLINE int IntelRDrand64(word64 *rnd)
 {
     unsigned char ok;
@@ -1059,6 +1329,22 @@
 }
 
+#else /* USE_WINDOWS_API */
+    /* The compiler Visual Studio uses does not allow inline assembly.
+     * It does allow for Intel intrinsic functions. */
+
 /* return 0 on success */
-static INLINE int IntelRDrand64_r(word64 *rnd)
+static WC_INLINE int IntelRDrand64(word64 *rnd)
+{
+    int ok;
+
+    ok = _rdrand64_step(rnd);
+
+    return (ok) ? 0 : -1;
+}
+
+#endif /* USE_WINDOWS_API */
+
+/* return 0 on success */
+static WC_INLINE int IntelRDrand64_r(word64 *rnd)
 {
     int i;
@@ -1182,4 +1468,17 @@
 int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
 {
+    #ifdef HAVE_INTEL_RDSEED
+        if (IS_INTEL_RDSEED(intel_flags)) {
+             if (!wc_GenerateSeed_IntelRD(NULL, output, sz)) {
+                 /* success, we're done */
+                 return 0;
+             }
+        #ifdef FORCE_FAILURE_RDSEED
+             /* don't fall back to CryptoAPI */
+             return READ_RAN_E;
+        #endif
+        }
+    #endif /* HAVE_INTEL_RDSEED */
+
     if(!CryptAcquireContext(&os->handle, 0, 0, PROV_RSA_FULL,
                             CRYPT_VERIFYCONTEXT))
@@ -1302,5 +1601,5 @@
         int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
         {
-            int i;
+            word32 i;
 
             /* turn on RNGA module */
@@ -1418,6 +1717,5 @@
 
 #elif defined(STM32_RNG)
-    /*
-     * wc_Generate a RNG seed using the hardware random number generator
+     /* Generate a RNG seed using the hardware random number generator
      * on the STM32F2/F4/F7. */
 
@@ -1443,5 +1741,43 @@
         return 0;
     }
+    #elif defined(WOLFSSL_STM32F427_RNG)
+
+    /* Generate a RNG seed using the hardware RNG on the STM32F427
+     * directly, following steps outlined in STM32F4 Reference
+     * Manual (Chapter 24) for STM32F4xx family. */
+    int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+    {
+        int i;
+        (void)os;
+
+        /* enable RNG peripheral clock */
+        RCC->AHB2ENR |= RCC_AHB2ENR_RNGEN;
+
+        /* enable RNG interrupt, set IE bit in RNG->CR register */
+        RNG->CR |= RNG_CR_IE;
+
+        /* enable RNG, set RNGEN bit in RNG->CR. Activates RNG,
+         * RNG_LFSR, and error detector */
+        RNG->CR |= RNG_CR_RNGEN;
+
+        /* verify no errors, make sure SEIS and CEIS bits are 0
+         * in RNG->SR register */
+        if (RNG->SR & (RNG_SR_SECS | RNG_SR_CECS))
+            return RNG_FAILURE_E;
+
+        for (i = 0; i < (int)sz; i++) {
+            /* wait until RNG number is ready */
+            while ((RNG->SR & RNG_SR_DRDY) == 0) { }
+
+            /* get value */
+            output[i] = RNG->DR;
+        }
+
+        return 0;
+    }
+
     #else
+
+    /* Generate a RNG seed using the STM32 Standard Peripheral Library */
     int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
     {
@@ -1493,4 +1829,36 @@
     }
 
+#elif defined(WOLFSSL_PB)
+
+    int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+    {
+        word32 i;
+        for (i = 0; i < sz; i++)
+            output[i] = UTL_Rand();
+
+        (void)os;
+
+        return 0;
+    }
+
+#elif defined(WOLFSSL_NUCLEUS)
+#include "nucleus.h"
+#include "kernel/plus_common.h"
+
+#warning "potential for not enough entropy, currently being used for testing"
+int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+{
+    int i;
+    srand(NU_Get_Time_Stamp());
+
+    for (i = 0; i < sz; i++ ) {
+        output[i] = rand() % 256;
+        if ((i % 8) == 7) {
+            srand(NU_Get_Time_Stamp());
+        }
+    }
+
+    return 0;
+}
 #elif defined(WOLFSSL_VXWORKS)
 
@@ -1630,4 +1998,84 @@
     }
 
+#elif (defined(WOLFSSL_IMX6_CAAM) || defined(WOLFSSL_IMX6_CAAM_RNG))
+
+    #include <wolfssl/wolfcrypt/port/caam/wolfcaam.h>
+    #include <wolfssl/wolfcrypt/port/caam/caam_driver.h>
+
+    int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+    {
+        Buffer buf[1];
+        int ret  = 0;
+        int times = 1000, i;
+
+        (void)os;
+
+        if (output == NULL) {
+            return BUFFER_E;
+        }
+
+        buf[0].BufferType = DataBuffer | LastBuffer;
+        buf[0].TheAddress = (Address)output;
+        buf[0].Length     = sz;
+
+        /* Check Waiting to make sure entropy is ready */
+        for (i = 0; i < times; i++) {
+            ret = wc_caamAddAndWait(buf, NULL, CAAM_ENTROPY);
+            if (ret == Success) {
+                break;
+            }
+
+            /* driver could be waiting for entropy */
+            if (ret != RAN_BLOCK_E) {
+                return ret;
+            }
+            usleep(100);
+        }
+
+        if (i == times && ret != Success) {
+             return RNG_FAILURE_E;
+        }
+        else { /* Success case */
+            ret = 0;
+        }
+
+        return ret;
+    }
+
+#elif defined(WOLFSSL_APACHE_MYNEWT)
+
+    #include <stdlib.h>
+    #include "os/os_time.h"
+    int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+    {
+        int i;
+        srand(os_time_get());
+
+        for (i = 0; i < sz; i++ ) {
+            output[i] = rand() % 256;
+            if ((i % 8) == 7) {
+                srand(os_time_get());
+            }
+        }
+
+        return 0;
+    }
+
+#elif defined(WOLFSSL_ESPIDF)
+    #if defined(WOLFSSL_ESPWROOM32)
+        #include <esp_system.h>
+        
+        int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+        {
+            int i;
+            
+            for (i = 0; i< sz; i++) {
+               output[i] =  esp_random( );
+            }
+        
+            return 0;
+        }
+    #endif /* end WOLFSSL_ESPWROOM32 */
+ 
 #elif defined(CUSTOM_RAND_GENERATE_BLOCK)
     /* #define CUSTOM_RAND_GENERATE_BLOCK myRngFunc
@@ -1640,5 +2088,6 @@
       defined(WOLFSSL_LPC43xx)  || defined(WOLFSSL_STM32F2xx) || \
       defined(MBED)             || defined(WOLFSSL_EMBOS) || \
-      defined(WOLFSSL_GENSEED_FORTEST)
+      defined(WOLFSSL_GENSEED_FORTEST) || defined(WOLFSSL_CHIBIOS) || \
+      defined(WOLFSSL_CONTIKI)
 
     /* these platforms do not have a default random seed and
@@ -1677,13 +2126,15 @@
              return ret;
     #else
-             /* fallback to /dev/urandom attempt */
+             /* reset error and fallback to using /dev/urandom */
              ret = 0;
     #endif
         }
-
     #endif /* HAVE_INTEL_RDSEED */
 
+    #ifndef NO_DEV_URANDOM /* way to disable use of /dev/urandom */
         os->fd = open("/dev/urandom",O_RDONLY);
-        if (os->fd == -1) {
+        if (os->fd == -1)
+    #endif
+        {
             /* may still have /dev/random */
             os->fd = open("/dev/random",O_RDONLY);
@@ -1703,5 +2154,5 @@
 
             if (sz) {
-    #ifdef BLOCKING
+    #if defined(BLOCKING) || defined(WC_RNG_BLOCKING)
                 sleep(0);             /* context switch */
     #else
@@ -1738,5 +2189,4 @@
 
 /* End wc_GenerateSeed */
-
 #endif /* WC_NO_RNG */
 #endif /* HAVE_FIPS */
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/ripemd.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/ripemd.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/ripemd.c	(revision 372)
@@ -272,5 +272,5 @@
 
 
-static INLINE void AddLength(RipeMd* ripemd, word32 len)
+static WC_INLINE void AddLength(RipeMd* ripemd, word32 len)
 {
     word32 tmp = ripemd->loLen;
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/rsa.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/rsa.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/rsa.c	(revision 372)
@@ -30,4 +30,16 @@
 #ifndef NO_RSA
 
+#if defined(HAVE_FIPS) && \
+    defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+
+    /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+    #define FIPS_NO_WRAPPERS
+
+       #ifdef USE_WINDOWS_API
+               #pragma code_seg(".fipsA$e")
+               #pragma const_seg(".fipsB$e")
+       #endif
+#endif
+
 #include <wolfssl/wolfcrypt/rsa.h>
 
@@ -44,5 +56,7 @@
  * RSA_LOW_MEM:         NON CRT Private Operations, less memory     default: off
  * WC_NO_RSA_OAEP:      Disables RSA OAEP padding                   default: on (not defined)
-
+ * WC_RSA_NONBLOCK:     Enables support for RSA non-blocking        default: off
+ * WC_RSA_NONBLOCK_TIME:Enables support for time based blocking     default: off
+ *                      time calculation.
 */
 
@@ -55,5 +69,8 @@
 
 
-#ifdef HAVE_FIPS
+/* If building for old FIPS. */
+#if defined(HAVE_FIPS) && \
+    (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))
+
 int  wc_InitRsaKey(RsaKey* key, void* ptr)
 {
@@ -64,4 +81,5 @@
     return InitRsaKey_fips(key, ptr);
 }
+
 
 int  wc_InitRsaKey_ex(RsaKey* key, void* ptr, int devId)
@@ -74,4 +92,5 @@
 }
 
+
 int  wc_FreeRsaKey(RsaKey* key)
 {
@@ -80,4 +99,5 @@
 
 
+#ifndef WOLFSSL_RSA_VERIFY_ONLY
 int  wc_RsaPublicEncrypt(const byte* in, word32 inLen, byte* out,
                                  word32 outLen, RsaKey* key, WC_RNG* rng)
@@ -88,6 +108,8 @@
     return RsaPublicEncrypt_fips(in, inLen, out, outLen, key, rng);
 }
-
-
+#endif
+
+
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
 int  wc_RsaPrivateDecryptInline(byte* in, word32 inLen, byte** out,
                                         RsaKey* key)
@@ -118,4 +140,5 @@
     return RsaSSL_Sign_fips(in, inLen, out, outLen, key, rng);
 }
+#endif
 
 
@@ -148,4 +171,5 @@
 
 
+#ifndef WOLFSSL_RSA_VERIFY_ONLY
 int wc_RsaFlattenPublicKey(RsaKey* key, byte* a, word32* aSz, byte* b,
                            word32* bSz)
@@ -155,4 +179,7 @@
     return RsaFlattenPublicKey(key, a, aSz, b, bSz);
 }
+#endif
+
+
 #ifdef WOLFSSL_KEY_GEN
     int wc_MakeRsaKey(RsaKey* key, int size, long e, WC_RNG* rng)
@@ -168,8 +195,11 @@
 */
 
-#else /* else build without fips */
+#else /* else build without fips, or for new fips */
 
 #include <wolfssl/wolfcrypt/random.h>
 #include <wolfssl/wolfcrypt/logging.h>
+#ifdef WOLF_CRYPTO_DEV
+    #include <wolfssl/wolfcrypt/cryptodev.h>
+#endif
 #ifdef NO_INLINE
     #include <wolfssl/wolfcrypt/misc.h>
@@ -179,6 +209,4 @@
 #endif
 
-#define ERROR_OUT(x) { ret = (x); goto done;}
-
 
 enum {
@@ -196,11 +224,14 @@
 static void wc_RsaCleanup(RsaKey* key)
 {
+#ifndef WOLFSSL_RSA_VERIFY_INLINE
     if (key && key->data) {
         /* make sure any allocated memory is free'd */
         if (key->dataIsAlloc) {
+        #ifndef WOLFSSL_RSA_PUBLIC_ONLY
             if (key->type == RSA_PRIVATE_DECRYPT ||
                 key->type == RSA_PRIVATE_ENCRYPT) {
                 ForceZero(key->data, key->dataLen);
             }
+        #endif
             XFREE(key->data, key->heap, DYNAMIC_TYPE_WOLF_BIGINT);
             key->dataIsAlloc = 0;
@@ -209,4 +240,7 @@
         key->dataLen = 0;
     }
+#else
+    (void)key;
+#endif
 }
 
@@ -218,13 +252,23 @@
         return BAD_FUNC_ARG;
     }
+
+    XMEMSET(key, 0, sizeof(RsaKey));
 
     key->type = RSA_TYPE_UNKNOWN;
     key->state = RSA_STATE_NONE;
     key->heap = heap;
+#ifndef WOLFSSL_RSA_VERIFY_INLINE
+    key->dataIsAlloc = 0;
     key->data = NULL;
+#endif
     key->dataLen = 0;
-    key->dataIsAlloc = 0;
 #ifdef WC_RSA_BLINDING
     key->rng = NULL;
+#endif
+
+#ifdef WOLF_CRYPTO_DEV
+    key->devId = devId;
+#else
+    (void)devId;
 #endif
 
@@ -241,13 +285,16 @@
             return ret;
     #endif /* WC_ASYNC_ENABLE_RSA */
-#else
-    (void)devId;
 #endif /* WOLFSSL_ASYNC_CRYPT */
 
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
     ret = mp_init_multi(&key->n, &key->e, NULL, NULL, NULL, NULL);
     if (ret != MP_OKAY)
         return ret;
 
+#if !defined(WOLFSSL_KEY_GEN) && !defined(OPENSSL_EXTRA) && defined(RSA_LOW_MEM)
+    ret = mp_init_multi(&key->d, &key->p, &key->q, NULL, NULL, NULL);
+#else
     ret = mp_init_multi(&key->d, &key->p, &key->q, &key->dP, &key->dQ, &key->u);
+#endif
     if (ret != MP_OKAY) {
         mp_clear(&key->n);
@@ -255,4 +302,14 @@
         return ret;
     }
+#else
+    ret = mp_init(&key->n);
+    if (ret != MP_OKAY)
+        return ret;
+    ret = mp_init(&key->e);
+    if (ret != MP_OKAY) {
+        mp_clear(&key->n);
+        return ret;
+    }
+#endif
 
 #ifdef WOLFSSL_XILINX_CRYPT
@@ -268,4 +325,27 @@
     return wc_InitRsaKey_ex(key, heap, INVALID_DEVID);
 }
+
+#ifdef HAVE_PKCS11
+int wc_InitRsaKey_Id(RsaKey* key, unsigned char* id, int len, void* heap,
+                     int devId)
+{
+    int ret = 0;
+
+    if (key == NULL)
+        ret = BAD_FUNC_ARG;
+    if (ret == 0 && (len < 0 || len > RSA_MAX_ID_LEN))
+        ret = BUFFER_E;
+
+    if (ret == 0)
+        ret = wc_InitRsaKey_ex(key, heap, devId);
+
+    if (ret == 0 && id != NULL && len != 0) {
+        XMEMCPY(key->id, id, len);
+        key->idLen = len;
+    }
+
+    return ret;
+}
+#endif
 
 
@@ -359,8 +439,11 @@
 #endif
 
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
     if (key->type == RSA_PRIVATE) {
+#if defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA) || !defined(RSA_LOW_MEM)
         mp_forcezero(&key->u);
         mp_forcezero(&key->dQ);
         mp_forcezero(&key->dP);
+#endif
         mp_forcezero(&key->q);
         mp_forcezero(&key->p);
@@ -368,10 +451,13 @@
     }
     /* private part */
+#if defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA) || !defined(RSA_LOW_MEM)
     mp_clear(&key->u);
     mp_clear(&key->dQ);
     mp_clear(&key->dP);
+#endif
     mp_clear(&key->q);
     mp_clear(&key->p);
     mp_clear(&key->d);
+#endif /* WOLFSSL_RSA_PUBLIC_ONLY */
 
     /* public part */
@@ -386,4 +472,95 @@
     return ret;
 }
+
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
+/* Check the pair-wise consistency of the RSA key.
+ * From NIST SP 800-56B, section 6.4.1.1.
+ * Verify that k = (k^e)^d, for some k: 1 < k < n-1. */
+int wc_CheckRsaKey(RsaKey* key)
+{
+#ifdef WOLFSSL_SMALL_STACK
+    mp_int *k = NULL, *tmp = NULL;
+#else
+    mp_int k[1], tmp[1];
+#endif
+    int ret = 0;
+
+#ifdef WOLFSSL_SMALL_STACK
+    k = (mp_int*)XMALLOC(sizeof(mp_int) * 2, NULL, DYNAMIC_TYPE_RSA);
+    if (k == NULL)
+        return MEMORY_E;
+    tmp = k + 1;
+#endif
+
+    if (mp_init_multi(k, tmp, NULL, NULL, NULL, NULL) != MP_OKAY)
+        ret = MP_INIT_E;
+
+    if (ret == 0) {
+        if (key == NULL)
+            ret = BAD_FUNC_ARG;
+    }
+
+    if (ret == 0) {
+        if (mp_set_int(k, 0x2342) != MP_OKAY)
+            ret = MP_READ_E;
+    }
+
+#ifdef WOLFSSL_SP_RSA
+#ifndef WOLFSSL_SP_NO_2048
+    if (mp_count_bits(&key->n) == 2048) {
+        ret = sp_ModExp_2048(k, &key->e, &key->n, tmp);
+        if (ret != 0)
+            ret = MP_EXPTMOD_E;
+        ret = sp_ModExp_2048(tmp, &key->d, &key->n, tmp);
+        if (ret != 0)
+            ret = MP_EXPTMOD_E;
+    }
+    else
+#endif
+#ifndef WOLFSSL_SP_NO_3072
+    if (mp_count_bits(&key->n) == 3072) {
+        ret = sp_ModExp_3072(k, &key->e, &key->n, tmp);
+        if (ret != 0)
+            ret = MP_EXPTMOD_E;
+        ret = sp_ModExp_3072(tmp, &key->d, &key->n, tmp);
+        if (ret != 0)
+            ret = MP_EXPTMOD_E;
+    }
+    else
+#endif
+#endif
+#ifdef WOLFSSL_SP_MATH
+    {
+        ret = WC_KEY_SIZE_E;
+    }
+#else
+    {
+        if (ret == 0) {
+            if (mp_exptmod(k, &key->e, &key->n, tmp) != MP_OKAY)
+                ret = MP_EXPTMOD_E;
+        }
+
+        if (ret == 0) {
+            if (mp_exptmod(tmp, &key->d, &key->n, tmp) != MP_OKAY)
+                ret = MP_EXPTMOD_E;
+        }
+    }
+#endif
+
+    if (ret == 0) {
+        if (mp_cmp(k, tmp) != MP_EQ)
+            ret = RSA_KEY_PAIR_E;
+    }
+
+    mp_forcezero(tmp);
+    mp_clear(tmp);
+    mp_clear(k);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(k, NULL, DYNAMIC_TYPE_RSA);
+#endif
+
+    return ret;
+}
+#endif
 
 
@@ -494,5 +671,4 @@
             break;
     #endif
-    #ifdef WOLFSSL_SHA512
     #ifdef WOLFSSL_SHA384
         case WC_MGF1SHA384:
@@ -500,4 +676,5 @@
             break;
     #endif
+    #ifdef WOLFSSL_SHA512
         case WC_MGF1SHA512:
             ret = RsaMGF1(WC_HASH_TYPE_SHA512, seed, seedSz, out, outSz, heap);
@@ -522,4 +699,6 @@
 
 /* Padding */
+#ifndef WOLFSSL_RSA_VERIFY_ONLY
+#ifndef WC_NO_RNG
 #ifndef WC_NO_RSA_OAEP
 static int RsaPad_OAEP(const byte* input, word32 inputLen, byte* pkcsBlock,
@@ -700,11 +879,25 @@
 
 #ifdef WC_RSA_PSS
+
 /* 0x00 .. 0x00 0x01 | Salt | Gen Hash | 0xbc
  * XOR MGF over all bytes down to end of Salt
  * Gen Hash = HASH(8 * 0x00 | Message Hash | Salt)
+ *
+ * input         Digest of the message.
+ * inputLen      Length of digest.
+ * pkcsBlock     Buffer to write to.
+ * pkcsBlockLen  Length of buffer to write to.
+ * rng           Random number generator (for salt).
+ * htype         Hash function to use.
+ * mgf           Mask generation function.
+ * saltLen       Length of salt to put in padding.
+ * bits          Length of key in bits.
+ * heap          Used for dynamic memory allocation.
+ * returns 0 on success, PSS_SALTLEN_E when the salt length is invalid
+ * and other negative values on error.
  */
 static int RsaPad_PSS(const byte* input, word32 inputLen, byte* pkcsBlock,
         word32 pkcsBlockLen, WC_RNG* rng, enum wc_HashType hType, int mgf,
-        int bits, void* heap)
+        int saltLen, int bits, void* heap)
 {
     int   ret;
@@ -719,18 +912,31 @@
         return hLen;
 
+    if (saltLen == -1) {
+        saltLen = hLen;
+        #ifdef WOLFSSL_SHA512
+            /* See FIPS 186-4 section 5.5 item (e). */
+            if (bits == 1024 && hLen == WC_SHA512_DIGEST_SIZE)
+                saltLen = RSA_PSS_SALT_MAX_SZ;
+        #endif
+    }
+    else if (saltLen > hLen || saltLen < -1)
+        return PSS_SALTLEN_E;
+    if ((int)pkcsBlockLen - hLen < saltLen + 2)
+        return PSS_SALTLEN_E;
+
     s = m = pkcsBlock;
-    XMEMSET(m, 0, 8);
-    m += 8;
+    XMEMSET(m, 0, RSA_PSS_PAD_SZ);
+    m += RSA_PSS_PAD_SZ;
     XMEMCPY(m, input, inputLen);
     m += inputLen;
-    if ((ret = wc_RNG_GenerateBlock(rng, salt, hLen)) != 0)
+    if ((ret = wc_RNG_GenerateBlock(rng, salt, saltLen)) != 0)
         return ret;
-    XMEMCPY(m, salt, hLen);
-    m += hLen;
+    XMEMCPY(m, salt, saltLen);
+    m += saltLen;
 
     h = pkcsBlock + pkcsBlockLen - 1 - hLen;
     if ((ret = wc_Hash(hType, s, (word32)(m - s), h, hLen)) != 0)
         return ret;
-    pkcsBlock[pkcsBlockLen - 1] = 0xbc;
+    pkcsBlock[pkcsBlockLen - 1] = RSA_PSS_PAD_TERM;
 
     ret = RsaMGF(mgf, h, hLen, pkcsBlock, pkcsBlockLen - hLen - 1, heap);
@@ -739,12 +945,12 @@
     pkcsBlock[0] &= (1 << ((bits - 1) & 0x7)) - 1;
 
-    m = pkcsBlock + pkcsBlockLen - 1 - hLen - hLen - 1;
+    m = pkcsBlock + pkcsBlockLen - 1 - saltLen - hLen - 1;
     *(m++) ^= 0x01;
-    for (i = 0; i < hLen; i++)
+    for (i = 0; i < saltLen; i++)
         m[i] ^= salt[i];
 
     return 0;
 }
-#endif
+#endif /* WC_RSA_PSS */
 
 static int RsaPad(const byte* input, word32 inputLen, byte* pkcsBlock,
@@ -770,4 +976,5 @@
     }
     else {
+#ifndef WOLFSSL_RSA_VERIFY_ONLY
         /* pad with non-zero random bytes */
         word32 padLen, i;
@@ -789,4 +996,8 @@
             if (pkcsBlock[i] == 0) pkcsBlock[i] = 0x01;
         }
+#else
+        (void)rng;
+        return RSA_WRONG_TYPE_E;
+#endif
     }
 
@@ -796,10 +1007,11 @@
     return 0;
 }
+#endif /* !WC_NO_RNG */
 
 /* helper function to direct which padding is used */
 static int wc_RsaPad_ex(const byte* input, word32 inputLen, byte* pkcsBlock,
     word32 pkcsBlockLen, byte padValue, WC_RNG* rng, int padType,
-    enum wc_HashType hType, int mgf, byte* optLabel, word32 labelLen, int bits,
-    void* heap)
+    enum wc_HashType hType, int mgf, byte* optLabel, word32 labelLen,
+    int saltLen, int bits, void* heap)
 {
     int ret;
@@ -807,4 +1019,5 @@
     switch (padType)
     {
+#ifndef WC_NO_RNG
         case WC_RSA_PKCSV15_PAD:
             /*WOLFSSL_MSG("wolfSSL Using RSA PKCSV15 padding");*/
@@ -825,5 +1038,23 @@
             WOLFSSL_MSG("wolfSSL Using RSA PSS padding");
             ret = RsaPad_PSS(input, inputLen, pkcsBlock, pkcsBlockLen, rng,
-                                                        hType, mgf, bits, heap);
+                                               hType, mgf, saltLen, bits, heap);
+            break;
+    #endif
+#endif /* !WC_NO_RNG */
+
+    #ifdef WC_RSA_NO_PADDING
+        case WC_RSA_NO_PAD:
+            WOLFSSL_MSG("wolfSSL Using NO padding");
+
+            /* In the case of no padding being used check that input is exactly
+             * the RSA key length */
+            if (bits <= 0 || inputLen != ((word32)bits/WOLFSSL_BIT_SIZE)) {
+                WOLFSSL_MSG("Bad input size");
+                ret = RSA_PAD_E;
+            }
+            else {
+                XMEMCPY(pkcsBlock, input, inputLen);
+                ret = 0;
+            }
             break;
     #endif
@@ -835,8 +1066,16 @@
 
     /* silence warning if not used with padding scheme */
+    (void)input;
+    (void)inputLen;
+    (void)pkcsBlock;
+    (void)pkcsBlockLen;
+    (void)padValue;
+    (void)rng;
+    (void)padType;
     (void)hType;
     (void)mgf;
     (void)optLabel;
     (void)labelLen;
+    (void)saltLen;
     (void)bits;
     (void)heap;
@@ -844,4 +1083,5 @@
     return ret;
 }
+#endif /* WOLFSSL_RSA_VERIFY_ONLY */
 
 
@@ -923,8 +1163,6 @@
     ret += pkcsBlock[0]     ^ 0x00; /* Y, the first value, should be 0 */
 
-    if (ret != 0) {
-        WOLFSSL_MSG("RsaUnPad_OAEP: Padding Error");
-        return BAD_PADDING_E;
-    }
+    /* Return 0 data length on error. */
+    idx = ctMaskSelInt(ctMaskEq(ret, 0), idx, pkcsBlockLen);
 
     /* adjust pointer to correct location in array and return size of M */
@@ -935,7 +1173,21 @@
 
 #ifdef WC_RSA_PSS
+/* 0x00 .. 0x00 0x01 | Salt | Gen Hash | 0xbc
+ * MGF over all bytes down to end of Salt
+ *
+ * pkcsBlock     Buffer holding decrypted data.
+ * pkcsBlockLen  Length of buffer.
+ * htype         Hash function to use.
+ * mgf           Mask generation function.
+ * saltLen       Length of salt to put in padding.
+ * bits          Length of key in bits.
+ * heap          Used for dynamic memory allocation.
+ * returns 0 on success, PSS_SALTLEN_E when the salt length is invalid,
+ * BAD_PADDING_E when the padding is not valid, MEMORY_E when allocation fails
+ * and other negative values on error.
+ */
 static int RsaUnPad_PSS(byte *pkcsBlock, unsigned int pkcsBlockLen,
                         byte **output, enum wc_HashType hType, int mgf,
-                        int bits, void* heap)
+                        int saltLen, int bits, void* heap)
 {
     int   ret;
@@ -947,13 +1199,25 @@
         return hLen;
 
-    if (pkcsBlock[pkcsBlockLen - 1] != 0xbc) {
-        WOLFSSL_MSG("RsaUnPad_PSS: Padding Error 0xBC");
+    if (saltLen == -1) {
+        saltLen = hLen;
+        #ifdef WOLFSSL_SHA512
+            /* See FIPS 186-4 section 5.5 item (e). */
+            if (bits == 1024 && hLen == WC_SHA512_DIGEST_SIZE)
+                saltLen = RSA_PSS_SALT_MAX_SZ;
+        #endif
+    }
+    else if (saltLen > hLen || saltLen < -1)
+        return PSS_SALTLEN_E;
+    if ((int)pkcsBlockLen - hLen < saltLen + 2)
+        return PSS_SALTLEN_E;
+
+    if (pkcsBlock[pkcsBlockLen - 1] != RSA_PSS_PAD_TERM) {
+        WOLFSSL_MSG("RsaUnPad_PSS: Padding Term Error");
         return BAD_PADDING_E;
     }
 
     tmp = (byte*)XMALLOC(pkcsBlockLen, heap, DYNAMIC_TYPE_RSA_BUFFER);
-    if (tmp == NULL) {
+    if (tmp == NULL)
         return MEMORY_E;
-    }
 
     if ((ret = RsaMGF(mgf, pkcsBlock + pkcsBlockLen - 1 - hLen, hLen,
@@ -964,5 +1228,5 @@
 
     tmp[0] &= (1 << ((bits - 1) & 0x7)) - 1;
-    for (i = 0; i < (int)(pkcsBlockLen - 1 - hLen - hLen - 1); i++) {
+    for (i = 0; i < (int)(pkcsBlockLen - 1 - saltLen - hLen - 1); i++) {
         if (tmp[i] != pkcsBlock[i]) {
             XFREE(tmp, heap, DYNAMIC_TYPE_RSA_BUFFER);
@@ -981,9 +1245,6 @@
     XFREE(tmp, heap, DYNAMIC_TYPE_RSA_BUFFER);
 
-    i = pkcsBlockLen - (RSA_PSS_PAD_SZ + 3 * hLen + 1);
-    XMEMSET(pkcsBlock + i, 0, RSA_PSS_PAD_SZ);
-
-    *output = pkcsBlock + i;
-    return RSA_PSS_PAD_SZ + 3 * hLen;
+    *output = pkcsBlock + pkcsBlockLen - (hLen + saltLen + 1);
+    return saltLen + hLen;
 }
 #endif
@@ -994,8 +1255,9 @@
                                                byte **output, byte padValue)
 {
-    word32 maxOutputLen = (pkcsBlockLen > 10) ? (pkcsBlockLen - 10) : 0;
-    word32 invalid = 0;
-    word32 i = 1;
-    word32 outputLen;
+    int    ret = BAD_FUNC_ARG;
+    word32 i;
+#ifndef WOLFSSL_RSA_VERIFY_ONLY
+    byte   invalid = 0;
+#endif
 
     if (output == NULL || pkcsBlockLen == 0) {
@@ -1003,42 +1265,60 @@
     }
 
-    if (pkcsBlock[0] != 0x0) { /* skip past zero */
-        invalid = 1;
-    }
-    pkcsBlock++; pkcsBlockLen--;
-
-    /* Require block type padValue */
-    invalid = (pkcsBlock[0] != padValue) || invalid;
-
-    /* verify the padding until we find the separator */
     if (padValue == RSA_BLOCK_TYPE_1) {
-        while (i<pkcsBlockLen && pkcsBlock[i++] == 0xFF) {/* Null body */}
-    }
-    else {
-        while (i<pkcsBlockLen && pkcsBlock[i++]) {/* Null body */}
-    }
-
-    if (!(i==pkcsBlockLen || pkcsBlock[i-1]==0)) {
+        /* First byte must be 0x00 and Second byte, block type, 0x01 */
+        if (pkcsBlock[0] != 0 || pkcsBlock[1] != RSA_BLOCK_TYPE_1) {
+            WOLFSSL_MSG("RsaUnPad error, invalid formatting");
+            return RSA_PAD_E;
+    }
+
+        /* check the padding until we find the separator */
+        for (i = 2; i < pkcsBlockLen && pkcsBlock[i++] == 0xFF; ) { }
+
+        /* Minimum of 11 bytes of pre-message data and must have separator. */
+        if (i < RSA_MIN_PAD_SZ || pkcsBlock[i-1] != 0) {
         WOLFSSL_MSG("RsaUnPad error, bad formatting");
         return RSA_PAD_E;
     }
 
-    outputLen = pkcsBlockLen - i;
-    invalid = (outputLen > maxOutputLen) || invalid;
-
-    if (invalid) {
-        WOLFSSL_MSG("RsaUnPad error, invalid formatting");
-        return RSA_PAD_E;
-    }
+        *output = (byte *)(pkcsBlock + i);
+        ret = pkcsBlockLen - i;
+    }
+#ifndef WOLFSSL_RSA_VERIFY_ONLY
+    else {
+        word32 j;
+        byte   pastSep = 0;
+
+        /* Decrypted with private key - unpad must be constant time. */
+        for (i = 0, j = 2; j < pkcsBlockLen; j++) {
+           /* Update i if not passed the separator and at separator. */
+           i |= (~pastSep) & ctMaskEq(pkcsBlock[j], 0x00) & (j + 1);
+           pastSep |= ctMaskEq(pkcsBlock[j], 0x00);
+        }
+
+        /* Minimum of 11 bytes of pre-message data - including leading 0x00. */
+        invalid |= ctMaskLT(i, RSA_MIN_PAD_SZ);
+        /* Must have seen separator. */
+        invalid |= ~pastSep;
+        /* First byte must be 0x00. */
+        invalid |= ctMaskNotEq(pkcsBlock[0], 0x00);
+        /* Check against expected block type: padValue */
+        invalid |= ctMaskNotEq(pkcsBlock[1], padValue);
 
     *output = (byte *)(pkcsBlock + i);
-    return outputLen;
-}
-
-/* helper function to direct unpadding */
+        ret = ((int)~invalid) & (pkcsBlockLen - i);
+    }
+#endif
+
+    return ret;
+}
+
+/* helper function to direct unpadding
+ *
+ * bits is the key modulus size in bits
+ */
 static int wc_RsaUnPad_ex(byte* pkcsBlock, word32 pkcsBlockLen, byte** out,
                           byte padValue, int padType, enum wc_HashType hType,
-                          int mgf, byte* optLabel, word32 labelLen, int bits,
-                          void* heap)
+                          int mgf, byte* optLabel, word32 labelLen, int saltLen,
+                          int bits, void* heap)
 {
     int ret;
@@ -1062,7 +1342,26 @@
             WOLFSSL_MSG("wolfSSL Using RSA PSS un-padding");
             ret = RsaUnPad_PSS((byte*)pkcsBlock, pkcsBlockLen, out, hType, mgf,
-                                                                    bits, heap);
+                                                           saltLen, bits, heap);
             break;
     #endif
+
+    #ifdef WC_RSA_NO_PADDING
+        case WC_RSA_NO_PAD:
+            WOLFSSL_MSG("wolfSSL Using NO un-padding");
+
+            /* In the case of no padding being used check that input is exactly
+             * the RSA key length */
+            if (bits <= 0 || pkcsBlockLen != ((word32)bits/WOLFSSL_BIT_SIZE)) {
+                WOLFSSL_MSG("Bad input size");
+                ret = RSA_PAD_E;
+            }
+            else {
+                if (out != NULL) {
+                    *out = pkcsBlock;
+                }
+                ret = pkcsBlockLen;
+            }
+            break;
+    #endif /* WC_RSA_NO_PADDING */
 
         default:
@@ -1076,4 +1375,5 @@
     (void)optLabel;
     (void)labelLen;
+    (void)saltLen;
     (void)bits;
     (void)heap;
@@ -1131,13 +1431,101 @@
 #endif /* WOLFSSL_XILINX_CRYPT */
 
+#ifdef WC_RSA_NONBLOCK
+static int wc_RsaFunctionNonBlock(const byte* in, word32 inLen, byte* out,
+                          word32* outLen, int type, RsaKey* key)
+{
+    int    ret = 0;
+    word32 keyLen, len;
+
+    if (key == NULL || key->nb == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    if (key->nb->exptmod.state == TFM_EXPTMOD_NB_INIT) {
+        if (mp_init(&key->nb->tmp) != MP_OKAY) {
+            ret = MP_INIT_E;
+        }
+
+        if (ret == 0) {
+            if (mp_read_unsigned_bin(&key->nb->tmp, (byte*)in, inLen) != MP_OKAY) {
+                ret = MP_READ_E;
+            }
+        }
+    }
+
+    if (ret == 0) {
+        switch(type) {
+        case RSA_PRIVATE_DECRYPT:
+        case RSA_PRIVATE_ENCRYPT:
+            ret = fp_exptmod_nb(&key->nb->exptmod, &key->nb->tmp, &key->d,
+                &key->n, &key->nb->tmp);
+            if (ret == FP_WOULDBLOCK)
+                return ret;
+            if (ret != MP_OKAY)
+                ret = MP_EXPTMOD_E;
+            break;
+
+        case RSA_PUBLIC_ENCRYPT:
+        case RSA_PUBLIC_DECRYPT:
+            ret = fp_exptmod_nb(&key->nb->exptmod, &key->nb->tmp, &key->e,
+                &key->n, &key->nb->tmp);
+            if (ret == FP_WOULDBLOCK)
+                return ret;
+            if (ret != MP_OKAY)
+                ret = MP_EXPTMOD_E;
+            break;
+        default:
+            ret = RSA_WRONG_TYPE_E;
+            break;
+        }
+    }
+
+    if (ret == 0) {
+        keyLen = wc_RsaEncryptSize(key);
+        if (keyLen > *outLen)
+            ret = RSA_BUFFER_E;
+    }
+    if (ret == 0) {
+        len = mp_unsigned_bin_size(&key->nb->tmp);
+
+        /* pad front w/ zeros to match key length */
+        while (len < keyLen) {
+            *out++ = 0x00;
+            len++;
+        }
+
+        *outLen = keyLen;
+
+        /* convert */
+        if (mp_to_unsigned_bin(&key->nb->tmp, out) != MP_OKAY) {
+             ret = MP_TO_E;
+        }
+    }
+
+    mp_clear(&key->nb->tmp);
+
+    return ret;
+}
+#endif /* WC_RSA_NONBLOCK */
+
 static int wc_RsaFunctionSync(const byte* in, word32 inLen, byte* out,
                           word32* outLen, int type, RsaKey* key, WC_RNG* rng)
 {
-    mp_int tmp;
+#ifndef WOLFSSL_SP_MATH
+#ifdef WOLFSSL_SMALL_STACK
+    mp_int* tmp = NULL;
 #ifdef WC_RSA_BLINDING
-    mp_int rnd, rndi;
+    mp_int* rnd = NULL;
+    mp_int* rndi = NULL;
+#endif
+#else
+    mp_int tmp[1];
+#ifdef WC_RSA_BLINDING
+    mp_int rnd[1], rndi[1];
+#endif
 #endif
     int    ret = 0;
-    word32 keyLen, len;
+    word32 keyLen = 0;
+#endif
 
 #ifdef WOLFSSL_HAVE_SP_RSA
@@ -1145,4 +1533,5 @@
     if (mp_count_bits(&key->n) == 2048) {
         switch(type) {
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
         case RSA_PRIVATE_DECRYPT:
         case RSA_PRIVATE_ENCRYPT:
@@ -1151,7 +1540,13 @@
                 return MISSING_RNG_E;
     #endif
+    #ifndef RSA_LOW_MEM
             return sp_RsaPrivate_2048(in, inLen, &key->d, &key->p, &key->q,
                                       &key->dP, &key->dQ, &key->u, &key->n,
                                       out, outLen);
+    #else
+            return sp_RsaPrivate_2048(in, inLen, &key->d, &key->p, &key->q,
+                                      NULL, NULL, NULL, &key->n, out, outLen);
+    #endif
+#endif
         case RSA_PUBLIC_ENCRYPT:
         case RSA_PUBLIC_DECRYPT:
@@ -1163,4 +1558,5 @@
     if (mp_count_bits(&key->n) == 3072) {
         switch(type) {
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
         case RSA_PRIVATE_DECRYPT:
         case RSA_PRIVATE_ENCRYPT:
@@ -1169,7 +1565,13 @@
                 return MISSING_RNG_E;
     #endif
+    #ifndef RSA_LOW_MEM
             return sp_RsaPrivate_3072(in, inLen, &key->d, &key->p, &key->q,
                                       &key->dP, &key->dQ, &key->u, &key->n,
                                       out, outLen);
+    #else
+            return sp_RsaPrivate_3072(in, inLen, &key->d, &key->p, &key->q,
+                                      NULL, NULL, NULL, &key->n, out, outLen);
+    #endif
+#endif
         case RSA_PUBLIC_ENCRYPT:
         case RSA_PUBLIC_DECRYPT:
@@ -1180,98 +1582,137 @@
 #endif /* WOLFSSL_HAVE_SP_RSA */
 
+#ifdef WOLFSSL_SP_MATH
     (void)rng;
-
-    if (mp_init(&tmp) != MP_OKAY)
-        return MP_INIT_E;
-
+    return WC_KEY_SIZE_E;
+#else
+    (void)rng;
+
+#ifdef WOLFSSL_SMALL_STACK
+    tmp = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_RSA);
+    if (tmp == NULL)
+        return MEMORY_E;
 #ifdef WC_RSA_BLINDING
+    rnd = (mp_int*)XMALLOC(sizeof(mp_int) * 2, key->heap, DYNAMIC_TYPE_RSA);
+    if (rnd == NULL) {
+        XFREE(tmp, key->heap, DYNAMIC_TYPE_RSA);
+        return MEMORY_E;
+    }
+    rndi = rnd + 1;
+#endif /* WC_RSA_BLINDING */
+#endif /* WOLFSSL_SMALL_STACK */
+
+    if (mp_init(tmp) != MP_OKAY)
+        ret = MP_INIT_E;
+
+#ifdef WC_RSA_BLINDING
+    if (ret == 0) {
     if (type == RSA_PRIVATE_DECRYPT || type == RSA_PRIVATE_ENCRYPT) {
-        if (mp_init_multi(&rnd, &rndi, NULL, NULL, NULL, NULL) != MP_OKAY) {
-            mp_clear(&tmp);
-            return MP_INIT_E;
-        }
-    }
-#endif
-
-    if (mp_read_unsigned_bin(&tmp, (byte*)in, inLen) != MP_OKAY)
-        ERROR_OUT(MP_READ_E);
-
+            if (mp_init_multi(rnd, rndi, NULL, NULL, NULL, NULL) != MP_OKAY) {
+                mp_clear(tmp);
+                ret = MP_INIT_E;
+            }
+        }
+    }
+#endif
+
+#ifndef TEST_UNPAD_CONSTANT_TIME
+    if (ret == 0 && mp_read_unsigned_bin(tmp, (byte*)in, inLen) != MP_OKAY)
+        ret = MP_READ_E;
+
+    if (ret == 0) {
     switch(type) {
+    #ifndef WOLFSSL_RSA_PUBLIC_ONLY
     case RSA_PRIVATE_DECRYPT:
     case RSA_PRIVATE_ENCRYPT:
     {
-    #ifdef WC_RSA_BLINDING
+        #if defined(WC_RSA_BLINDING) && !defined(WC_NO_RNG)
         /* blind */
-        ret = mp_rand(&rnd, get_digit_count(&key->n), rng);
-        if (ret != MP_OKAY)
-            goto done;
+            ret = mp_rand(rnd, get_digit_count(&key->n), rng);
 
         /* rndi = 1/rnd mod n */
-        if (mp_invmod(&rnd, &key->n, &rndi) != MP_OKAY)
-            ERROR_OUT(MP_INVMOD_E);
+            if (ret == 0 && mp_invmod(rnd, &key->n, rndi) != MP_OKAY)
+                ret = MP_INVMOD_E;
 
         /* rnd = rnd^e */
-        if (mp_exptmod(&rnd, &key->e, &key->n, &rnd) != MP_OKAY)
-            ERROR_OUT(MP_EXPTMOD_E);
+            if (ret == 0 && mp_exptmod(rnd, &key->e, &key->n, rnd) != MP_OKAY)
+                ret = MP_EXPTMOD_E;
 
         /* tmp = tmp*rnd mod n */
-        if (mp_mulmod(&tmp, &rnd, &key->n, &tmp) != MP_OKAY)
-            ERROR_OUT(MP_MULMOD_E);
-    #endif /* WC_RSA_BLINGING */
+            if (ret == 0 && mp_mulmod(tmp, rnd, &key->n, tmp) != MP_OKAY)
+                ret = MP_MULMOD_E;
+        #endif /* WC_RSA_BLINDING && !WC_NO_RNG */
 
     #ifdef RSA_LOW_MEM      /* half as much memory but twice as slow */
-        if (mp_exptmod(&tmp, &key->d, &key->n, &tmp) != MP_OKAY)
-            ERROR_OUT(MP_EXPTMOD_E);
+            if (ret == 0 && mp_exptmod(tmp, &key->d, &key->n, tmp) != MP_OKAY)
+                ret = MP_EXPTMOD_E;
     #else
-        /* Return 0 when cond is false and n when cond is true. */
-        #define COND_N(cond, n)    ((0 - (cond)) & (n))
-        /* If ret has an error value return it otherwise if r is OK then return
-         * 0 otherwise return e.
-         */
-        #define RET_ERR(ret, r, e) \
-            ((ret) | (COND_N((ret) == 0, COND_N((r) != MP_OKAY, (e)))))
-
-        { /* tmpa/b scope */
-        mp_int tmpa, tmpb;
-        int r;
-
-        if (mp_init(&tmpa) != MP_OKAY)
-            ERROR_OUT(MP_INIT_E);
-
-        if (mp_init(&tmpb) != MP_OKAY) {
-            mp_clear(&tmpa);
-            ERROR_OUT(MP_INIT_E);
+            if (ret == 0) {
+            #ifdef WOLFSSL_SMALL_STACK
+                mp_int* tmpa = NULL;
+                mp_int* tmpb = NULL;
+            #else
+                mp_int tmpa[1], tmpb[1];
+            #endif
+                int cleara = 0, clearb = 0;
+
+            #ifdef WOLFSSL_SMALL_STACK
+                tmpa = XMALLOC(sizeof(mp_int) * 2, key->heap, DYNAMIC_TYPE_RSA);
+                if (tmpa != NULL)
+                    tmpb = tmpa + 1;
+                else
+                    ret = MEMORY_E;
+            #endif
+
+                if (ret == 0) {
+                    if (mp_init(tmpa) != MP_OKAY)
+                        ret = MP_INIT_E;
+                    else
+                        cleara = 1;
+                }
+
+                if (ret == 0) {
+                    if (mp_init(tmpb) != MP_OKAY)
+                        ret = MP_INIT_E;
+                    else
+                        clearb = 1;
         }
 
         /* tmpa = tmp^dP mod p */
-        r = mp_exptmod(&tmp, &key->dP, &key->p, &tmpa);
-        ret = RET_ERR(ret, r, MP_EXPTMOD_E);
+                if (ret == 0 && mp_exptmod(tmp, &key->dP, &key->p,
+                                                               tmpa) != MP_OKAY)
+                    ret = MP_EXPTMOD_E;
 
         /* tmpb = tmp^dQ mod q */
-        r = mp_exptmod(&tmp, &key->dQ, &key->q, &tmpb);
-        ret = RET_ERR(ret, r, MP_EXPTMOD_E);
+                if (ret == 0 && mp_exptmod(tmp, &key->dQ, &key->q,
+                                                               tmpb) != MP_OKAY)
+                    ret = MP_EXPTMOD_E;
 
         /* tmp = (tmpa - tmpb) * qInv (mod p) */
-        r = mp_sub(&tmpa, &tmpb, &tmp);
-        ret = RET_ERR(ret, r, MP_SUB_E);
-
-        r = mp_mulmod(&tmp, &key->u, &key->p, &tmp);
-        ret = RET_ERR(ret, r, MP_MULMOD_E);
+                if (ret == 0 && mp_sub(tmpa, tmpb, tmp) != MP_OKAY)
+                    ret = MP_SUB_E;
+
+                if (ret == 0 && mp_mulmod(tmp, &key->u, &key->p,
+                                                                tmp) != MP_OKAY)
+                    ret = MP_MULMOD_E;
 
         /* tmp = tmpb + q * tmp */
-        r = mp_mul(&tmp, &key->q, &tmp);
-        ret = RET_ERR(ret, r, MP_MUL_E);
-
-        r = mp_add(&tmp, &tmpb, &tmp);
-        ret = RET_ERR(ret, r, MP_ADD_E);
-
-        mp_clear(&tmpa);
-        mp_clear(&tmpb);
-
-        if (ret != 0) {
-            goto done;
-        }
-        #undef RET_ERR
-        #undef COND_N
+                if (ret == 0 && mp_mul(tmp, &key->q, tmp) != MP_OKAY)
+                    ret = MP_MUL_E;
+
+                if (ret == 0 && mp_add(tmp, tmpb, tmp) != MP_OKAY)
+                    ret = MP_ADD_E;
+
+            #ifdef WOLFSSL_SMALL_STACK
+                if (tmpa != NULL)
+            #endif
+                {
+                    if (cleara)
+                        mp_clear(tmpa);
+                    if (clearb)
+                        mp_clear(tmpb);
+            #ifdef WOLFSSL_SMALL_STACK
+                    XFREE(tmpa, key->heap, DYNAMIC_TYPE_RSA);
+            #endif
+        }
         } /* tmpa/b scope */
     #endif   /* RSA_LOW_MEM */
@@ -1279,52 +1720,59 @@
     #ifdef WC_RSA_BLINDING
         /* unblind */
-        if (mp_mulmod(&tmp, &rndi, &key->n, &tmp) != MP_OKAY)
-            ERROR_OUT(MP_MULMOD_E);
+            if (ret == 0 && mp_mulmod(tmp, rndi, &key->n, tmp) != MP_OKAY)
+                ret = MP_MULMOD_E;
     #endif   /* WC_RSA_BLINDING */
 
         break;
     }
+    #endif
     case RSA_PUBLIC_ENCRYPT:
     case RSA_PUBLIC_DECRYPT:
     #ifdef WOLFSSL_XILINX_CRYPT
         ret = wc_RsaFunctionXil(in, inLen, out, outLen, type, key, rng);
-        goto done;
     #else
-        if (mp_exptmod(&tmp, &key->e, &key->n, &tmp) != MP_OKAY)
-            ERROR_OUT(MP_EXPTMOD_E);
+            if (mp_exptmod(tmp, &key->e, &key->n, tmp) != MP_OKAY)
+                ret = MP_EXPTMOD_E;
         break;
     #endif
     default:
-        ERROR_OUT(RSA_WRONG_TYPE_E);
-    }
-
-    keyLen = wc_RsaEncryptSize(key);
-    if (keyLen > *outLen) {
-        ERROR_OUT(RSA_BUFFER_E);
-    }
-
-    len = mp_unsigned_bin_size(&tmp);
-
-    /* pad front w/ zeros to match key length */
-    while (len < keyLen) {
-        *out++ = 0x00;
-        len++;
-    }
-
+            ret = RSA_WRONG_TYPE_E;
+            break;
+    }
+    }
+
+    if (ret == 0) {
+        keyLen = wc_RsaEncryptSize(key);
+        if (keyLen > *outLen)
+            ret = RSA_BUFFER_E;
+    }
+    if (ret == 0) {
     *outLen = keyLen;
-
-    /* convert */
-    if (mp_to_unsigned_bin(&tmp, out) != MP_OKAY)
-        ERROR_OUT(MP_TO_E);
-
-done:
-    mp_clear(&tmp);
+        if (mp_to_unsigned_bin_len(tmp, out, keyLen) != MP_OKAY)
+             ret = MP_TO_E;
+    }
+#else
+    (void)type;
+    (void)key;
+    (void)keyLen;
+    XMEMCPY(out, in, inLen);
+    *outLen = inLen;
+#endif
+
+    mp_clear(tmp);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(tmp, key->heap, DYNAMIC_TYPE_RSA);
+#endif
 #ifdef WC_RSA_BLINDING
     if (type == RSA_PRIVATE_DECRYPT || type == RSA_PRIVATE_ENCRYPT) {
-        mp_clear(&rndi);
-        mp_clear(&rnd);
-    }
-#endif
+        mp_clear(rndi);
+        mp_clear(rnd);
+    }
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(rnd, key->heap, DYNAMIC_TYPE_RSA);
+#endif
+#endif /* WC_RSA_BLINDING */
     return ret;
+#endif /* WOLFSSL_SP_MATH */
 }
 
@@ -1352,7 +1800,9 @@
 
     switch(type) {
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
     case RSA_PRIVATE_DECRYPT:
     case RSA_PRIVATE_ENCRYPT:
     #ifdef HAVE_CAVIUM
+        key->dataLen = key->n.raw.len;
         ret = NitroxRsaExptMod(in, inLen,
                                key->d.raw.buf, key->d.raw.len,
@@ -1375,8 +1825,10 @@
     #endif
         break;
+#endif
 
     case RSA_PUBLIC_ENCRYPT:
     case RSA_PUBLIC_DECRYPT:
     #ifdef HAVE_CAVIUM
+        key->dataLen = key->n.raw.len;
         ret = NitroxRsaExptMod(in, inLen,
                                key->e.raw.buf, key->e.raw.len,
@@ -1400,8 +1852,109 @@
 #endif /* WOLFSSL_ASYNC_CRYPT && WC_ASYNC_ENABLE_RSA */
 
+#if defined(WC_RSA_DIRECT) || defined(WC_RSA_NO_PADDING)
+/* Function that does the RSA operation directly with no padding.
+ *
+ * in       buffer to do operation on
+ * inLen    length of input buffer
+ * out      buffer to hold results
+ * outSz    gets set to size of result buffer. Should be passed in as length
+ *          of out buffer. If the pointer "out" is null then outSz gets set to
+ *          the expected buffer size needed and LENGTH_ONLY_E gets returned.
+ * key      RSA key to use for encrypt/decrypt
+ * type     if using private or public key {RSA_PUBLIC_ENCRYPT,
+ *          RSA_PUBLIC_DECRYPT, RSA_PRIVATE_ENCRYPT, RSA_PRIVATE_DECRYPT}
+ * rng      wolfSSL RNG to use if needed
+ *
+ * returns size of result on success
+ */
+int wc_RsaDirect(byte* in, word32 inLen, byte* out, word32* outSz,
+        RsaKey* key, int type, WC_RNG* rng)
+{
+    int ret;
+
+    if (in == NULL || outSz == NULL || key == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    /* sanity check on type of RSA operation */
+    switch (type) {
+        case RSA_PUBLIC_ENCRYPT:
+        case RSA_PUBLIC_DECRYPT:
+        case RSA_PRIVATE_ENCRYPT:
+        case RSA_PRIVATE_DECRYPT:
+            break;
+        default:
+            WOLFSSL_MSG("Bad RSA type");
+            return BAD_FUNC_ARG;
+    }
+
+    if ((ret = wc_RsaEncryptSize(key)) < 0) {
+        return BAD_FUNC_ARG;
+    }
+
+    if (inLen != (word32)ret) {
+        WOLFSSL_MSG("Bad input length. Should be RSA key size");
+        return BAD_FUNC_ARG;
+    }
+
+    if (out == NULL) {
+        *outSz = inLen;
+        return LENGTH_ONLY_E;
+    }
+
+    switch (key->state) {
+        case RSA_STATE_NONE:
+        case RSA_STATE_ENCRYPT_PAD:
+        case RSA_STATE_ENCRYPT_EXPTMOD:
+        case RSA_STATE_DECRYPT_EXPTMOD:
+        case RSA_STATE_DECRYPT_UNPAD:
+            key->state = (type == RSA_PRIVATE_ENCRYPT ||
+                    type == RSA_PUBLIC_ENCRYPT) ? RSA_STATE_ENCRYPT_EXPTMOD:
+                                                  RSA_STATE_DECRYPT_EXPTMOD;
+
+            key->dataLen = *outSz;
+
+            ret = wc_RsaFunction(in, inLen, out, &key->dataLen, type, key, rng);
+            if (ret >= 0 || ret == WC_PENDING_E) {
+                key->state = (type == RSA_PRIVATE_ENCRYPT ||
+                    type == RSA_PUBLIC_ENCRYPT) ? RSA_STATE_ENCRYPT_RES:
+                                                  RSA_STATE_DECRYPT_RES;
+            }
+            if (ret < 0) {
+                break;
+            }
+
+            FALL_THROUGH;
+
+        case RSA_STATE_ENCRYPT_RES:
+        case RSA_STATE_DECRYPT_RES:
+            ret = key->dataLen;
+            break;
+
+        default:
+            ret = BAD_STATE_E;
+    }
+
+    /* if async pending then skip cleanup*/
+    if (ret == WC_PENDING_E
+    #ifdef WC_RSA_NONBLOCK
+        || ret == FP_WOULDBLOCK
+    #endif
+    ) {
+        return ret;
+    }
+
+    key->state = RSA_STATE_NONE;
+    wc_RsaCleanup(key);
+
+    return ret;
+}
+#endif /* WC_RSA_DIRECT || WC_RSA_NO_PADDING */
+
+
 int wc_RsaFunction(const byte* in, word32 inLen, byte* out,
                           word32* outLen, int type, RsaKey* key, WC_RNG* rng)
 {
-    int ret;
+    int ret = 0;
 
     if (key == NULL || in == NULL || inLen == 0 || out == NULL ||
@@ -1409,4 +1962,64 @@
         return BAD_FUNC_ARG;
     }
+
+#ifdef WOLF_CRYPTO_DEV
+    if (key->devId != INVALID_DEVID) {
+        ret = wc_CryptoDev_Rsa(in, inLen, out, outLen, type, key, rng);
+        if (ret != NOT_COMPILED_IN)
+            return ret;
+        ret = 0; /* reset error code and try using software */
+    }
+#endif
+
+#ifndef TEST_UNPAD_CONSTANT_TIME
+#ifndef NO_RSA_BOUNDS_CHECK
+    if (type == RSA_PRIVATE_DECRYPT &&
+        key->state == RSA_STATE_DECRYPT_EXPTMOD) {
+
+        /* Check that 1 < in < n-1. (Requirement of 800-56B.) */
+#ifdef WOLFSSL_SMALL_STACK
+        mp_int* c = NULL;
+#else
+        mp_int c[1];
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+        c = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_RSA);
+        if (c == NULL)
+            ret = MEMORY_E;
+#endif
+
+        if (mp_init(c) != MP_OKAY)
+            ret = MEMORY_E;
+        if (ret == 0) {
+            if (mp_read_unsigned_bin(c, in, inLen) != 0)
+                ret = MP_READ_E;
+        }
+        if (ret == 0) {
+            /* check c > 1 */
+            if (mp_cmp_d(c, 1) != MP_GT)
+                ret = RSA_OUT_OF_RANGE_E;
+        }
+        if (ret == 0) {
+            /* add c+1 */
+            if (mp_add_d(c, 1, c) != MP_OKAY)
+                ret = MP_ADD_E;
+        }
+        if (ret == 0) {
+            /* check c+1 < n */
+            if (mp_cmp(c, &key->n) != MP_LT)
+                ret = RSA_OUT_OF_RANGE_E;
+        }
+        mp_clear(c);
+
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(c, key->heap, DYNAMIC_TYPE_RSA);
+#endif
+
+        if (ret != 0)
+            return ret;
+    }
+#endif /* NO_RSA_BOUNDS_CHECK */
+#endif
 
 #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_RSA)
@@ -1417,4 +2030,10 @@
     else
 #endif
+#ifdef WC_RSA_NONBLOCK
+    if (key->nb) {
+        ret = wc_RsaFunctionNonBlock(in, inLen, out, outLen, type, key);
+    }
+    else
+#endif
     {
         ret = wc_RsaFunctionSync(in, inLen, out, outLen, type, key, rng);
@@ -1422,5 +2041,9 @@
 
     /* handle error */
-    if (ret < 0 && ret != WC_PENDING_E) {
+    if (ret < 0 && ret != WC_PENDING_E
+    #ifdef WC_RSA_NONBLOCK
+        && ret != FP_WOULDBLOCK
+    #endif
+    ) {
         if (ret == MP_EXPTMOD_E) {
             /* This can happen due to incorrectly set FP_MAX_BITS or missing XREALLOC */
@@ -1436,4 +2059,5 @@
 
 
+#ifndef WOLFSSL_RSA_VERIFY_ONLY
 /* Internal Wrappers */
 /* Gives the option of choosing padding type
@@ -1447,15 +2071,18 @@
         RSA_PRIVATE_ENCRYPT or RSA_PRIVATE_DECRYPT
    pad_value: RSA_BLOCK_TYPE_1 or RSA_BLOCK_TYPE_2
-   pad_type  : type of padding: WC_RSA_PKCSV15_PAD, WC_RSA_OAEP_PAD or
-        WC_RSA_PSS_PAD
+   pad_type  : type of padding: WC_RSA_PKCSV15_PAD, WC_RSA_OAEP_PAD,
+        WC_RSA_NO_PAD or WC_RSA_PSS_PAD
    hash  : type of hash algorithm to use found in wolfssl/wolfcrypt/hash.h
    mgf   : type of mask generation function to use
    label : optional label
-   labelSz : size of optional label buffer */
+   labelSz : size of optional label buffer
+   saltLen : Length of salt used in PSS
+   rng : random number generator */
 static int RsaPublicEncryptEx(const byte* in, word32 inLen, byte* out,
                             word32 outLen, RsaKey* key, int rsa_type,
                             byte pad_value, int pad_type,
                             enum wc_HashType hash, int mgf,
-                            byte* label, word32 labelSz, WC_RNG* rng)
+                            byte* label, word32 labelSz, int saltLen,
+                            WC_RNG* rng)
 {
     int ret, sz;
@@ -1475,4 +2102,9 @@
 
     if (inLen > (word32)(sz - RSA_MIN_PAD_SZ)) {
+#ifdef WC_RSA_NO_PADDING
+        /* In the case that no padding is used the input length can and should
+         * be the same size as the RSA key. */
+        if (pad_type != WC_RSA_NO_PAD)
+#endif
         return RSA_BUFFER_E;
     }
@@ -1481,9 +2113,8 @@
     case RSA_STATE_NONE:
     case RSA_STATE_ENCRYPT_PAD:
-        key->state = RSA_STATE_ENCRYPT_PAD;
-
     #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_RSA) && \
             defined(HAVE_CAVIUM)
-        if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_RSA && key->n.raw.buf) {
+        if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_RSA &&
+                                 pad_type != WC_RSA_PSS_PAD && key->n.raw.buf) {
             /* Async operations that include padding */
             if (rsa_type == RSA_PUBLIC_ENCRYPT &&
@@ -1502,6 +2133,7 @@
     #endif
 
+        key->state = RSA_STATE_ENCRYPT_PAD;
         ret = wc_RsaPad_ex(in, inLen, out, sz, pad_value, rng, pad_type, hash,
-                           mgf, label, labelSz, mp_count_bits(&key->n),
+                           mgf, label, labelSz, saltLen, mp_count_bits(&key->n),
                            key->heap);
         if (ret < 0) {
@@ -1510,5 +2142,4 @@
 
         key->state = RSA_STATE_ENCRYPT_EXPTMOD;
-
         FALL_THROUGH;
 
@@ -1537,5 +2168,9 @@
 
     /* if async pending then return and skip done cleanup below */
-    if (ret == WC_PENDING_E) {
+    if (ret == WC_PENDING_E
+    #ifdef WC_RSA_NONBLOCK
+        || ret == FP_WOULDBLOCK
+    #endif
+    ) {
         return ret;
     }
@@ -1546,4 +2181,5 @@
     return ret;
 }
+#endif
 
 /* Gives the option of choosing padding type
@@ -1557,15 +2193,18 @@
         RSA_PRIVATE_ENCRYPT or RSA_PRIVATE_DECRYPT
    pad_value: RSA_BLOCK_TYPE_1 or RSA_BLOCK_TYPE_2
-   pad_type  : type of padding: WC_RSA_PKCSV15_PAD, WC_RSA_OAEP_PAD
-        WC_RSA_PSS_PAD
+   pad_type  : type of padding: WC_RSA_PKCSV15_PAD, WC_RSA_OAEP_PAD,
+        WC_RSA_NO_PAD, WC_RSA_PSS_PAD
    hash  : type of hash algorithm to use found in wolfssl/wolfcrypt/hash.h
    mgf   : type of mask generation function to use
    label : optional label
-   labelSz : size of optional label buffer */
+   labelSz : size of optional label buffer
+   saltLen : Length of salt used in PSS
+   rng : random number generator */
 static int RsaPrivateDecryptEx(byte* in, word32 inLen, byte* out,
                             word32 outLen, byte** outPtr, RsaKey* key,
                             int rsa_type, byte pad_value, int pad_type,
                             enum wc_HashType hash, int mgf,
-                            byte* label, word32 labelSz, WC_RNG* rng)
+                            byte* label, word32 labelSz, int saltLen,
+                            WC_RNG* rng)
 {
     int ret = RSA_WRONG_TYPE_E;
@@ -1577,6 +2216,4 @@
     switch (key->state) {
     case RSA_STATE_NONE:
-    case RSA_STATE_DECRYPT_EXPTMOD:
-        key->state = RSA_STATE_DECRYPT_EXPTMOD;
         key->dataLen = inLen;
 
@@ -1584,12 +2221,14 @@
             defined(HAVE_CAVIUM)
         /* Async operations that include padding */
-        if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_RSA) {
+        if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_RSA &&
+                                                   pad_type != WC_RSA_PSS_PAD) {
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
             if (rsa_type == RSA_PRIVATE_DECRYPT &&
                                                 pad_value == RSA_BLOCK_TYPE_2) {
                 key->state = RSA_STATE_DECRYPT_RES;
                 key->data = NULL;
-                if (outPtr)
-                    *outPtr = in;
-                return NitroxRsaPrivateDecrypt(in, inLen, out, &key->dataLen, key);
+                return NitroxRsaPrivateDecrypt(in, inLen, out, &key->dataLen,
+                                               key);
+#endif
             }
             else if (rsa_type == RSA_PUBLIC_DECRYPT &&
@@ -1602,4 +2241,5 @@
     #endif
 
+#if !defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(WOLFSSL_RSA_VERIFY_INLINE)
         /* verify the tmp ptr is NULL, otherwise indicates bad state */
         if (key->data != NULL) {
@@ -1610,5 +2250,6 @@
         /* if not doing this inline then allocate a buffer for it */
         if (outPtr == NULL) {
-            key->data = (byte*)XMALLOC(inLen, key->heap, DYNAMIC_TYPE_WOLF_BIGINT);
+            key->data = (byte*)XMALLOC(inLen, key->heap,
+                                                      DYNAMIC_TYPE_WOLF_BIGINT);
             key->dataIsAlloc = 1;
             if (key->data == NULL) {
@@ -1621,6 +2262,17 @@
             key->data = out;
         }
-        ret = wc_RsaFunction(key->data, inLen, key->data, &key->dataLen, rsa_type,
-                                                                      key, rng);
+#endif
+
+        key->state = RSA_STATE_DECRYPT_EXPTMOD;
+        FALL_THROUGH;
+
+    case RSA_STATE_DECRYPT_EXPTMOD:
+#if !defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(WOLFSSL_RSA_VERIFY_INLINE)
+        ret = wc_RsaFunction(key->data, inLen, key->data, &key->dataLen,
+                                                            rsa_type, key, rng);
+#else
+        ret = wc_RsaFunction(out, inLen, out, &key->dataLen, rsa_type, key,
+                                                                           rng);
+#endif
 
         if (ret >= 0 || ret == WC_PENDING_E) {
@@ -1636,21 +2288,47 @@
     {
         byte* pad = NULL;
+#if !defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(WOLFSSL_RSA_VERIFY_INLINE)
         ret = wc_RsaUnPad_ex(key->data, key->dataLen, &pad, pad_value, pad_type,
-                             hash, mgf, label, labelSz, mp_count_bits(&key->n),
-                             key->heap);
-        if (ret > 0 && ret <= (int)outLen && pad != NULL) {
+                             hash, mgf, label, labelSz, saltLen,
+                             mp_count_bits(&key->n), key->heap);
+#else
+        ret = wc_RsaUnPad_ex(out, key->dataLen, &pad, pad_value, pad_type, hash,
+                             mgf, label, labelSz, saltLen,
+                             mp_count_bits(&key->n), key->heap);
+#endif
+        if (rsa_type == RSA_PUBLIC_DECRYPT && ret > (int)outLen)
+            ret = RSA_BUFFER_E;
+        else if (ret >= 0 && pad != NULL) {
+#if !defined(WOLFSSL_RSA_VERIFY_ONLY)
+            signed char c;
+#endif
+
             /* only copy output if not inline */
             if (outPtr == NULL) {
+#if !defined(WOLFSSL_RSA_VERIFY_ONLY)
+                word32 i, j;
+                int start = (int)((size_t)pad - (size_t)key->data);
+
+                for (i = 0, j = 0; j < key->dataLen; j++) {
+                    out[i] = key->data[j];
+                    c  = ctMaskGTE(j, start);
+                    c &= ctMaskLT(i, outLen);
+                    /* 0 - no add, -1 add */
+                    i += -c;
+                }
+#else
                 XMEMCPY(out, pad, ret);
+#endif
             }
-            else {
+            else
                 *outPtr = pad;
-            }
-        }
-        else if (ret >= 0) {
+
+#if !defined(WOLFSSL_RSA_VERIFY_ONLY)
+            ret = ctMaskSelInt(ctMaskLTE(ret, outLen), ret, RSA_BUFFER_E);
+            ret = ctMaskSelInt(ctMaskNotEq(ret, 0), ret, RSA_BUFFER_E);
+#else
+            if (outLen < (word32)ret)
             ret = RSA_BUFFER_E;
-        }
-        if (ret < 0) {
-            break;
+#endif
         }
 
@@ -1662,11 +2340,13 @@
     #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_RSA) && \
             defined(HAVE_CAVIUM)
-        if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_RSA) {
-            /* return event ret */
-            ret = key->asyncDev.event.ret;
-            if (ret == 0) {
+        if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_RSA &&
+                                                   pad_type != WC_RSA_PSS_PAD) {
+            if (ret > 0) {
                 /* convert result */
                 byte* dataLen = (byte*)&key->dataLen;
                 ret = (dataLen[0] << 8) | (dataLen[1]);
+
+                if (outPtr)
+                    *outPtr = in;
             }
         }
@@ -1680,5 +2360,9 @@
 
     /* if async pending then return and skip done cleanup below */
-    if (ret == WC_PENDING_E) {
+    if (ret == WC_PENDING_E
+    #ifdef WC_RSA_NONBLOCK
+        || ret == FP_WOULDBLOCK
+    #endif
+    ) {
         return ret;
     }
@@ -1691,4 +2375,5 @@
 
 
+#ifndef WOLFSSL_RSA_VERIFY_ONLY
 /* Public RSA Functions */
 int wc_RsaPublicEncrypt(const byte* in, word32 inLen, byte* out, word32 outLen,
@@ -1697,9 +2382,9 @@
     return RsaPublicEncryptEx(in, inLen, out, outLen, key,
         RSA_PUBLIC_ENCRYPT, RSA_BLOCK_TYPE_2, WC_RSA_PKCSV15_PAD,
-        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, rng);
-}
-
-
-#ifndef WC_NO_RSA_OAEP
+        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, 0, rng);
+}
+
+
+#if !defined(WC_NO_RSA_OAEP) || defined(WC_RSA_NO_PADDING)
 int wc_RsaPublicEncrypt_ex(const byte* in, word32 inLen, byte* out,
                     word32 outLen, RsaKey* key, WC_RNG* rng, int type,
@@ -1708,9 +2393,11 @@
 {
     return RsaPublicEncryptEx(in, inLen, out, outLen, key, RSA_PUBLIC_ENCRYPT,
-        RSA_BLOCK_TYPE_2, type, hash, mgf, label, labelSz, rng);
+        RSA_BLOCK_TYPE_2, type, hash, mgf, label, labelSz, 0, rng);
 }
 #endif /* WC_NO_RSA_OAEP */
-
-
+#endif
+
+
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
 int wc_RsaPrivateDecryptInline(byte* in, word32 inLen, byte** out, RsaKey* key)
 {
@@ -1721,5 +2408,5 @@
     return RsaPrivateDecryptEx(in, inLen, in, inLen, out, key,
         RSA_PRIVATE_DECRYPT, RSA_BLOCK_TYPE_2, WC_RSA_PKCSV15_PAD,
-        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, rng);
+        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, 0, rng);
 }
 
@@ -1736,5 +2423,5 @@
     return RsaPrivateDecryptEx(in, inLen, in, inLen, out, key,
         RSA_PRIVATE_DECRYPT, RSA_BLOCK_TYPE_2, type, hash,
-        mgf, label, labelSz, rng);
+        mgf, label, labelSz, 0, rng);
 }
 #endif /* WC_NO_RSA_OAEP */
@@ -1750,8 +2437,8 @@
     return RsaPrivateDecryptEx((byte*)in, inLen, out, outLen, NULL, key,
         RSA_PRIVATE_DECRYPT, RSA_BLOCK_TYPE_2, WC_RSA_PKCSV15_PAD,
-        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, rng);
-}
-
-#ifndef WC_NO_RSA_OAEP
+        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, 0, rng);
+}
+
+#if !defined(WC_NO_RSA_OAEP) || defined(WC_RSA_NO_PADDING)
 int wc_RsaPrivateDecrypt_ex(const byte* in, word32 inLen, byte* out,
                             word32 outLen, RsaKey* key, int type,
@@ -1765,7 +2452,8 @@
     return RsaPrivateDecryptEx((byte*)in, inLen, out, outLen, NULL, key,
         RSA_PRIVATE_DECRYPT, RSA_BLOCK_TYPE_2, type, hash, mgf, label,
-        labelSz, rng);
-}
-#endif /* WC_NO_RSA_OAEP */
+        labelSz, 0, rng);
+}
+#endif /* WC_NO_RSA_OAEP || WC_RSA_NO_PADDING */
+#endif /* WOLFSSL_RSA_PUBLIC_ONLY */
 
 
@@ -1778,7 +2466,8 @@
     return RsaPrivateDecryptEx(in, inLen, in, inLen, out, key,
         RSA_PUBLIC_DECRYPT, RSA_BLOCK_TYPE_1, WC_RSA_PKCSV15_PAD,
-        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, rng);
-}
-
+        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, 0, rng);
+}
+
+#ifndef WOLFSSL_RSA_VERIFY_ONLY
 int wc_RsaSSL_Verify(const byte* in, word32 inLen, byte* out, word32 outLen,
                                                                  RsaKey* key)
@@ -1796,10 +2485,43 @@
     return RsaPrivateDecryptEx((byte*)in, inLen, out, outLen, NULL, key,
         RSA_PUBLIC_DECRYPT, RSA_BLOCK_TYPE_1, WC_RSA_PKCSV15_PAD,
-        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, rng);
-}
+        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, 0, rng);
+}
+#endif
 
 #ifdef WC_RSA_PSS
+/* Verify the message signed with RSA-PSS.
+ * The input buffer is reused for the ouput buffer.
+ * Salt length is equal to hash length.
+ *
+ * in     Buffer holding encrypted data.
+ * inLen  Length of data in buffer.
+ * out    Pointer to address containing the PSS data.
+ * hash   Hash algorithm.
+ * mgf    Mask generation function.
+ * key    Public RSA key.
+ * returns the length of the PSS data on success and negative indicates failure.
+ */
 int wc_RsaPSS_VerifyInline(byte* in, word32 inLen, byte** out,
                            enum wc_HashType hash, int mgf, RsaKey* key)
+{
+    return wc_RsaPSS_VerifyInline_ex(in, inLen, out, hash, mgf, -1, key);
+}
+
+/* Verify the message signed with RSA-PSS.
+ * The input buffer is reused for the ouput buffer.
+ *
+ * in       Buffer holding encrypted data.
+ * inLen    Length of data in buffer.
+ * out      Pointer to address containing the PSS data.
+ * hash     Hash algorithm.
+ * mgf      Mask generation function.
+ * key      Public RSA key.
+ * saltLen  Length of salt used. -1 indicates salt length is the same as the
+ *          hash length.
+ * returns the length of the PSS data on success and negative indicates failure.
+ */
+int wc_RsaPSS_VerifyInline_ex(byte* in, word32 inLen, byte** out,
+                              enum wc_HashType hash, int mgf, int saltLen,
+                              RsaKey* key)
 {
     WC_RNG* rng = NULL;
@@ -1809,36 +2531,226 @@
     return RsaPrivateDecryptEx(in, inLen, in, inLen, out, key,
         RSA_PUBLIC_DECRYPT, RSA_BLOCK_TYPE_1, WC_RSA_PSS_PAD,
-        hash, mgf, NULL, 0, rng);
-}
-
-/* Sig = 8 * 0x00 | Space for Message Hash | Salt | Exp Hash
- * Exp Hash = HASH(8 * 0x00 | Message Hash | Salt)
+        hash, mgf, NULL, 0, saltLen, rng);
+}
+
+/* Verify the message signed with RSA-PSS.
+ * Salt length is equal to hash length.
+ *
+ * in     Buffer holding encrypted data.
+ * inLen  Length of data in buffer.
+ * out    Pointer to address containing the PSS data.
+ * hash   Hash algorithm.
+ * mgf    Mask generation function.
+ * key    Public RSA key.
+ * returns the length of the PSS data on success and negative indicates failure.
+ */
+int wc_RsaPSS_Verify(byte* in, word32 inLen, byte* out, word32 outLen,
+                     enum wc_HashType hash, int mgf, RsaKey* key)
+{
+    return wc_RsaPSS_Verify_ex(in, inLen, out, outLen, hash, mgf, -1, key);
+}
+
+/* Verify the message signed with RSA-PSS.
+ *
+ * in       Buffer holding encrypted data.
+ * inLen    Length of data in buffer.
+ * out      Pointer to address containing the PSS data.
+ * hash     Hash algorithm.
+ * mgf      Mask generation function.
+ * key      Public RSA key.
+ * saltLen  Length of salt used. -1 indicates salt length is the same as the
+ *          hash length.
+ * returns the length of the PSS data on success and negative indicates failure.
+ */
+int wc_RsaPSS_Verify_ex(byte* in, word32 inLen, byte* out, word32 outLen,
+                        enum wc_HashType hash, int mgf, int saltLen,
+                        RsaKey* key)
+{
+    WC_RNG* rng = NULL;
+#ifdef WC_RSA_BLINDING
+    rng = key->rng;
+#endif
+    return RsaPrivateDecryptEx(in, inLen, out, outLen, NULL, key,
+        RSA_PUBLIC_DECRYPT, RSA_BLOCK_TYPE_1, WC_RSA_PSS_PAD,
+        hash, mgf, NULL, 0, saltLen, rng);
+}
+
+
+/* Checks the PSS data to ensure that the signature matches.
+ * Salt length is equal to hash length.
+ *
+ * in        Hash of the data that is being verified.
+ * inSz      Length of hash.
+ * sig       Buffer holding PSS data.
+ * sigSz     Size of PSS data.
+ * hashType  Hash algorithm.
+ * returns BAD_PADDING_E when the PSS data is invalid, BAD_FUNC_ARG when
+ * NULL is passed in to in or sig or inSz is not the same as the hash
+ * algorithm length and 0 on success.
  */
 int wc_RsaPSS_CheckPadding(const byte* in, word32 inSz, byte* sig,
                            word32 sigSz, enum wc_HashType hashType)
 {
-    int ret;
+    return wc_RsaPSS_CheckPadding_ex(in, inSz, sig, sigSz, hashType, inSz, 0);
+}
+
+/* Checks the PSS data to ensure that the signature matches.
+ *
+ * in        Hash of the data that is being verified.
+ * inSz      Length of hash.
+ * sig       Buffer holding PSS data.
+ * sigSz     Size of PSS data.
+ * hashType  Hash algorithm.
+ * saltLen   Length of salt used. -1 indicates salt length is the same as the
+ *           hash length.
+ * returns BAD_PADDING_E when the PSS data is invalid, BAD_FUNC_ARG when
+ * NULL is passed in to in or sig or inSz is not the same as the hash
+ * algorithm length and 0 on success.
+ */
+int wc_RsaPSS_CheckPadding_ex(const byte* in, word32 inSz, byte* sig,
+                              word32 sigSz, enum wc_HashType hashType,
+                              int saltLen, int bits)
+{
+    int ret = 0;
+    byte sigCheck[WC_MAX_DIGEST_SIZE*2 + RSA_PSS_PAD_SZ];
+
+    (void)bits;
 
     if (in == NULL || sig == NULL ||
-                      inSz != (word32)wc_HashGetDigestSize(hashType) ||
-                      sigSz != RSA_PSS_PAD_SZ + inSz * 3)
+                      inSz != (word32)wc_HashGetDigestSize(hashType))
         ret = BAD_FUNC_ARG;
-    else {
-        XMEMCPY(sig + RSA_PSS_PAD_SZ, in, inSz);
-        ret = wc_Hash(hashType, sig, RSA_PSS_PAD_SZ + inSz * 2, sig, inSz);
-        if (ret != 0)
-            return ret;
-        if (XMEMCMP(sig, sig + RSA_PSS_PAD_SZ + inSz * 2, inSz) != 0) {
+
+    if (ret == 0) {
+        if (saltLen == -1) {
+            saltLen = inSz;
+            #ifdef WOLFSSL_SHA512
+                /* See FIPS 186-4 section 5.5 item (e). */
+                if (bits == 1024 && inSz == WC_SHA512_DIGEST_SIZE)
+                    saltLen = RSA_PSS_SALT_MAX_SZ;
+            #endif
+        }
+        else if (saltLen < -1 || (word32)saltLen > inSz)
+            ret = PSS_SALTLEN_E;
+    }
+
+    /* Sig = Salt | Exp Hash */
+    if (ret == 0) {
+        if (sigSz != inSz + saltLen)
+            ret = BAD_PADDING_E;
+    }
+
+    /* Exp Hash = HASH(8 * 0x00 | Message Hash | Salt) */
+    if (ret == 0) {
+        XMEMSET(sigCheck, 0, RSA_PSS_PAD_SZ);
+        XMEMCPY(sigCheck + RSA_PSS_PAD_SZ, in, inSz);
+        XMEMCPY(sigCheck + RSA_PSS_PAD_SZ + inSz, sig, saltLen);
+        ret = wc_Hash(hashType, sigCheck, RSA_PSS_PAD_SZ + inSz + saltLen,
+                      sigCheck, inSz);
+    }
+    if (ret == 0) {
+        if (XMEMCMP(sigCheck, sig + saltLen, inSz) != 0) {
             WOLFSSL_MSG("RsaPSS_CheckPadding: Padding Error");
             ret = BAD_PADDING_E;
         }
-        else
-            ret = 0;
     }
 
     return ret;
 }
-#endif
-
+
+
+/* Verify the message signed with RSA-PSS.
+ * The input buffer is reused for the ouput buffer.
+ * Salt length is equal to hash length.
+ *
+ * in     Buffer holding encrypted data.
+ * inLen  Length of data in buffer.
+ * out    Pointer to address containing the PSS data.
+ * digest Hash of the data that is being verified.
+ * digestLen Length of hash.
+ * hash   Hash algorithm.
+ * mgf    Mask generation function.
+ * key    Public RSA key.
+ * returns the length of the PSS data on success and negative indicates failure.
+ */
+int wc_RsaPSS_VerifyCheckInline(byte* in, word32 inLen, byte** out,
+                           const byte* digest, word32 digestLen,
+                           enum wc_HashType hash, int mgf, RsaKey* key)
+{
+    int ret = 0, verify, saltLen, hLen, bits = 0;
+
+    hLen = wc_HashGetDigestSize(hash);
+    if (hLen < 0)
+        return hLen;
+    if ((word32)hLen != digestLen)
+        return BAD_FUNC_ARG;
+
+    saltLen = hLen;
+    #ifdef WOLFSSL_SHA512
+        /* See FIPS 186-4 section 5.5 item (e). */
+        bits = mp_count_bits(&key->n);
+        if (bits == 1024 && hLen == WC_SHA512_DIGEST_SIZE)
+            saltLen = RSA_PSS_SALT_MAX_SZ;
+    #endif
+
+    verify = wc_RsaPSS_VerifyInline_ex(in, inLen, out, hash, mgf, saltLen, key);
+    if (verify > 0)
+        ret = wc_RsaPSS_CheckPadding_ex(digest, digestLen, *out, verify,
+                                        hash, saltLen, bits);
+    if (ret == 0)
+        ret = verify;
+
+    return ret;
+}
+
+
+/* Verify the message signed with RSA-PSS.
+ * Salt length is equal to hash length.
+ *
+ * in     Buffer holding encrypted data.
+ * inLen  Length of data in buffer.
+ * out    Pointer to address containing the PSS data.
+ * outLen Length of the output.
+ * digest Hash of the data that is being verified.
+ * digestLen Length of hash.
+ * hash   Hash algorithm.
+ * mgf    Mask generation function.
+ * key    Public RSA key.
+ * returns the length of the PSS data on success and negative indicates failure.
+ */
+int wc_RsaPSS_VerifyCheck(byte* in, word32 inLen, byte* out, word32 outLen,
+                          const byte* digest, word32 digestLen,
+                          enum wc_HashType hash, int mgf,
+                          RsaKey* key)
+{
+    int ret = 0, verify, saltLen, hLen, bits = 0;
+
+    hLen = wc_HashGetDigestSize(hash);
+    if (hLen < 0)
+        return hLen;
+    if ((word32)hLen != digestLen)
+        return BAD_FUNC_ARG;
+
+    saltLen = hLen;
+    #ifdef WOLFSSL_SHA512
+        /* See FIPS 186-4 section 5.5 item (e). */
+        bits = mp_count_bits(&key->n);
+        if (bits == 1024 && hLen == WC_SHA512_DIGEST_SIZE)
+            saltLen = RSA_PSS_SALT_MAX_SZ;
+    #endif
+
+    verify = wc_RsaPSS_Verify_ex(in, inLen, out, outLen, hash,
+                                 mgf, saltLen, key);
+    if (verify > 0)
+        ret = wc_RsaPSS_CheckPadding_ex(digest, digestLen, out, verify,
+                                        hash, saltLen, bits);
+    if (ret == 0)
+        ret = verify;
+
+    return ret;
+}
+
+#endif
+
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
 int wc_RsaSSL_Sign(const byte* in, word32 inLen, byte* out, word32 outLen,
                                                    RsaKey* key, WC_RNG* rng)
@@ -1846,26 +2758,76 @@
     return RsaPublicEncryptEx(in, inLen, out, outLen, key,
         RSA_PRIVATE_ENCRYPT, RSA_BLOCK_TYPE_1, WC_RSA_PKCSV15_PAD,
-        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, rng);
+        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, 0, rng);
 }
 
 #ifdef WC_RSA_PSS
+/* Sign the hash of a message using RSA-PSS.
+ * Salt length is equal to hash length.
+ *
+ * in      Buffer holding hash of message.
+ * inLen   Length of data in buffer (hash length).
+ * out     Buffer to write encrypted signature into.
+ * outLen  Size of buffer to write to.
+ * hash    Hash algorithm.
+ * mgf     Mask generation function.
+ * key     Public RSA key.
+ * rng     Random number generator.
+ * returns the length of the encrypted signature on success, a negative value
+ * indicates failure.
+ */
 int wc_RsaPSS_Sign(const byte* in, word32 inLen, byte* out, word32 outLen,
                        enum wc_HashType hash, int mgf, RsaKey* key, WC_RNG* rng)
 {
+    return wc_RsaPSS_Sign_ex(in, inLen, out, outLen, hash, mgf, -1, key, rng);
+}
+
+/* Sign the hash of a message using RSA-PSS.
+ *
+ * in       Buffer holding hash of message.
+ * inLen    Length of data in buffer (hash length).
+ * out      Buffer to write encrypted signature into.
+ * outLen   Size of buffer to write to.
+ * hash     Hash algorithm.
+ * mgf      Mask generation function.
+ * saltLen  Length of salt used. -1 indicates salt length is the same as the
+ *          hash length.
+ * key      Public RSA key.
+ * rng      Random number generator.
+ * returns the length of the encrypted signature on success, a negative value
+ * indicates failure.
+ */
+int wc_RsaPSS_Sign_ex(const byte* in, word32 inLen, byte* out, word32 outLen,
+                      enum wc_HashType hash, int mgf, int saltLen, RsaKey* key,
+                      WC_RNG* rng)
+{
     return RsaPublicEncryptEx(in, inLen, out, outLen, key,
         RSA_PRIVATE_ENCRYPT, RSA_BLOCK_TYPE_1, WC_RSA_PSS_PAD,
-        hash, mgf, NULL, 0, rng);
-}
-#endif
-
+        hash, mgf, NULL, 0, saltLen, rng);
+}
+#endif
+#endif
+
+#if !defined(WOLFSSL_RSA_PUBLIC_ONLY) || !defined(WOLFSSL_SP_MATH)
 int wc_RsaEncryptSize(RsaKey* key)
 {
+    int ret;
+
     if (key == NULL) {
         return BAD_FUNC_ARG;
     }
-    return mp_unsigned_bin_size(&key->n);
-}
-
-
+
+    ret = mp_unsigned_bin_size(&key->n);
+
+#ifdef WOLF_CRYPTO_DEV
+    if (ret == 0 && key->devId != INVALID_DEVID) {
+        ret = 2048/8; /* hardware handles, use 2048-bit as default */
+}
+#endif
+
+    return ret;
+}
+#endif
+
+#ifndef WOLFSSL_RSA_VERIFY_ONLY
 /* flatten RsaKey structure into individual elements (e, n) */
 int wc_RsaFlattenPublicKey(RsaKey* key, byte* e, word32* eSz, byte* n,
@@ -1896,16 +2858,312 @@
     return 0;
 }
+#endif
+
+#endif /* HAVE_FIPS */
+
+
+#ifndef WOLFSSL_RSA_VERIFY_ONLY
+static int RsaGetValue(mp_int* in, byte* out, word32* outSz)
+{
+    word32 sz;
+    int ret = 0;
+
+    /* Parameters ensured by calling function. */
+
+    sz = (word32)mp_unsigned_bin_size(in);
+    if (sz > *outSz)
+        ret = RSA_BUFFER_E;
+
+    if (ret == 0)
+        ret = mp_to_unsigned_bin(in, out);
+
+    if (ret == MP_OKAY)
+        *outSz = sz;
+
+    return ret;
+}
+
+
+int wc_RsaExportKey(RsaKey* key,
+                    byte* e, word32* eSz, byte* n, word32* nSz,
+                    byte* d, word32* dSz, byte* p, word32* pSz,
+                    byte* q, word32* qSz)
+{
+    int ret = BAD_FUNC_ARG;
+
+    if (key && e && eSz && n && nSz && d && dSz && p && pSz && q && qSz)
+        ret = 0;
+
+    if (ret == 0)
+        ret = RsaGetValue(&key->e, e, eSz);
+    if (ret == 0)
+        ret = RsaGetValue(&key->n, n, nSz);
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
+    if (ret == 0)
+        ret = RsaGetValue(&key->d, d, dSz);
+    if (ret == 0)
+        ret = RsaGetValue(&key->p, p, pSz);
+    if (ret == 0)
+        ret = RsaGetValue(&key->q, q, qSz);
+#else
+    /* no private parts to key */
+    if (d == NULL || p == NULL || q == NULL || dSz == NULL || pSz == NULL
+            || qSz == NULL) {
+        ret = BAD_FUNC_ARG;
+    }
+    else {
+        *dSz = 0;
+        *pSz = 0;
+        *qSz = 0;
+    }
+#endif /* WOLFSSL_RSA_PUBLIC_ONLY */
+
+    return ret;
+}
+#endif
+
 
 #ifdef WOLFSSL_KEY_GEN
+
+/* Check that |p-q| > 2^((size/2)-100) */
+static int wc_CompareDiffPQ(mp_int* p, mp_int* q, int size)
+{
+    mp_int c, d;
+    int ret;
+
+    if (p == NULL || q == NULL)
+        return BAD_FUNC_ARG;
+
+    ret = mp_init_multi(&c, &d, NULL, NULL, NULL, NULL);
+
+    /* c = 2^((size/2)-100) */
+    if (ret == 0)
+        ret = mp_2expt(&c, (size/2)-100);
+
+    /* d = |p-q| */
+    if (ret == 0)
+        ret = mp_sub(p, q, &d);
+
+    if (ret == 0)
+        ret = mp_abs(&d, &d);
+
+    /* compare */
+    if (ret == 0)
+        ret = mp_cmp(&d, &c);
+
+    if (ret == MP_GT)
+        ret = MP_OKAY;
+
+    mp_clear(&d);
+    mp_clear(&c);
+
+    return ret;
+}
+
+
+/* The lower_bound value is floor(2^(0.5) * 2^((nlen/2)-1)) where nlen is 4096.
+ * This number was calculated using a small test tool written with a common
+ * large number math library. Other values of nlen may be checked with a subset
+ * of lower_bound. */
+static const byte lower_bound[] = {
+    0xB5, 0x04, 0xF3, 0x33, 0xF9, 0xDE, 0x64, 0x84,
+    0x59, 0x7D, 0x89, 0xB3, 0x75, 0x4A, 0xBE, 0x9F,
+    0x1D, 0x6F, 0x60, 0xBA, 0x89, 0x3B, 0xA8, 0x4C,
+    0xED, 0x17, 0xAC, 0x85, 0x83, 0x33, 0x99, 0x15,
+/* 512 */
+    0x4A, 0xFC, 0x83, 0x04, 0x3A, 0xB8, 0xA2, 0xC3,
+    0xA8, 0xB1, 0xFE, 0x6F, 0xDC, 0x83, 0xDB, 0x39,
+    0x0F, 0x74, 0xA8, 0x5E, 0x43, 0x9C, 0x7B, 0x4A,
+    0x78, 0x04, 0x87, 0x36, 0x3D, 0xFA, 0x27, 0x68,
+/* 1024 */
+    0xD2, 0x20, 0x2E, 0x87, 0x42, 0xAF, 0x1F, 0x4E,
+    0x53, 0x05, 0x9C, 0x60, 0x11, 0xBC, 0x33, 0x7B,
+    0xCA, 0xB1, 0xBC, 0x91, 0x16, 0x88, 0x45, 0x8A,
+    0x46, 0x0A, 0xBC, 0x72, 0x2F, 0x7C, 0x4E, 0x33,
+    0xC6, 0xD5, 0xA8, 0xA3, 0x8B, 0xB7, 0xE9, 0xDC,
+    0xCB, 0x2A, 0x63, 0x43, 0x31, 0xF3, 0xC8, 0x4D,
+    0xF5, 0x2F, 0x12, 0x0F, 0x83, 0x6E, 0x58, 0x2E,
+    0xEA, 0xA4, 0xA0, 0x89, 0x90, 0x40, 0xCA, 0x4A,
+/* 2048 */
+    0x81, 0x39, 0x4A, 0xB6, 0xD8, 0xFD, 0x0E, 0xFD,
+    0xF4, 0xD3, 0xA0, 0x2C, 0xEB, 0xC9, 0x3E, 0x0C,
+    0x42, 0x64, 0xDA, 0xBC, 0xD5, 0x28, 0xB6, 0x51,
+    0xB8, 0xCF, 0x34, 0x1B, 0x6F, 0x82, 0x36, 0xC7,
+    0x01, 0x04, 0xDC, 0x01, 0xFE, 0x32, 0x35, 0x2F,
+    0x33, 0x2A, 0x5E, 0x9F, 0x7B, 0xDA, 0x1E, 0xBF,
+    0xF6, 0xA1, 0xBE, 0x3F, 0xCA, 0x22, 0x13, 0x07,
+    0xDE, 0xA0, 0x62, 0x41, 0xF7, 0xAA, 0x81, 0xC2,
+/* 3072 */
+    0xC1, 0xFC, 0xBD, 0xDE, 0xA2, 0xF7, 0xDC, 0x33,
+    0x18, 0x83, 0x8A, 0x2E, 0xAF, 0xF5, 0xF3, 0xB2,
+    0xD2, 0x4F, 0x4A, 0x76, 0x3F, 0xAC, 0xB8, 0x82,
+    0xFD, 0xFE, 0x17, 0x0F, 0xD3, 0xB1, 0xF7, 0x80,
+    0xF9, 0xAC, 0xCE, 0x41, 0x79, 0x7F, 0x28, 0x05,
+    0xC2, 0x46, 0x78, 0x5E, 0x92, 0x95, 0x70, 0x23,
+    0x5F, 0xCF, 0x8F, 0x7B, 0xCA, 0x3E, 0xA3, 0x3B,
+    0x4D, 0x7C, 0x60, 0xA5, 0xE6, 0x33, 0xE3, 0xE1
+/* 4096 */
+};
+
+
+/* returns 1 on key size ok and 0 if not ok */
+static WC_INLINE int RsaSizeCheck(int size)
+{
+    if (size < RSA_MIN_SIZE || size > RSA_MAX_SIZE) {
+        return 0;
+    }
+
+#ifdef HAVE_FIPS
+    /* Key size requirements for CAVP */
+    switch (size) {
+        case 1024:
+        case 2048:
+        case 3072:
+        case 4096:
+            return 1;
+    }
+
+    return 0;
+#else
+    return 1; /* allow unusual key sizes in non FIPS mode */
+#endif /* HAVE_FIPS */
+}
+
+
+static int _CheckProbablePrime(mp_int* p, mp_int* q, mp_int* e, int nlen,
+                                    int* isPrime, WC_RNG* rng)
+{
+    int ret;
+    mp_int tmp1, tmp2;
+    mp_int* prime;
+
+    if (p == NULL || e == NULL || isPrime == NULL)
+        return BAD_FUNC_ARG;
+
+    if (!RsaSizeCheck(nlen))
+        return BAD_FUNC_ARG;
+
+    *isPrime = MP_NO;
+
+    if (q != NULL) {
+        /* 5.4 - check that |p-q| <= (2^(1/2))(2^((nlen/2)-1)) */
+        ret = wc_CompareDiffPQ(p, q, nlen);
+        if (ret != MP_OKAY) goto notOkay;
+        prime = q;
+    }
+    else
+        prime = p;
+
+    ret = mp_init_multi(&tmp1, &tmp2, NULL, NULL, NULL, NULL);
+    if (ret != MP_OKAY) goto notOkay;
+
+    /* 4.4,5.5 - Check that prime >= (2^(1/2))(2^((nlen/2)-1))
+     *           This is a comparison against lowerBound */
+    ret = mp_read_unsigned_bin(&tmp1, lower_bound, nlen/16);
+    if (ret != MP_OKAY) goto notOkay;
+    ret = mp_cmp(prime, &tmp1);
+    if (ret == MP_LT) goto exit;
+
+    /* 4.5,5.6 - Check that GCD(p-1, e) == 1 */
+    ret = mp_sub_d(prime, 1, &tmp1);  /* tmp1 = prime-1 */
+    if (ret != MP_OKAY) goto notOkay;
+    ret = mp_gcd(&tmp1, e, &tmp2);  /* tmp2 = gcd(prime-1, e) */
+    if (ret != MP_OKAY) goto notOkay;
+    ret = mp_cmp_d(&tmp2, 1);
+    if (ret != MP_EQ) goto exit; /* e divides p-1 */
+
+    /* 4.5.1,5.6.1 - Check primality of p with 8 rounds of M-R.
+     * mp_prime_is_prime_ex() performs test divisions against the first 256
+     * prime numbers. After that it performs 8 rounds of M-R using random
+     * bases between 2 and n-2.
+     * mp_prime_is_prime() performs the same test divisions and then does
+     * M-R with the first 8 primes. Both functions set isPrime as a
+     * side-effect. */
+    if (rng != NULL)
+        ret = mp_prime_is_prime_ex(prime, 8, isPrime, rng);
+    else
+        ret = mp_prime_is_prime(prime, 8, isPrime);
+    if (ret != MP_OKAY) goto notOkay;
+
+exit:
+    ret = MP_OKAY;
+notOkay:
+    mp_clear(&tmp1);
+    mp_clear(&tmp2);
+    return ret;
+}
+
+
+int wc_CheckProbablePrime_ex(const byte* pRaw, word32 pRawSz,
+                          const byte* qRaw, word32 qRawSz,
+                          const byte* eRaw, word32 eRawSz,
+                          int nlen, int* isPrime, WC_RNG* rng)
+{
+    mp_int p, q, e;
+    mp_int* Q = NULL;
+    int ret;
+
+    if (pRaw == NULL || pRawSz == 0 ||
+        eRaw == NULL || eRawSz == 0 ||
+        isPrime == NULL) {
+
+        return BAD_FUNC_ARG;
+    }
+
+    if ((qRaw != NULL && qRawSz == 0) || (qRaw == NULL && qRawSz != 0))
+        return BAD_FUNC_ARG;
+
+    ret = mp_init_multi(&p, &q, &e, NULL, NULL, NULL);
+
+    if (ret == MP_OKAY)
+        ret = mp_read_unsigned_bin(&p, pRaw, pRawSz);
+
+    if (ret == MP_OKAY) {
+        if (qRaw != NULL) {
+            ret = mp_read_unsigned_bin(&q, qRaw, qRawSz);
+            if (ret == MP_OKAY)
+                Q = &q;
+        }
+    }
+
+    if (ret == MP_OKAY)
+        ret = mp_read_unsigned_bin(&e, eRaw, eRawSz);
+
+    if (ret == MP_OKAY)
+        ret = _CheckProbablePrime(&p, Q, &e, nlen, isPrime, rng);
+
+    ret = (ret == MP_OKAY) ? 0 : PRIME_GEN_E;
+
+    mp_clear(&p);
+    mp_clear(&q);
+    mp_clear(&e);
+
+    return ret;
+}
+
+
+int wc_CheckProbablePrime(const byte* pRaw, word32 pRawSz,
+                          const byte* qRaw, word32 qRawSz,
+                          const byte* eRaw, word32 eRawSz,
+                          int nlen, int* isPrime)
+{
+    return wc_CheckProbablePrime_ex(pRaw, pRawSz, qRaw, qRawSz,
+                          eRaw, eRawSz, nlen, isPrime, NULL);
+}
+
+#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS) && \
+        defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))
 /* Make an RSA key for size bits, with e specified, 65537 is a good e */
 int wc_MakeRsaKey(RsaKey* key, int size, long e, WC_RNG* rng)
 {
+#ifndef WC_NO_RNG
     mp_int p, q, tmp1, tmp2, tmp3;
-    int    err;
+    int err, i, failCount, primeSz, isPrime = 0;
+    byte* buf = NULL;
 
     if (key == NULL || rng == NULL)
         return BAD_FUNC_ARG;
 
-    if (size < RSA_MIN_SIZE || size > RSA_MAX_SIZE)
+    if (!RsaSizeCheck(size))
         return BAD_FUNC_ARG;
 
@@ -1913,10 +3171,19 @@
         return BAD_FUNC_ARG;
 
-#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_RSA)
+#ifdef WOLF_CRYPTO_DEV
+    if (key->devId != INVALID_DEVID) {
+        int ret = wc_CryptoDev_MakeRsaKey(key, size, e, rng);
+        if (ret != NOT_COMPILED_IN)
+            return ret;
+    }
+#endif
+
+#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_RSA) && \
+    defined(WC_ASYNC_ENABLE_RSA_KEYGEN)
     if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_RSA) {
     #ifdef HAVE_CAVIUM
         /* TODO: Not implemented */
     #elif defined(HAVE_INTEL_QA)
-        /* TODO: Not implemented */
+        return IntelQaRsaKeyGen(&key->asyncDev, key, size, e, rng);
     #else
         if (wc_AsyncTestInit(&key->asyncDev, ASYNC_TEST_RSA_MAKE)) {
@@ -1932,88 +3199,163 @@
 #endif
 
-    if ((err = mp_init_multi(&p, &q, &tmp1, &tmp2, &tmp3, NULL)) != MP_OKAY)
-        return err;
-
+    err = mp_init_multi(&p, &q, &tmp1, &tmp2, &tmp3, NULL);
+
+    if (err == MP_OKAY)
     err = mp_set_int(&tmp3, e);
+
+    /* The failCount value comes from NIST FIPS 186-4, section B.3.3,
+     * process steps 4.7 and 5.8. */
+    failCount = 5 * (size / 2);
+    primeSz = size / 16; /* size is the size of n in bits.
+                            primeSz is in bytes. */
+
+    /* allocate buffer to work with */
+    if (err == MP_OKAY) {
+        buf = (byte*)XMALLOC(primeSz, key->heap, DYNAMIC_TYPE_RSA);
+        if (buf == NULL)
+            err = MEMORY_E;
+    }
 
     /* make p */
     if (err == MP_OKAY) {
+        isPrime = 0;
+        i = 0;
         do {
-            err = mp_rand_prime(&p, size/16, rng, key->heap); /* size in bytes/2 */
+#ifdef SHOW_GEN
+            printf(".");
+            fflush(stdout);
+#endif
+            /* generate value */
+            err = wc_RNG_GenerateBlock(rng, buf, primeSz);
+            if (err == 0) {
+                /* prime lower bound has the MSB set, set it in candidate */
+                buf[0] |= 0x80;
+                /* make candidate odd */
+                buf[primeSz-1] |= 0x01;
+                /* load value */
+                err = mp_read_unsigned_bin(&p, buf, primeSz);
+            }
 
             if (err == MP_OKAY)
-                err = mp_sub_d(&p, 1, &tmp1);  /* tmp1 = p-1 */
-
-            if (err == MP_OKAY)
-                err = mp_gcd(&tmp1, &tmp3, &tmp2);  /* tmp2 = gcd(p-1, e) */
-        } while (err == MP_OKAY && mp_cmp_d(&tmp2, 1) != 0);  /* e divides p-1 */
-    }
+                err = _CheckProbablePrime(&p, NULL, &tmp3, size, &isPrime, rng);
+
+#ifdef WOLFSSL_FIPS
+            i++;
+#else
+            /* Keep the old retry behavior in non-FIPS build. */
+            (void)i;
+#endif
+        } while (err == MP_OKAY && !isPrime && i < failCount);
+    }
+
+    if (err == MP_OKAY && !isPrime)
+        err = PRIME_GEN_E;
 
     /* make q */
     if (err == MP_OKAY) {
+        isPrime = 0;
+        i = 0;
         do {
-            err = mp_rand_prime(&q, size/16, rng, key->heap); /* size in bytes/2 */
+#ifdef SHOW_GEN
+            printf(".");
+            fflush(stdout);
+#endif
+            /* generate value */
+            err = wc_RNG_GenerateBlock(rng, buf, primeSz);
+            if (err == 0) {
+                /* prime lower bound has the MSB set, set it in candidate */
+                buf[0] |= 0x80;
+                /* make candidate odd */
+                buf[primeSz-1] |= 0x01;
+                /* load value */
+                err = mp_read_unsigned_bin(&q, buf, primeSz);
+            }
 
             if (err == MP_OKAY)
-                err = mp_sub_d(&q, 1, &tmp1);  /* tmp1 = q-1 */
-
-            if (err == MP_OKAY)
-                err = mp_gcd(&tmp1, &tmp3, &tmp2);  /* tmp2 = gcd(q-1, e) */
-        } while (err == MP_OKAY && mp_cmp_d(&tmp2, 1) != 0);  /* e divides q-1 */
-    }
-
+                err = _CheckProbablePrime(&p, &q, &tmp3, size, &isPrime, rng);
+
+#ifdef WOLFSSL_FIPS
+            i++;
+#else
+            /* Keep the old retry behavior in non-FIPS build. */
+            (void)i;
+#endif
+        } while (err == MP_OKAY && !isPrime && i < failCount);
+    }
+
+    if (err == MP_OKAY && !isPrime)
+        err = PRIME_GEN_E;
+
+    if (buf) {
+        ForceZero(buf, primeSz);
+        XFREE(buf, key->heap, DYNAMIC_TYPE_RSA);
+    }
+
+
+    /* Setup RsaKey buffers */
     if (err == MP_OKAY)
         err = mp_init_multi(&key->n, &key->e, &key->d, &key->p, &key->q, NULL);
-
     if (err == MP_OKAY)
         err = mp_init_multi(&key->dP, &key->dQ, &key->u, NULL, NULL, NULL);
 
-    if (err == MP_OKAY)
-        err = mp_sub_d(&p, 1, &tmp2);  /* tmp2 = p-1 */
-
-    if (err == MP_OKAY)
-        err = mp_lcm(&tmp1, &tmp2, &tmp1);  /* tmp1 = lcm(p-1, q-1),last loop */
-
+    /* Software Key Calculation */
+    if (err == MP_OKAY)                /* tmp1 = p-1 */
+        err = mp_sub_d(&p, 1, &tmp1);
+    if (err == MP_OKAY)                /* tmp2 = q-1 */
+        err = mp_sub_d(&q, 1, &tmp2);
+    if (err == MP_OKAY)                /* tmp3 = lcm(p-1, q-1), last loop */
+        err = mp_lcm(&tmp1, &tmp2, &tmp3);
     /* make key */
-    if (err == MP_OKAY)
-        err = mp_set_int(&key->e, (mp_digit)e);  /* key->e = e */
-
+    if (err == MP_OKAY)                /* key->e = e */
+        err = mp_set_int(&key->e, (mp_digit)e);
     if (err == MP_OKAY)                /* key->d = 1/e mod lcm(p-1, q-1) */
-        err = mp_invmod(&key->e, &tmp1, &key->d);
-
-    if (err == MP_OKAY)
-        err = mp_mul(&p, &q, &key->n);  /* key->n = pq */
-
-    if (err == MP_OKAY)
-        err = mp_sub_d(&p, 1, &tmp1);
-
-    if (err == MP_OKAY)
-        err = mp_sub_d(&q, 1, &tmp2);
-
-    if (err == MP_OKAY)
+        err = mp_invmod(&key->e, &tmp3, &key->d);
+    if (err == MP_OKAY)                /* key->n = pq */
+        err = mp_mul(&p, &q, &key->n);
+    if (err == MP_OKAY)                /* key->dP = d mod(p-1) */
         err = mp_mod(&key->d, &tmp1, &key->dP);
-
-    if (err == MP_OKAY)
+    if (err == MP_OKAY)                /* key->dQ = d mod(q-1) */
         err = mp_mod(&key->d, &tmp2, &key->dQ);
-
-    if (err == MP_OKAY)
+    if (err == MP_OKAY)                /* key->u = 1/q mod p */
         err = mp_invmod(&q, &p, &key->u);
-
     if (err == MP_OKAY)
         err = mp_copy(&p, &key->p);
-
     if (err == MP_OKAY)
         err = mp_copy(&q, &key->q);
 
+#ifdef HAVE_WOLF_BIGINT
+    /* make sure raw unsigned bin version is available */
+    if (err == MP_OKAY)
+         err = wc_mp_to_bigint(&key->n, &key->n.raw);
+    if (err == MP_OKAY)
+         err = wc_mp_to_bigint(&key->e, &key->e.raw);
+    if (err == MP_OKAY)
+         err = wc_mp_to_bigint(&key->d, &key->d.raw);
+    if (err == MP_OKAY)
+         err = wc_mp_to_bigint(&key->p, &key->p.raw);
+    if (err == MP_OKAY)
+         err = wc_mp_to_bigint(&key->q, &key->q.raw);
+    if (err == MP_OKAY)
+         err = wc_mp_to_bigint(&key->dP, &key->dP.raw);
+    if (err == MP_OKAY)
+         err = wc_mp_to_bigint(&key->dQ, &key->dQ.raw);
+    if (err == MP_OKAY)
+         err = wc_mp_to_bigint(&key->u, &key->u.raw);
+#endif
+
     if (err == MP_OKAY)
         key->type = RSA_PRIVATE;
 
+    mp_clear(&tmp1);
+    mp_clear(&tmp2);
     mp_clear(&tmp3);
-    mp_clear(&tmp2);
-    mp_clear(&tmp1);
+    mp_clear(&p);
     mp_clear(&q);
-    mp_clear(&p);
-
-    if (err != MP_OKAY) {
+
+    /* Perform the pair-wise consistency test on the new key. */
+    if (err == 0)
+        err = wc_CheckRsaKey(key);
+
+    if (err != 0) {
         wc_FreeRsaKey(key);
         return err;
@@ -2025,12 +3367,14 @@
     }
 #endif
-
     return 0;
-}
+#else
+    return NOT_COMPILED_IN;
+#endif
+}
+#endif /* !FIPS || FIPS_VER >= 2 */
 #endif /* WOLFSSL_KEY_GEN */
 
 
 #ifdef WC_RSA_BLINDING
-
 int wc_RsaSetRNG(RsaKey* key, WC_RNG* rng)
 {
@@ -2042,10 +3386,35 @@
     return 0;
 }
-
 #endif /* WC_RSA_BLINDING */
 
-
-#undef ERROR_OUT
-
-#endif /* HAVE_FIPS */
+#ifdef WC_RSA_NONBLOCK
+int wc_RsaSetNonBlock(RsaKey* key, RsaNb* nb)
+{
+    if (key == NULL)
+        return BAD_FUNC_ARG;
+
+    if (nb) {
+        XMEMSET(nb, 0, sizeof(RsaNb));
+    }
+
+    /* Allow nb == NULL to clear non-block mode */
+    key->nb = nb;
+
+    return 0;
+}
+#ifdef WC_RSA_NONBLOCK_TIME
+int wc_RsaSetNonBlockTime(RsaKey* key, word32 maxBlockUs, word32 cpuMHz)
+{
+    if (key == NULL || key->nb == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    /* calculate maximum number of instructions to block */
+    key->nb->exptmod.maxBlockInst = cpuMHz * maxBlockUs;
+
+    return 0;
+}
+#endif /* WC_RSA_NONBLOCK_TIME */
+#endif /* WC_RSA_NONBLOCK */
+
 #endif /* NO_RSA */
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/sha.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/sha.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/sha.c	(revision 372)
@@ -29,9 +29,23 @@
 #if !defined(NO_SHA)
 
+#if defined(HAVE_FIPS) && \
+	defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+
+    /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+    #define FIPS_NO_WRAPPERS
+
+    #ifdef USE_WINDOWS_API
+        #pragma code_seg(".fipsA$j")
+        #pragma const_seg(".fipsB$j")
+    #endif
+#endif
+
 #include <wolfssl/wolfcrypt/sha.h>
 #include <wolfssl/wolfcrypt/error-crypt.h>
 
 /* fips wrapper calls, user can call direct */
-#ifdef HAVE_FIPS
+#if defined(HAVE_FIPS) && \
+    (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))
+
     int wc_InitSha(wc_Sha* sha)
     {
@@ -72,5 +86,5 @@
     }
 
-#else /* else build without fips */
+#else /* else build without fips, or for FIPS v2 */
 
 
@@ -88,6 +102,4 @@
 #endif
 
-static INLINE void AddLength(wc_Sha* sha, word32 len);
-
 
 /* Hardware Acceleration */
@@ -97,57 +109,15 @@
 #elif defined(STM32_HASH)
 
-    /*
-     * STM32F2/F4/F7 hardware SHA1 support through the HASH_* API's from the
-     * Standard Peripheral Library or CubeMX (See note in README).
-     */
-
-    /* STM32 register size, bytes */
-    #ifdef WOLFSSL_STM32_CUBEMX
-        #define SHA_REG_SIZE  WC_SHA_BLOCK_SIZE
-    #else
-        #define SHA_REG_SIZE  4
-        /* STM32 struct notes:
-         * sha->buffer  = first 4 bytes used to hold partial block if needed
-         * sha->buffLen = num bytes currently stored in sha->buffer
-         * sha->loLen   = num bytes that have been written to STM32 FIFO
-         */
-    #endif
-    #define SHA_HW_TIMEOUT 0xFF
-
+    /* Supports CubeMX HAL or Standard Peripheral Library */
 	int wc_InitSha_ex(wc_Sha* sha, void* heap, int devId)
     {
-		if (sha == NULL)
+        if (sha == NULL) {
 			return BAD_FUNC_ARG;
-
-		sha->heap = heap;
-        XMEMSET(sha->buffer, 0, sizeof(sha->buffer));
-        sha->buffLen = 0;
-        sha->loLen = 0;
-        sha->hiLen = 0;
-
-        /* initialize HASH peripheral */
-    #ifdef WOLFSSL_STM32_CUBEMX
-        HAL_HASH_DeInit(&sha->hashHandle);
-        sha->hashHandle.Init.DataType = HASH_DATATYPE_8B;
-        if (HAL_HASH_Init(&sha->hashHandle) != HAL_OK) {
-            return ASYNC_INIT_E;
-        }
-
-        /* reset the hash control register */
-        /* required because Cube MX is not clearing algo bits */
-        HASH->CR &= ~HASH_CR_ALGO;
-    #else
-        HASH_DeInit();
-
-        /* reset the hash control register */
-        HASH->CR &= ~ (HASH_CR_ALGO | HASH_CR_DATATYPE | HASH_CR_MODE);
-
-        /* configure algo used, algo mode, datatype */
-        HASH->CR |= (HASH_AlgoSelection_SHA1 | HASH_AlgoMode_HASH
-                   | HASH_DataType_8b);
-
-        /* reset HASH processor */
-        HASH->CR |= HASH_CR_INIT;
-    #endif
+        }
+
+        (void)devId;
+        (void)heap;
+
+        wc_Stm32_Hash_Init(&sha->stmCtx);
 
         return 0;
@@ -156,6 +126,5 @@
     int wc_ShaUpdate(wc_Sha* sha, const byte* data, word32 len)
     {
-        int ret = 0;
-        byte* local;
+        int ret;
 
         if (sha == NULL || (data == NULL && len > 0)) {
@@ -163,32 +132,9 @@
         }
 
-        /* do block size increments */
-        local = (byte*)sha->buffer;
-
-        /* check that internal buffLen is valid */
-        if (sha->buffLen >= SHA_REG_SIZE)
-            return BUFFER_E;
-
-        while (len) {
-            word32 add = min(len, SHA_REG_SIZE - sha->buffLen);
-            XMEMCPY(&local[sha->buffLen], data, add);
-
-            sha->buffLen += add;
-            data         += add;
-            len          -= add;
-
-            if (sha->buffLen == SHA_REG_SIZE) {
-            #ifdef WOLFSSL_STM32_CUBEMX
-                if (HAL_HASH_SHA1_Accumulate(
-                        &sha->hashHandle, local, SHA_REG_SIZE) != HAL_OK) {
-                    ret = ASYNC_OP_E;
-                }
-            #else
-                HASH_DataIn(*(uint32_t*)local);
-            #endif
-
-                AddLength(sha, SHA_REG_SIZE);
-                sha->buffLen = 0;
-            }
+        ret = wolfSSL_CryptHwMutexLock();
+        if (ret == 0) {
+            ret = wc_Stm32_Hash_Update(&sha->stmCtx, HASH_AlgoSelection_SHA1,
+                data, len);
+            wolfSSL_CryptHwMutexUnLock();
         }
         return ret;
@@ -197,50 +143,18 @@
     int wc_ShaFinal(wc_Sha* sha, byte* hash)
     {
-        int ret = 0;
-
-        if (sha == NULL || hash == NULL)
+        int ret;
+
+        if (sha == NULL || hash == NULL) {
             return BAD_FUNC_ARG;
-
-    #ifdef WOLFSSL_STM32_CUBEMX
-        if (HAL_HASH_SHA1_Start(&sha->hashHandle,
-                (byte*)sha->buffer, sha->buffLen,
-                (byte*)sha->digest, SHA_HW_TIMEOUT) != HAL_OK) {
-            ret = ASYNC_OP_E;
-        }
-        HAL_HASH_DeInit(&sha->hashHandle);
-    #else
-        __IO uint16_t nbvalidbitsdata = 0;
-
-        /* finish reading any trailing bytes into FIFO */
-        if (sha->buffLen > 0) {
-            HASH_DataIn(*(uint32_t*)sha->buffer);
-            AddLength(sha, sha->buffLen);
-        }
-
-        /* calculate number of valid bits in last word of input data */
-        nbvalidbitsdata = 8 * (sha->loLen % SHA_REG_SIZE);
-
-        /* configure number of valid bits in last word of the data */
-        HASH_SetLastWordValidBitsNbr(nbvalidbitsdata);
-
-        /* start HASH processor */
-        HASH_StartDigest();
-
-        /* wait until Busy flag == RESET */
-        while (HASH_GetFlagStatus(HASH_FLAG_BUSY) != RESET) {}
-
-        /* read message digest */
-        sha->digest[0] = HASH->HR[0];
-        sha->digest[1] = HASH->HR[1];
-        sha->digest[2] = HASH->HR[2];
-        sha->digest[3] = HASH->HR[3];
-        sha->digest[4] = HASH->HR[4];
-
-        ByteReverseWords(sha->digest, sha->digest, WC_SHA_DIGEST_SIZE);
-    #endif /* WOLFSSL_STM32_CUBEMX */
-
-        XMEMCPY(hash, sha->digest, WC_SHA_DIGEST_SIZE);
-
-        (void)wc_InitSha_ex(sha, sha->heap, INVALID_DEVID);  /* reset state */
+        }
+
+        ret = wolfSSL_CryptHwMutexLock();
+        if (ret == 0) {
+            ret = wc_Stm32_Hash_Final(&sha->stmCtx, HASH_AlgoSelection_SHA1,
+                hash, WC_SHA_DIGEST_SIZE);
+            wolfSSL_CryptHwMutexUnLock();
+        }
+
+        (void)wc_InitSha(sha);  /* reset state */
 
         return ret;
@@ -251,6 +165,13 @@
 
     #include "fsl_ltc.h"
-    static int InitSha(wc_Sha* sha)
-    {
+    int wc_InitSha_ex(wc_Sha* sha, void* heap, int devId)
+    {
+        if (sha == NULL) {
+            return BAD_FUNC_ARG;
+        }
+
+        (void)devId;
+        (void)heap;
+
         LTC_HASH_Init(LTC_BASE, &sha->ctx, kLTC_Sha1, NULL, 0);
         return 0;
@@ -317,4 +238,6 @@
     }
 
+#elif defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_HASH)
+    /* wolfcrypt/src/port/caam/caam_sha.c */
 #else
 
@@ -342,6 +265,8 @@
 
 
-#if defined(USE_SHA_SOFTWARE_IMPL) || defined(STM32_HASH)
-static INLINE void AddLength(wc_Sha* sha, word32 len)
+/* Software implementation */
+#ifdef USE_SHA_SOFTWARE_IMPL
+
+static WC_INLINE void AddLength(wc_Sha* sha, word32 len)
 {
     word32 tmp = sha->loLen;
@@ -349,9 +274,4 @@
         sha->hiLen++;                       /* carry low to high */
 }
-#endif
-
-
-/* Software implementation */
-#ifdef USE_SHA_SOFTWARE_IMPL
 
 /* Check if custom wc_Sha transform is used */
@@ -367,4 +287,12 @@
     #define f3(x,y,z) (((x)&(y))|((z)&((x)|(y))))
     #define f4(x,y,z) ((x)^(y)^(z))
+
+    #ifdef WOLFSSL_NUCLEUS_1_2
+        /* nucleus.h also defines R1-R4 */
+        #undef R1
+        #undef R2
+        #undef R3
+        #undef R4
+    #endif
 
     /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
@@ -526,4 +454,24 @@
 }
 
+int wc_ShaFinalRaw(wc_Sha* sha, byte* hash)
+{
+#ifdef LITTLE_ENDIAN_ORDER
+    word32 digest[WC_SHA_DIGEST_SIZE / sizeof(word32)];
+#endif
+
+    if (sha == NULL || hash == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+#ifdef LITTLE_ENDIAN_ORDER
+    ByteReverseWords((word32*)digest, (word32*)sha->digest, WC_SHA_DIGEST_SIZE);
+    XMEMCPY(hash, digest, WC_SHA_DIGEST_SIZE);
+#else
+    XMEMCPY(hash, sha->digest, WC_SHA_DIGEST_SIZE);
+#endif
+
+    return 0;
+}
+
 int wc_ShaFinal(wc_Sha* sha, byte* hash)
 {
@@ -606,4 +554,8 @@
     wolfAsync_DevCtxFree(&sha->asyncDev, WOLFSSL_ASYNC_MARKER_SHA);
 #endif /* WOLFSSL_ASYNC_CRYPT */
+
+#ifdef WOLFSSL_PIC32MZ_HASH
+    wc_ShaPic32Free(sha);
+#endif
 }
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/sha256.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/sha256.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/sha256.c	(revision 372)
@@ -29,5 +29,17 @@
 #include <wolfssl/wolfcrypt/settings.h>
 
-#if !defined(NO_SHA256)
+#if !defined(NO_SHA256) && !defined(WOLFSSL_ARMASM)
+
+#if defined(HAVE_FIPS) && \
+	defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+
+    /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+    #define FIPS_NO_WRAPPERS
+
+    #ifdef USE_WINDOWS_API
+        #pragma code_seg(".fipsA$d")
+        #pragma const_seg(".fipsB$d")
+    #endif
+#endif
 
 #include <wolfssl/wolfcrypt/sha256.h>
@@ -36,5 +48,6 @@
 
 /* fips wrapper calls, user can call direct */
-#ifdef HAVE_FIPS
+#if defined(HAVE_FIPS) && \
+    (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))
 
     int wc_InitSha256(wc_Sha256* sha)
@@ -59,4 +72,10 @@
             return BAD_FUNC_ARG;
         }
+
+        if (data == NULL && len == 0) {
+            /* valid, but do nothing */
+            return 0;
+        }
+
         return Sha256Update_fips(sha, data, len);
     }
@@ -74,5 +93,5 @@
     }
 
-#else /* else build without fips */
+#else /* else build without fips, or for FIPS v2 */
 
 
@@ -90,8 +109,27 @@
 #endif
 
+#ifdef WOLFSSL_DEVCRYPTO_HASH
+    #include <wolfssl/wolfcrypt/port/devcrypto/wc_devcrypto.h>
+#endif
+
+
 
 #if defined(USE_INTEL_SPEEDUP)
+    #if defined(__GNUC__) && ((__GNUC__ < 4) || \
+                              (__GNUC__ == 4 && __GNUC_MINOR__ <= 8))
+        #undef  NO_AVX2_SUPPORT
+        #define NO_AVX2_SUPPORT
+    #endif
+    #if defined(__clang__) && ((__clang_major__ < 3) || \
+                               (__clang_major__ == 3 && __clang_minor__ <= 5))
+        #define NO_AVX2_SUPPORT
+    #elif defined(__clang__) && defined(NO_AVX2_SUPPORT)
+        #undef NO_AVX2_SUPPORT
+    #endif
+
     #define HAVE_INTEL_AVX1
+    #ifndef NO_AVX2_SUPPORT
     #define HAVE_INTEL_AVX2
+    #endif
 #endif /* USE_INTEL_SPEEDUP */
 
@@ -101,7 +139,7 @@
 
 
-static INLINE void AddLength(wc_Sha256* sha256, word32 len);
-
-#if !defined(WOLFSSL_PIC32MZ_HASH) && !defined(STM32_HASH)
+#if !defined(WOLFSSL_PIC32MZ_HASH) && !defined(STM32_HASH_SHA2) && \
+    (!defined(WOLFSSL_IMX6_CAAM) || defined(NO_IMX6_CAAM_HASH)) && \
+    !defined(WOLFSSL_AFALG_HASH) && !defined(WOLFSSL_DEVCRYPTO_HASH)
 static int InitSha256(wc_Sha256* sha256)
 {
@@ -151,7 +189,7 @@
 
     #if defined(HAVE_INTEL_AVX1)|| defined(HAVE_INTEL_AVX2)
-      Transform(); Function prototype
+      Transform_Sha256(); Function prototype
     #else
-      Transform() {   }
+      Transform_Sha256() {   }
       int Sha256Final() {
          Save/Recover XMM, YMM
@@ -172,5 +210,5 @@
        #define XMM Instructions/inline asm
 
-       int Transform() {
+       int Transform_Sha256() {
            Stitched Message Sched/Round
         }
@@ -180,5 +218,5 @@
       #define YMM Instructions/inline asm
 
-      int Transform() {
+      int Transform_Sha256() {
           More granural Stitched Message Sched/Round
       }
@@ -193,16 +231,27 @@
 
     /* #if defined(HAVE_INTEL_AVX1/2) at the tail of sha256 */
-    static int Transform(wc_Sha256* sha256);
+    static int Transform_Sha256(wc_Sha256* sha256);
     #if defined(HAVE_INTEL_AVX1)
-        static int Transform_AVX1(wc_Sha256 *sha256);
+        static int Transform_Sha256_AVX1(wc_Sha256 *sha256);
+        static int Transform_Sha256_AVX1_Len(wc_Sha256* sha256, word32 len);
     #endif
     #if defined(HAVE_INTEL_AVX2)
-        static int Transform_AVX2(wc_Sha256 *sha256);
-        static int Transform_AVX1_RORX(wc_Sha256 *sha256);
-    #endif
-    static int (*Transform_p)(wc_Sha256* sha256) /* = _Transform */;
+        static int Transform_Sha256_AVX2(wc_Sha256 *sha256);
+        static int Transform_Sha256_AVX2_Len(wc_Sha256* sha256, word32 len);
+        #ifdef HAVE_INTEL_RORX
+        static int Transform_Sha256_AVX1_RORX(wc_Sha256 *sha256);
+        static int Transform_Sha256_AVX1_RORX_Len(wc_Sha256* sha256, word32 len);
+        static int Transform_Sha256_AVX2_RORX(wc_Sha256 *sha256);
+        static int Transform_Sha256_AVX2_RORX_Len(wc_Sha256* sha256, word32 len);
+    #endif
+    #endif
+    static int (*Transform_Sha256_p)(wc_Sha256* sha256);
+                                                       /* = _Transform_Sha256 */
+    static int (*Transform_Sha256_Len_p)(wc_Sha256* sha256, word32 len);
+                                                                    /* = NULL */
     static int transform_check = 0;
     static word32 intel_flags;
-    #define XTRANSFORM(S, B)  (*Transform_p)((S))
+    #define XTRANSFORM(S)         (*Transform_Sha256_p)((S))
+    #define XTRANSFORM_LEN(S, L)  (*Transform_Sha256_Len_p)((S),(L))
 
     static void Sha256_SetTransform(void)
@@ -214,34 +263,41 @@
         intel_flags = cpuid_get_flags();
 
-    #if defined(HAVE_INTEL_AVX2)
-        if (IS_INTEL_AVX2(intel_flags) && IS_INTEL_BMI2(intel_flags)) {
+    #ifdef HAVE_INTEL_AVX2
+        if (IS_INTEL_AVX2(intel_flags)) {
+        #ifdef HAVE_INTEL_RORX
+            if (IS_INTEL_BMI2(intel_flags)) {
+                Transform_Sha256_p = Transform_Sha256_AVX2_RORX;
+                Transform_Sha256_Len_p = Transform_Sha256_AVX2_RORX_Len;
+            }
+            else
+        #endif
             if (1)
-                Transform_p = Transform_AVX1_RORX;
-            else
-                Transform_p = Transform_AVX2;
+            {
+                Transform_Sha256_p = Transform_Sha256_AVX2;
+                Transform_Sha256_Len_p = Transform_Sha256_AVX2_Len;
+            }
+        #ifdef HAVE_INTEL_RORX
+            else {
+                Transform_Sha256_p = Transform_Sha256_AVX1_RORX;
+                Transform_Sha256_Len_p = Transform_Sha256_AVX1_RORX_Len;
+            }
+        #endif
         }
         else
     #endif
-    #if defined(HAVE_INTEL_AVX1)
-        if (1) {
-            Transform_p = ((IS_INTEL_AVX1(intel_flags)) ? Transform_AVX1 :
-                                                                     Transform);
+    #ifdef HAVE_INTEL_AVX1
+        if (IS_INTEL_AVX1(intel_flags)) {
+            Transform_Sha256_p = Transform_Sha256_AVX1;
+            Transform_Sha256_Len_p = Transform_Sha256_AVX1_Len;
         }
         else
     #endif
-            Transform_p = Transform;
+        {
+            Transform_Sha256_p = Transform_Sha256;
+            Transform_Sha256_Len_p = NULL;
+        }
 
         transform_check = 1;
     }
-
-    /* Dummy for saving MM_REGs on behalf of Transform */
-    #if defined(HAVE_INTEL_AVX2) && !defined(HAVE_INTEL_AVX1)
-        #define SAVE_XMM_YMM   __asm__ volatile("or %%r8d, %%r8d":::\
-          "%ymm4","%ymm5","%ymm6","%ymm7","%ymm8","%ymm9","%ymm10","%ymm11","%ymm12","%ymm13","%ymm14","%ymm15")
-    #elif defined(HAVE_INTEL_AVX1)
-        #define SAVE_XMM_YMM   __asm__ volatile("or %%r8d, %%r8d":::\
-            "xmm0","xmm1","xmm2","xmm3","xmm4","xmm5","xmm6","xmm7","xmm8","xmm9","xmm10",\
-            "xmm11","xmm12","xmm13","xmm14","xmm15")
-    #endif
 
     int wc_InitSha256_ex(wc_Sha256* sha256, void* heap, int devId)
@@ -289,5 +345,6 @@
     #endif
 
-    #define XTRANSFORM(S, B)  Transform((S), (B))
+    #define XTRANSFORM(S)        Transform_Sha256((S))
+    #define XTRANSFORM_LEN(S,L)  Transform_Sha256_Len((S),(L))
 
     int wc_InitSha256_ex(wc_Sha256* sha256, void* heap, int devId)
@@ -316,12 +373,12 @@
     }
 
-    static int Transform(wc_Sha256* sha256, byte* buf)
+    static int Transform_Sha256(wc_Sha256* sha256)
     {
         int ret = wolfSSL_CryptHwMutexLock();
         if (ret == 0) {
     #ifdef FREESCALE_MMCAU_CLASSIC_SHA
-            cau_sha256_hash_n(buf, 1, sha256->digest);
+            cau_sha256_hash_n((byte*)sha256->buffer, 1, sha256->digest);
     #else
-            MMCAU_SHA256_HashN(buf, 1, sha256->digest);
+            MMCAU_SHA256_HashN((byte*)sha256->buffer, 1, sha256->digest);
     #endif
             wolfSSL_CryptHwMutexUnLock();
@@ -333,23 +390,7 @@
     #include <wolfssl/wolfcrypt/port/pic32/pic32mz-crypt.h>
 
-#elif defined(STM32_HASH)
-
-    /*
-     * STM32F2/F4/F7 hardware SHA256 support through the HASH_* API's from the
-     * Standard Peripheral Library or CubeMX (See note in README).
-     */
-
-    /* STM32 register size, bytes */
-    #ifdef WOLFSSL_STM32_CUBEMX
-        #define SHA256_REG_SIZE  SHA256_BLOCK_SIZE
-    #else
-        #define SHA256_REG_SIZE  4
-        /* STM32 struct notes:
-         * sha256->buffer  = first 4 bytes used to hold partial block if needed
-         * sha256->buffLen = num bytes currently stored in sha256->buffer
-         * sha256->loLen   = num bytes that have been written to STM32 FIFO
-         */
-    #endif
-    #define SHA256_HW_TIMEOUT 0xFF
+#elif defined(STM32_HASH_SHA2)
+
+    /* Supports CubeMX HAL or Standard Peripheral Library */
 
     int wc_InitSha256_ex(wc_Sha256* sha256, void* heap, int devId)
@@ -358,34 +399,8 @@
             return BAD_FUNC_ARG;
 
-        sha256->heap = heap;
-        XMEMSET(sha256->buffer, 0, sizeof(sha256->buffer));
-        sha256->buffLen = 0;
-        sha256->loLen = 0;
-        sha256->hiLen = 0;
-
-        /* initialize HASH peripheral */
-    #ifdef WOLFSSL_STM32_CUBEMX
-        HAL_HASH_DeInit(&sha256->hashHandle);
-        sha256->hashHandle.Init.DataType = HASH_DATATYPE_8B;
-        if (HAL_HASH_Init(&sha256->hashHandle) != HAL_OK) {
-            return ASYNC_INIT_E;
-        }
-        /* reset the hash control register */
-        /* required because Cube MX is not clearing algo bits */
-        HASH->CR &= ~HASH_CR_ALGO;
-    #else
-        HASH_DeInit();
-
-        /* reset the hash control register */
-        HASH->CR &= ~ (HASH_CR_ALGO | HASH_CR_DATATYPE | HASH_CR_MODE);
-
-        /* configure algo used, algo mode, datatype */
-        HASH->CR |= (HASH_AlgoSelection_SHA256 | HASH_AlgoMode_HASH
-                   | HASH_DataType_8b);
-
-        /* reset HASH processor */
-        HASH->CR |= HASH_CR_INIT;
-    #endif
-
+        (void)devId;
+        (void)heap;
+
+        wc_Stm32_Hash_Init(&sha256->stmCtx);
         return 0;
     }
@@ -394,5 +409,4 @@
     {
         int ret = 0;
-        byte* local;
 
         if (sha256 == NULL || (data == NULL && len > 0)) {
@@ -400,32 +414,9 @@
         }
 
-        /* do block size increments */
-        local = (byte*)sha256->buffer;
-
-        /* check that internal buffLen is valid */
-        if (sha256->buffLen >= SHA256_REG_SIZE)
-            return BUFFER_E;
-
-        while (len) {
-            word32 add = min(len, SHA256_REG_SIZE - sha256->buffLen);
-            XMEMCPY(&local[sha256->buffLen], data, add);
-
-            sha256->buffLen += add;
-            data            += add;
-            len             -= add;
-
-            if (sha256->buffLen == SHA256_REG_SIZE) {
-            #ifdef WOLFSSL_STM32_CUBEMX
-                if (HAL_HASHEx_SHA256_Accumulate(
-                        &sha256->hashHandle, local, SHA256_REG_SIZE) != HAL_OK) {
-                    ret = ASYNC_OP_E;
-                }
-            #else
-                HASH_DataIn(*(uint32_t*)local);
-            #endif
-
-                AddLength(sha256, SHA256_REG_SIZE);
-                sha256->buffLen = 0;
-            }
+        ret = wolfSSL_CryptHwMutexLock();
+        if (ret == 0) {
+            ret = wc_Stm32_Hash_Update(&sha256->stmCtx,
+                HASH_AlgoSelection_SHA256, data, len);
+            wolfSSL_CryptHwMutexUnLock();
         }
         return ret;
@@ -436,53 +427,28 @@
         int ret = 0;
 
-        if (sha256 == NULL || hash == NULL)
+        if (sha256 == NULL || hash == NULL) {
             return BAD_FUNC_ARG;
-
-    #ifdef WOLFSSL_STM32_CUBEMX
-        if (HAL_HASHEx_SHA256_Start(&sha256->hashHandle,
-                (byte*)sha256->buffer, sha256->buffLen,
-                (byte*)sha256->digest, SHA256_HW_TIMEOUT) != HAL_OK) {
-            ret = ASYNC_OP_E;
-        }
-    #else
-        __IO uint16_t nbvalidbitsdata = 0;
-
-        /* finish reading any trailing bytes into FIFO */
-        if (sha256->buffLen > 0) {
-            HASH_DataIn(*(uint32_t*)sha256->buffer);
-            AddLength(sha256, sha256->buffLen);
-        }
-
-        /* calculate number of valid bits in last word of input data */
-        nbvalidbitsdata = 8 * (sha256->loLen % SHA256_REG_SIZE);
-
-        /* configure number of valid bits in last word of the data */
-        HASH_SetLastWordValidBitsNbr(nbvalidbitsdata);
-
-        /* start HASH processor */
-        HASH_StartDigest();
-
-        /* wait until Busy flag == RESET */
-        while (HASH_GetFlagStatus(HASH_FLAG_BUSY) != RESET) {}
-
-        /* read message digest */
-        sha256->digest[0] = HASH->HR[0];
-        sha256->digest[1] = HASH->HR[1];
-        sha256->digest[2] = HASH->HR[2];
-        sha256->digest[3] = HASH->HR[3];
-        sha256->digest[4] = HASH->HR[4];
-        sha256->digest[5] = HASH_DIGEST->HR[5];
-        sha256->digest[6] = HASH_DIGEST->HR[6];
-        sha256->digest[7] = HASH_DIGEST->HR[7];
-
-        ByteReverseWords(sha256->digest, sha256->digest, SHA256_DIGEST_SIZE);
-    #endif /* WOLFSSL_STM32_CUBEMX */
-
-        XMEMCPY(hash, sha256->digest, SHA256_DIGEST_SIZE);
-
-        (void)wc_InitSha256_ex(sha256, sha256->heap, INVALID_DEVID);
+        }
+
+        ret = wolfSSL_CryptHwMutexLock();
+        if (ret == 0) {
+            ret = wc_Stm32_Hash_Final(&sha256->stmCtx,
+                HASH_AlgoSelection_SHA256, hash, WC_SHA256_DIGEST_SIZE);
+            wolfSSL_CryptHwMutexUnLock();
+        }
+
+        (void)wc_InitSha256(sha256); /* reset state */
 
         return ret;
     }
+
+#elif defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_HASH)
+    /* functions defined in wolfcrypt/src/port/caam/caam_sha256.c */
+
+#elif defined(WOLFSSL_AFALG_HASH)
+    /* implemented in wolfcrypt/src/port/af_alg/afalg_hash.c */
+
+#elif defined(WOLFSSL_DEVCRYPTO_HASH)
+    /* implemented in wolfcrypt/src/port/devcrypto/devcrypt_hash.c */
 
 #else
@@ -500,4 +466,8 @@
         if (ret != 0)
             return ret;
+
+    #ifdef WOLFSSL_SMALL_STACK_CACHE
+        sha256->W = NULL;
+    #endif
 
     #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_SHA256)
@@ -511,8 +481,4 @@
     }
 #endif /* End Hardware Acceleration */
-
-#ifndef SAVE_XMM_YMM
-    #define SAVE_XMM_YMM
-#endif
 
 #ifdef NEED_SOFT_SHA256
@@ -544,22 +510,40 @@
     #define Gamma1(x)       (S(x, 17) ^ S(x, 19) ^ R(x, 10))
 
-    #define RND(a,b,c,d,e,f,g,h,i) \
-         t0 = (h) + Sigma1((e)) + Ch((e), (f), (g)) + K[(i)] + W[(i)]; \
-         t1 = Sigma0((a)) + Maj((a), (b), (c)); \
-         (d) += t0; \
-         (h)  = t0 + t1;
+    #define a(i) S[(0-i) & 7]
+    #define b(i) S[(1-i) & 7]
+    #define c(i) S[(2-i) & 7]
+    #define d(i) S[(3-i) & 7]
+    #define e(i) S[(4-i) & 7]
+    #define f(i) S[(5-i) & 7]
+    #define g(i) S[(6-i) & 7]
+    #define h(i) S[(7-i) & 7]
+
+    #define RND(j) \
+         t0 = h(j) + Sigma1(e(j)) + Ch(e(j), f(j), g(j)) + K[i+j] + W[i+j]; \
+         t1 = Sigma0(a(j)) + Maj(a(j), b(j), c(j)); \
+         d(j) += t0; \
+         h(j)  = t0 + t1
 
     #ifndef XTRANSFORM
-         #define XTRANSFORM(S, B) Transform((S))
+         #define XTRANSFORM(S)        Transform_Sha256((S))
+         #define XTRANSFORM_LEN(S,L)  Transform_Sha256_Len((S),(L))
      #endif
 
-    static int Transform(wc_Sha256* sha256)
+    static int Transform_Sha256(wc_Sha256* sha256)
     {
         word32 S[8], t0, t1;
         int i;
 
-    #ifdef WOLFSSL_SMALL_STACK
+    #ifdef WOLFSSL_SMALL_STACK_CACHE
+        word32* W = sha256->W;
+        if (W == NULL) {
+            W = (word32*)XMALLOC(sizeof(word32) * WC_SHA256_BLOCK_SIZE, NULL,
+                                                           DYNAMIC_TYPE_DIGEST);
+            if (W == NULL)
+                return MEMORY_E;
+            sha256->W = W;
+        }
+    #elif defined(WOLFSSL_SMALL_STACK)
         word32* W;
-
         W = (word32*)XMALLOC(sizeof(word32) * WC_SHA256_BLOCK_SIZE, NULL,
             DYNAMIC_TYPE_TMP_BUFFER);
@@ -580,14 +564,19 @@
             W[i] = Gamma1(W[i-2]) + W[i-7] + Gamma0(W[i-15]) + W[i-16];
 
+    #ifdef USE_SLOW_SHA256
+        /* not unrolled - ~2k smaller and ~25% slower */
         for (i = 0; i < WC_SHA256_BLOCK_SIZE; i += 8) {
-            RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0);
-            RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1);
-            RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2);
-            RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3);
-            RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4);
-            RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5);
-            RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6);
-            RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7);
-        }
+            int j;
+            for (j = 0; j < 8; j++) { /* braces needed here for macros {} */
+                RND(j);
+            }
+        }
+    #else
+        /* partially loop unrolled */
+        for (i = 0; i < WC_SHA256_BLOCK_SIZE; i += 8) {
+            RND(0); RND(1); RND(2); RND(3);
+            RND(4); RND(5); RND(6); RND(7);
+        }
+    #endif /* USE_SLOW_SHA256 */
 
         /* Add the working vars back into digest state[] */
@@ -596,8 +585,7 @@
         }
 
-    #ifdef WOLFSSL_SMALL_STACK
+    #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE)
         XFREE(W, NULL, DYNAMIC_TYPE_TMP_BUFFER);
     #endif
-
         return 0;
     }
@@ -606,6 +594,7 @@
 
 
-#if defined(XTRANSFORM) || defined(STM32_HASH)
-static INLINE void AddLength(wc_Sha256* sha256, word32 len)
+#ifdef XTRANSFORM
+
+    static WC_INLINE void AddLength(wc_Sha256* sha256, word32 len)
 {
     word32 tmp = sha256->loLen;
@@ -613,10 +602,6 @@
         sha256->hiLen++;                       /* carry low to high */
 }
-#endif
-
-
-#ifdef XTRANSFORM
-
-    static INLINE int Sha256Update(wc_Sha256* sha256, const byte* data, word32 len)
+
+    static WC_INLINE int Sha256Update(wc_Sha256* sha256, const byte* data, word32 len)
     {
         int ret = 0;
@@ -625,4 +610,9 @@
         if (sha256 == NULL || (data == NULL && len > 0)) {
             return BAD_FUNC_ARG;
+        }
+
+        if (data == NULL && len == 0) {
+            /* valid, but do nothing */
+            return 0;
         }
 
@@ -642,7 +632,5 @@
             return BUFFER_E;
 
-        SAVE_XMM_YMM; /* for Intel AVX */
-
-        while (len) {
+        if (sha256->buffLen > 0) {
             word32 add = min(len, WC_SHA256_BLOCK_SIZE - sha256->buffLen);
             XMEMCPY(&local[sha256->buffLen], data, add);
@@ -662,12 +650,70 @@
                 }
         #endif
-                ret = XTRANSFORM(sha256, local);
-                if (ret != 0) {
+                ret = XTRANSFORM(sha256);
+                if (ret == 0) {
+                    AddLength(sha256, WC_SHA256_BLOCK_SIZE);
+                    sha256->buffLen = 0;
+                }
+                else
+                    len = 0;
+            }
+        }
+
+    #if defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
+        if (Transform_Sha256_Len_p != NULL) {
+            word32 blocksLen = len & ~(WC_SHA256_BLOCK_SIZE-1);
+
+            if (blocksLen > 0) {
+                AddLength(sha256, blocksLen);
+                sha256->data = data;
+                /* Byte reversal performed in function if required. */
+                XTRANSFORM_LEN(sha256, blocksLen);
+                data += blocksLen;
+                len  -= blocksLen;
+            }
+        }
+        else
+    #endif
+    #if !defined(LITTLE_ENDIAN_ORDER) || defined(FREESCALE_MMCAU_SHA) || \
+                            defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
+        {
+            word32 blocksLen = len & ~(WC_SHA256_BLOCK_SIZE-1);
+
+            AddLength(sha256, blocksLen);
+            while (len >= WC_SHA256_BLOCK_SIZE) {
+                XMEMCPY(local, data, WC_SHA256_BLOCK_SIZE);
+
+                data += WC_SHA256_BLOCK_SIZE;
+                len  -= WC_SHA256_BLOCK_SIZE;
+
+                /* Byte reversal performed in function if required. */
+                ret = XTRANSFORM(sha256);
+                if (ret != 0)
                     break;
                 }
-
-                AddLength(sha256, WC_SHA256_BLOCK_SIZE);
-                sha256->buffLen = 0;
+        }
+    #else
+        {
+            word32 blocksLen = len & ~(WC_SHA256_BLOCK_SIZE-1);
+
+            AddLength(sha256, blocksLen);
+            while (len >= WC_SHA256_BLOCK_SIZE) {
+                XMEMCPY(local, data, WC_SHA256_BLOCK_SIZE);
+
+                data += WC_SHA256_BLOCK_SIZE;
+                len  -= WC_SHA256_BLOCK_SIZE;
+
+                ByteReverseWords(sha256->buffer, sha256->buffer,
+                                                          WC_SHA256_BLOCK_SIZE);
+                ret = XTRANSFORM(sha256);
+                if (ret != 0)
+                    break;
             }
+            }
+    #endif
+
+        if (len > 0) {
+            XMEMCPY(local, data, len);
+            sha256->buffLen = len;
         }
 
@@ -680,5 +726,5 @@
     }
 
-    static INLINE int Sha256Final(wc_Sha256* sha256)
+    static WC_INLINE int Sha256Final(wc_Sha256* sha256)
     {
 
@@ -689,6 +735,4 @@
             return BAD_FUNC_ARG;
         }
-
-        SAVE_XMM_YMM; /* for Intel AVX */
 
         AddLength(sha256, sha256->buffLen);  /* before adding pads */
@@ -713,5 +757,5 @@
             }
 
-            ret = XTRANSFORM(sha256, local);
+            ret = XTRANSFORM(sha256);
             if (ret != 0)
                 return ret;
@@ -755,5 +799,26 @@
     #endif
 
-        return XTRANSFORM(sha256, local);
+        return XTRANSFORM(sha256);
+    }
+
+    int wc_Sha256FinalRaw(wc_Sha256* sha256, byte* hash)
+    {
+    #ifdef LITTLE_ENDIAN_ORDER
+        word32 digest[WC_SHA256_DIGEST_SIZE / sizeof(word32)];
+    #endif
+
+        if (sha256 == NULL || hash == NULL) {
+            return BAD_FUNC_ARG;
+        }
+
+    #ifdef LITTLE_ENDIAN_ORDER
+        ByteReverseWords((word32*)digest, (word32*)sha256->digest,
+                                                         WC_SHA256_DIGEST_SIZE);
+        XMEMCPY(hash, digest, WC_SHA256_DIGEST_SIZE);
+    #else
+        XMEMCPY(hash, sha256->digest, WC_SHA256_DIGEST_SIZE);
+    #endif
+
+        return 0;
     }
 
@@ -792,270 +857,575 @@
 #if defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
 
-#define _DigestToReg(S0, S1, S2, S3, S4, S5, S6, S7) \
-    "leaq	%[digest], %%r8\n\t"                 \
-    "movl	  (%%r8), %"#S0"\n\t"                \
-    "movl	 4(%%r8), %"#S1"\n\t"                \
-    "movl	 8(%%r8), %"#S2"\n\t"                \
-    "movl	12(%%r8), %"#S3"\n\t"                \
-    "movl	16(%%r8), %"#S4"\n\t"                \
-    "movl	20(%%r8), %"#S5"\n\t"                \
-    "movl	24(%%r8), %"#S6"\n\t"                \
-    "movl	28(%%r8), %"#S7"\n\t"
-
-#define _RegToDigest(S0, S1, S2, S3, S4, S5, S6, S7) \
-    "leaq	%[digest], %%r8\n\t"                 \
-    "addl %"#S0",   (%%r8)\n\t"                      \
-    "addl %"#S1",  4(%%r8)\n\t"                      \
-    "addl %"#S2",  8(%%r8)\n\t"                      \
-    "addl %"#S3", 12(%%r8)\n\t"                      \
-    "addl %"#S4", 16(%%r8)\n\t"                      \
-    "addl %"#S5", 20(%%r8)\n\t"                      \
-    "addl %"#S6", 24(%%r8)\n\t"                      \
-    "addl %"#S7", 28(%%r8)\n\t"
-
-#define DigestToReg(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7 )\
-    _DigestToReg(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7 )
-
-#define RegToDigest(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7 )\
-    _RegToDigest(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7 )
-
-
-#define S_0 %r15d
-#define S_1 %r10d
-#define S_2 %r11d
-#define S_3 %r12d
-#define S_4 %r13d
-#define S_5 %r14d
-#define S_6 %ebx
-#define S_7 %r9d
-
-#define SSE_REGs "%edi", "%esi", "%edx", "%ebx","%r8","%r9","%r10","%r11","%r12","%r13","%r14","%r15"
+#define _LOAD_DIGEST()                     \
+    "movl	  (%[sha256]), %%r8d \n\t" \
+    "movl	 4(%[sha256]), %%r9d \n\t" \
+    "movl	 8(%[sha256]), %%r10d\n\t" \
+    "movl	12(%[sha256]), %%r11d\n\t" \
+    "movl	16(%[sha256]), %%r12d\n\t" \
+    "movl	20(%[sha256]), %%r13d\n\t" \
+    "movl	24(%[sha256]), %%r14d\n\t" \
+    "movl	28(%[sha256]), %%r15d\n\t"
+
+#define _STORE_ADD_DIGEST()                \
+    "addl	%%r8d ,   (%[sha256])\n\t" \
+    "addl	%%r9d ,  4(%[sha256])\n\t" \
+    "addl	%%r10d,  8(%[sha256])\n\t" \
+    "addl	%%r11d, 12(%[sha256])\n\t" \
+    "addl	%%r12d, 16(%[sha256])\n\t" \
+    "addl	%%r13d, 20(%[sha256])\n\t" \
+    "addl	%%r14d, 24(%[sha256])\n\t" \
+    "addl	%%r15d, 28(%[sha256])\n\t"
+
+#define _ADD_DIGEST()                      \
+    "addl	  (%[sha256]), %%r8d \n\t" \
+    "addl	 4(%[sha256]), %%r9d \n\t" \
+    "addl	 8(%[sha256]), %%r10d\n\t" \
+    "addl	12(%[sha256]), %%r11d\n\t" \
+    "addl	16(%[sha256]), %%r12d\n\t" \
+    "addl	20(%[sha256]), %%r13d\n\t" \
+    "addl	24(%[sha256]), %%r14d\n\t" \
+    "addl	28(%[sha256]), %%r15d\n\t"
+
+#define _STORE_DIGEST()                    \
+    "movl	%%r8d ,   (%[sha256])\n\t" \
+    "movl	%%r9d ,  4(%[sha256])\n\t" \
+    "movl	%%r10d,  8(%[sha256])\n\t" \
+    "movl	%%r11d, 12(%[sha256])\n\t" \
+    "movl	%%r12d, 16(%[sha256])\n\t" \
+    "movl	%%r13d, 20(%[sha256])\n\t" \
+    "movl	%%r14d, 24(%[sha256])\n\t" \
+    "movl	%%r15d, 28(%[sha256])\n\t"
+
+#define LOAD_DIGEST() \
+    _LOAD_DIGEST()
+
+#define STORE_ADD_DIGEST() \
+    _STORE_ADD_DIGEST()
+
+#define ADD_DIGEST() \
+    _ADD_DIGEST()
+
+#define STORE_DIGEST() \
+    _STORE_DIGEST()
+
+
+#define S_0 %r8d
+#define S_1 %r9d
+#define S_2 %r10d
+#define S_3 %r11d
+#define S_4 %r12d
+#define S_5 %r13d
+#define S_6 %r14d
+#define S_7 %r15d
+
+#define L1  "%%edx"
+#define L2  "%%ecx"
+#define L3  "%%eax"
+#define L4  "%%ebx"
+#define WK  "%%rsp"
+
+#define WORK_REGS  "eax", "ebx", "ecx", "edx"
+#define STATE_REGS "r8","r9","r10","r11","r12","r13","r14","r15"
+#define XMM_REGS   "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",    \
+                   "xmm7", "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13"
 
 #if defined(HAVE_INTEL_RORX)
-#define RND_STEP_RORX_1(a,b,c,d,e,f,g,h,i) \
-    "# edx = e>>>6\n\t"                    \
-    "rorx	$6, %"#e", %%edx\n\t"
-
-#define RND_STEP_RORX_2(a,b,c,d,e,f,g,h,i) \
-    "# edi = e>>>11\n\t"                   \
-    "rorx	$11, %"#e",%%edi\n\t"      \
-    "# edi = (e>>11) ^ (e>>6)\n\t"         \
-    "xorl	%%edx, %%edi\n\t"          \
-    "# edx = e>>>25\n\t"                   \
-    "rorx	$25, %"#e", %%edx\n\t"
-
-#define RND_STEP_RORX_3(a,b,c,d,e,f,g,h,i) \
-    "# esi = f\n\t"                        \
-    "movl	%"#f", %%esi\n\t"          \
-    "# esi = f ^ g\n\t"                    \
-    "xorl	%"#g", %%esi\n\t"          \
-    "# edx = Sigma1(e)\n\t"                \
-    "xorl	%%edi, %%edx\n\t"          \
-    "# esi = (f ^ g) & e\n\t"              \
-    "andl	%"#e", %%esi\n\t"          \
-    "# esi = Ch(e,f,g)\n\t"                \
-    "xorl	%"#g", %%esi\n\t"
-
-#define RND_STEP_RORX_4(a,b,c,d,e,f,g,h,i) \
-    "# h += w_k\n\t"                       \
-    "leaq	%[W_K], %%r8\n\t"          \
-    "addl	("#i")*4(%%r8), %"#h"\n\t" \
-    "# h = h + w_k + Sigma1(e)\n\t"        \
-    "addl	%%edx, %"#h"\n\t"          \
-    "# r8d = a>>>2\n\t"                    \
-    "rorx	$2, %"#a", %%r8d\n\t"      \
-    "# edi = a>>>13\n\t"                   \
-    "rorx	$13, %"#a", %%edi\n\t"
-
-#define RND_STEP_RORX_5(a,b,c,d,e,f,g,h,i) \
-    "# edx = a>>22\n\t"                    \
-    "rorx	$22, %"#a", %%edx\n\t"     \
-    "# edi = (a>>>2) ^ (a>>>13)\n\t"       \
-    "xorl	%%r8d, %%edi\n\t"          \
-    "# edx = Sigma0(a)\n\t"                \
-    "xorl	%%edi, %%edx\n\t"
-
-#define RND_STEP_RORX_6(a,b,c,d,e,f,g,h,i) \
-    "# edi = b\n\t"                        \
-    "movl	%"#b", %%edi\n\t"          \
-    "# edi = a | b\n\t"                    \
-    "orl	%"#a", %%edi\n\t"          \
-    "# edi = (a | b) & c\n\t"              \
-    "andl	%"#c", %%edi\n\t"          \
-    "# r8d = b\n\t"                        \
-    "movl	%"#b", %%r8d\n\t"
-
-#define RND_STEP_RORX_7(a,b,c,d,e,f,g,h,i) \
-    "# h += Ch(e,f,g)\n\t"                 \
-    "addl	%%esi, %"#h"\n\t"          \
-    "# r8d = b & a\n\t"                    \
-    "andl	%"#a", %%r8d\n\t"          \
-    "# r8d = Maj(a,b,c)\n\t"               \
-    "orl	%%edi, %%r8d\n\t"
-
-#define RND_STEP_RORX_8(a,b,c,d,e,f,g,h,i)       \
-    "# d += h + w_k + Sigma1(e) + Ch(e,f,g)\n\t" \
+#define RND_STEP_RORX_0_1(a, b, c, d, e, f, g, h, i) \
+    /* L3 = f */                                     \
+    "movl	%" #f ", " L3 "\n\t"                 \
+    /* L2 = e>>>11 */                                \
+    "rorx	$11, %" #e ", " L2 "\n\t"            \
+    /* h += w_k */                                   \
+    "addl	(" #i ")*4(" WK "), %" #h "\n\t"     \
+
+#define RND_STEP_RORX_0_2(a, b, c, d, e, f, g, h, i) \
+    /* L2 = (e>>>6) ^ (e>>>11) */                    \
+    "xorl	" L1 ", " L2 "\n\t"                  \
+    /* L3 = f ^ g */                                 \
+    "xorl	%" #g ", " L3 "\n\t"                 \
+    /* L1 = e>>>25 */                                \
+    "rorx	$25, %" #e ", " L1 "\n\t"            \
+
+#define RND_STEP_RORX_0_3(a, b, c, d, e, f, g, h, i) \
+    /* L3 = (f ^ g) & e */                           \
+    "andl	%" #e ", " L3 "\n\t"                 \
+    /* L1 = Sigma1(e) */                             \
+    "xorl	" L2 ", " L1 "\n\t"                  \
+    /* L2 = a>>>13 */                                \
+    "rorx	$13, %" #a ", " L2 "\n\t"            \
+
+#define RND_STEP_RORX_0_4(a, b, c, d, e, f, g, h, i) \
+    /* h += Sigma1(e) */                             \
+    "addl	" L1 ", %" #h "\n\t"                 \
+    /* L1 = a>>>2 */                                 \
+    "rorx	$2, %" #a ", " L1 "\n\t"             \
+    /* L3 = Ch(e,f,g) */                             \
+    "xorl	%" #g ", " L3 "\n\t"                 \
+
+#define RND_STEP_RORX_0_5(a, b, c, d, e, f, g, h, i) \
+    /* L2 = (a>>>2) ^ (a>>>13) */                    \
+    "xorl	" L1 ", " L2 "\n\t"                  \
+    /* L1 = a>>>22 */                                \
+    "rorx	$22, %" #a ", " L1 "\n\t"            \
+    /* h += Ch(e,f,g) */                             \
+    "addl	" L3 ", %" #h "\n\t"                 \
+
+#define RND_STEP_RORX_0_6(a, b, c, d, e, f, g, h, i) \
+    /* L1 = Sigma0(a) */                             \
+    "xorl	" L2 ", " L1 "\n\t"                  \
+    /* L3 = b */                                     \
+    "movl	%" #b ", " L3 "\n\t"                 \
+    /* d += h + w_k + Sigma1(e) + Ch(e,f,g) */       \
+    "addl	%" #h ", %" #d "\n\t"                \
+
+#define RND_STEP_RORX_0_7(a, b, c, d, e, f, g, h, i) \
+    /* L3 = a ^ b */                                 \
+    "xorl	%" #a ", " L3 "\n\t"                 \
+    /* h += Sigma0(a) */                             \
+    "addl	" L1 ", %" #h "\n\t"                 \
+    /* L4 = (a ^ b) & (b ^ c) */                     \
+    "andl	" L3 ", " L4 "\n\t"                  \
+
+#define RND_STEP_RORX_0_8(a, b, c, d, e, f, g, h, i) \
+    /* L4 = Maj(a,b,c) */                            \
+    "xorl	%" #b ", " L4 "\n\t"                 \
+    /* L1 = d>>>6 (= e>>>6 next RND) */              \
+    "rorx	$6, %" #d ", " L1 "\n\t"             \
+    /* h += Maj(a,b,c) */                            \
+    "addl	" L4 ", %" #h "\n\t"                 \
+
+#define RND_STEP_RORX_1_1(a, b, c, d, e, f, g, h, i) \
+    /* L4 = f */                                     \
+    "movl	%" #f ", " L4 "\n\t"                 \
+    /* L2 = e>>>11 */                                \
+    "rorx	$11, %" #e ", " L2 "\n\t"            \
+    /* h += w_k */                                   \
+    "addl	(" #i ")*4(" WK "), %" #h "\n\t"     \
+
+#define RND_STEP_RORX_1_2(a, b, c, d, e, f, g, h, i) \
+    /* L2 = (e>>>6) ^ (e>>>11) */                    \
+    "xorl	" L1 ", " L2 "\n\t"                  \
+    /* L4 = f ^ g */                                 \
+    "xorl	%" #g ", " L4 "\n\t"                 \
+    /* L1 = e>>>25 */                                \
+    "rorx	$25, %" #e ", " L1 "\n\t"            \
+
+#define RND_STEP_RORX_1_3(a, b, c, d, e, f, g, h, i) \
+    /* L4 = (f ^ g) & e */                           \
+    "andl	%" #e ", " L4 "\n\t"                 \
+    /* L1 = Sigma1(e) */                             \
+    "xorl	" L2 ", " L1 "\n\t"                  \
+    /* L2 = a>>>13 */                                \
+    "rorx	$13, %" #a ", " L2 "\n\t"            \
+
+#define RND_STEP_RORX_1_4(a, b, c, d, e, f, g, h, i) \
+    /* h += Sigma1(e) */                             \
+    "addl	" L1 ", %" #h "\n\t"                 \
+    /* L1 = a>>>2 */                                 \
+    "rorx	$2, %" #a ", " L1 "\n\t"             \
+    /* L4 = Ch(e,f,g) */                             \
+    "xorl	%" #g ", " L4 "\n\t"                 \
+
+#define RND_STEP_RORX_1_5(a, b, c, d, e, f, g, h, i) \
+    /* L2 = (a>>>2) ^ (a>>>13) */                    \
+    "xorl	" L1 ", " L2 "\n\t"                  \
+    /* L1 = a>>>22 */                                \
+    "rorx	$22, %" #a ", " L1 "\n\t"            \
+    /* h += Ch(e,f,g) */                             \
+    "addl	" L4 ", %" #h "\n\t"                 \
+
+#define RND_STEP_RORX_1_6(a, b, c, d, e, f, g, h, i) \
+    /* L1 = Sigma0(a) */                             \
+    "xorl	" L2 ", " L1 "\n\t"                  \
+    /* L4 = b */                                     \
+    "movl	%" #b ", " L4 "\n\t"                 \
+    /* d += h + w_k + Sigma1(e) + Ch(e,f,g) */       \
     "addl	%"#h", %"#d"\n\t"                \
-    "addl	%"#h", %%r8d\n\t"                \
-    "addl	%%edx, %%r8d\n\t"                \
-    "movl	%%r8d, %"#h"\n\t"
+
+#define RND_STEP_RORX_1_7(a, b, c, d, e, f, g, h, i) \
+    /* L4 = a ^ b */                                 \
+    "xorl	%" #a ", " L4 "\n\t"                 \
+    /* h += Sigma0(a) */                             \
+    "addl	" L1 ", %" #h "\n\t"                 \
+    /* L3 = (a ^ b) & (b ^ c) */                     \
+    "andl	" L4 ", " L3 "\n\t"                  \
+
+#define RND_STEP_RORX_1_8(a, b, c, d, e, f, g, h, i) \
+    /* L3 = Maj(a,b,c) */                            \
+    "xorl	%" #b ", " L3 "\n\t"                 \
+    /* L1 = d>>>6 (= e>>>6 next RND) */              \
+    "rorx	$6, %" #d ", " L1 "\n\t"             \
+    /* h += Maj(a,b,c) */                            \
+    "addl	" L3 ", %" #h "\n\t"                 \
+
+#define _RND_RORX_X_0(a, b, c, d, e, f, g, h, i)     \
+    /* L1 = e>>>6 */                                 \
+    "rorx	$6, %" #e ", " L1 "\n\t"             \
+    /* L2 = e>>>11 */                                \
+    "rorx	$11, %" #e ", " L2 "\n\t"            \
+    /* Prev RND: h += Maj(a,b,c) */                  \
+    "addl	" L3 ", %" #a "\n\t"                 \
+    /* h += w_k */                                   \
+    "addl	(" #i ")*4(" WK "), %" #h "\n\t"     \
+    /* L3 = f */                                     \
+    "movl	%" #f ", " L3 "\n\t"                 \
+    /* L2 = (e>>>6) ^ (e>>>11) */                    \
+    "xorl	" L1 ", " L2 "\n\t"                  \
+    /* L3 = f ^ g */                                 \
+    "xorl	%" #g ", " L3 "\n\t"                 \
+    /* L1 = e>>>25 */                                \
+    "rorx	$25, %" #e ", " L1 "\n\t"            \
+    /* L1 = Sigma1(e) */                             \
+    "xorl	" L2 ", " L1 "\n\t"                  \
+    /* L3 = (f ^ g) & e */                           \
+    "andl	%" #e ", " L3 "\n\t"                 \
+    /* h += Sigma1(e) */                             \
+    "addl	" L1 ", %" #h "\n\t"                 \
+    /* L1 = a>>>2 */                                 \
+    "rorx	$2, %" #a ", " L1 "\n\t"             \
+    /* L2 = a>>>13 */                                \
+    "rorx	$13, %" #a ", " L2 "\n\t"            \
+    /* L3 = Ch(e,f,g) */                             \
+    "xorl	%" #g ", " L3 "\n\t"                 \
+    /* L2 = (a>>>2) ^ (a>>>13) */                    \
+    "xorl	" L1 ", " L2 "\n\t"                  \
+    /* L1 = a>>>22 */                                \
+    "rorx	$22, %" #a ", " L1 "\n\t"            \
+    /* h += Ch(e,f,g) */                             \
+    "addl	" L3 ", %" #h "\n\t"                 \
+    /* L1 = Sigma0(a) */                             \
+    "xorl	" L2 ", " L1 "\n\t"                  \
+    /* L3 = b */                                     \
+    "movl	%" #b ", " L3 "\n\t"                 \
+    /* d += h + w_k + Sigma1(e) + Ch(e,f,g) */       \
+    "addl	%" #h ", %" #d "\n\t"                \
+    /* L3 = a ^ b */                                 \
+    "xorl	%" #a ", " L3 "\n\t"                 \
+    /* L4 = (a ^ b) & (b ^ c) */                     \
+    "andl	" L3 ", " L4 "\n\t"                  \
+    /* h += Sigma0(a) */                             \
+    "addl	" L1 ", %" #h "\n\t"                 \
+    /* L4 = Maj(a,b,c) */                            \
+    "xorl	%" #b ", " L4 "\n\t"                 \
+
+#define _RND_RORX_X_1(a, b, c, d, e, f, g, h, i)     \
+    /* L1 = e>>>6 */                                 \
+    "rorx	$6, %" #e ", " L1 "\n\t"             \
+    /* L2 = e>>>11 */                                \
+    "rorx	$11, %" #e ", " L2 "\n\t"            \
+    /* Prev RND: h += Maj(a,b,c) */                  \
+    "addl	" L4 ", %" #a "\n\t"                 \
+    /* h += w_k */                                   \
+    "addl	(" #i ")*4(" WK "), %" #h "\n\t"     \
+    /* L4 = f */                                     \
+    "movl	%" #f ", " L4 "\n\t"                 \
+    /* L2 = (e>>>6) ^ (e>>>11) */                    \
+    "xorl	" L1 ", " L2 "\n\t"                  \
+    /* L4 = f ^ g */                                 \
+    "xorl	%" #g ", " L4 "\n\t"                 \
+    /* L1 = e>>>25 */                                \
+    "rorx	$25, %" #e ", " L1 "\n\t"            \
+    /* L1 = Sigma1(e) */                             \
+    "xorl	" L2 ", " L1 "\n\t"                  \
+    /* L4 = (f ^ g) & e */                           \
+    "andl	%" #e ", " L4 "\n\t"                 \
+    /* h += Sigma1(e) */                             \
+    "addl	" L1 ", %" #h "\n\t"                 \
+    /* L1 = a>>>2 */                                 \
+    "rorx	$2, %" #a ", " L1 "\n\t"             \
+    /* L2 = a>>>13 */                                \
+    "rorx	$13, %" #a ", " L2 "\n\t"            \
+    /* L4 = Ch(e,f,g) */                             \
+    "xorl	%" #g ", " L4 "\n\t"                 \
+    /* L2 = (a>>>2) ^ (a>>>13) */                    \
+    "xorl	" L1 ", " L2 "\n\t"                  \
+    /* L1 = a>>>22 */                                \
+    "rorx	$22, %" #a ", " L1 "\n\t"            \
+    /* h += Ch(e,f,g) */                             \
+    "addl	" L4 ", %" #h "\n\t"                 \
+    /* L1 = Sigma0(a) */                             \
+    "xorl	" L2 ", " L1 "\n\t"                  \
+    /* L4 = b */                                     \
+    "movl	%" #b ", " L4 "\n\t"                 \
+    /* d += h + w_k + Sigma1(e) + Ch(e,f,g) */       \
+    "addl	%" #h ", %" #d "\n\t"                \
+    /* L4 = a ^ b */                                 \
+    "xorl	%" #a ", " L4 "\n\t"                 \
+    /* L2 = (a ^ b) & (b ^ c) */                     \
+    "andl	" L4 ", " L3 "\n\t"                  \
+    /* h += Sigma0(a) */                             \
+    "addl	" L1 ", %" #h "\n\t"                 \
+    /* L3 = Maj(a,b,c) */                            \
+    "xorl	%" #b ", " L3 "\n\t"                 \
+
+
+#define RND_RORX_X_0(a,b,c,d,e,f,g,h,i) \
+       _RND_RORX_X_0(a,b,c,d,e,f,g,h,i)
+#define RND_RORX_X_1(a,b,c,d,e,f,g,h,i) \
+       _RND_RORX_X_1(a,b,c,d,e,f,g,h,i)
+
+#define RND_RORX_X4(a,b,c,d,e,f,g,h,i)    \
+        RND_RORX_X_0(a,b,c,d,e,f,g,h,i+0) \
+        RND_RORX_X_1(h,a,b,c,d,e,f,g,i+1) \
+        RND_RORX_X_0(g,h,a,b,c,d,e,f,i+2) \
+        RND_RORX_X_1(f,g,h,a,b,c,d,e,i+3)
+
 #endif /* HAVE_INTEL_RORX */
 
-#define RND_STEP_1(a,b,c,d,e,f,g,h,i) \
-    "movl	%"#e", %%edx\n\t"     \
-    "# edx = e>>>6\n\t"               \
-    "roll	$26, %%edx\n\t"       \
-    "movl	%"#e", %%edi\n\t"
-
-#define RND_STEP_2(a,b,c,d,e,f,g,h,i) \
-    "# edi = e>>>11\n\t"              \
-    "roll	$21, %%edi\n\t"       \
-    "# edi = (e>>11) ^ (e>>6)\n\t"    \
-    "xorl	%%edx, %%edi\n\t"     \
-    "# edx = e\n\t"                   \
-    "movl	%"#e", %%edx\n\t"     \
-    "# edx = e>>>25\n\t"              \
-    "roll	$7, %%edx\n\t"
-
-#define RND_STEP_3(a,b,c,d,e,f,g,h,i) \
-    "# esi = f\n\t"                   \
-    "movl	%"#f", %%esi\n\t"     \
-    "# esi = f ^ g\n\t"               \
-    "xorl	%"#g", %%esi\n\t"     \
-    "# edx = Sigma1(e)\n\t"           \
-    "xorl	%%edi, %%edx\n\t"     \
-    "# esi = (f ^ g) & e\n\t"         \
-    "andl	%"#e", %%esi\n\t"     \
-    "# esi = Ch(e,f,g)\n\t"           \
-    "xorl	%"#g", %%esi\n\t"
-
-#define RND_STEP_4(a,b,c,d,e,f,g,h,i)      \
-    "# h += w_k\n\t"                       \
-    "leaq	%[W_K], %%r8\n\t"          \
-    "addl	("#i")*4(%%r8), %"#h"\n\t" \
-    "# h = h + w_k + Sigma1(e)\n\t"        \
-    "addl	%%edx, %"#h"\n\t"          \
-    "# r8d = a\n\t"                        \
-    "movl	%"#a", %%r8d\n\t"          \
-    "# r8d = a>>>2\n\t"                    \
-    "roll	$30, %%r8d\n\t"            \
-    "# edi = a\n\t"                        \
-    "movl	%"#a", %%edi\n\t"          \
-    "# edi = a>>>13\n\t"                   \
-    "roll	$19, %%edi\n\t"            \
-    "# edx = a\n\t"                        \
-    "movl	%"#a", %%edx\n\t"
-
-#define RND_STEP_5(a,b,c,d,e,f,g,h,i) \
-    "# edx = a>>>22\n\t"              \
-    "roll	$10, %%edx\n\t"       \
-    "# edi = (a>>>2) ^ (a>>>13)\n\t"  \
-    "xorl	%%r8d, %%edi\n\t"     \
-    "# edx = Sigma0(a)\n\t"           \
-    "xorl	%%edi, %%edx\n\t"
-
-#define RND_STEP_6(a,b,c,d,e,f,g,h,i) \
-    "# edi = b\n\t"                   \
-    "movl	%"#b", %%edi\n\t"     \
-    "# edi = a | b\n\t"               \
-    "orl	%"#a", %%edi\n\t"     \
-    "# edi = (a | b) & c\n\t"         \
-    "andl	%"#c", %%edi\n\t"     \
-    "# r8d = b\n\t"                   \
-    "movl	%"#b", %%r8d\n\t"
-
-#define RND_STEP_7(a,b,c,d,e,f,g,h,i) \
-    "# h += Ch(e,f,g)\n\t"            \
-    "addl	%%esi, %"#h"\n\t"     \
-    "#r8d = b & a\n\t"                \
-    "andl	%"#a", %%r8d\n\t"     \
-    "# r8d = Maj(a,b,c)\n\t"          \
-    "orl	%%edi, %%r8d\n\t"
-
-#define RND_STEP_8(a,b,c,d,e,f,g,h,i)                                    \
-    "# d += h + w_k + Sigma1(e) + Ch(e,f,g)\n\t"                         \
+#define RND_STEP_0_1(a,b,c,d,e,f,g,h,i)                               \
+    /* L1 = e>>>14 */                                                 \
+    "rorl	$14, " L1 "\n\t"                                      \
+
+#define RND_STEP_0_2(a,b,c,d,e,f,g,h,i)                               \
+    /* L3 = b */                                                      \
+    "movl	%" #b ", " L3 "\n\t"                                  \
+    /* L2 = f */                                                      \
+    "movl	%" #f ", " L2 "\n\t"                                  \
+    /* h += w_k */                                                    \
+    "addl	(" #i ")*4(" WK "), %" #h "\n\t"                      \
+    /* L2 = f ^ g */                                                  \
+    "xorl	%" #g ", " L2 "\n\t"                                  \
+
+#define RND_STEP_0_3(a,b,c,d,e,f,g,h,i)                               \
+    /* L1 = (e>>>14) ^ e */                                           \
+    "xorl	%" #e ", " L1 "\n\t"                                  \
+    /* L2 = (f ^ g) & e */                                            \
+    "andl	%" #e ", " L2 "\n\t"                                  \
+
+#define RND_STEP_0_4(a,b,c,d,e,f,g,h,i)                               \
+    /* L1 = ((e>>>14) ^ e) >>> 5 */                                   \
+    "rorl	$5, " L1 "\n\t"                                       \
+    /* L2 = Ch(e,f,g) */                                              \
+    "xorl	%" #g ", " L2 "\n\t"                                  \
+    /* L1 = (((e>>>14) ^ e) >>> 5) ^ e */                             \
+    "xorl	%" #e ", " L1 "\n\t"                                  \
+    /* h += Ch(e,f,g) */                                              \
+    "addl	" L2 ", %" #h "\n\t"                                  \
+
+#define RND_STEP_0_5(a,b,c,d,e,f,g,h,i)                               \
+    /* L1 = ((((e>>>14) ^ e) >>> 5) ^ e) >>> 6 */                     \
+    "rorl	$6, " L1 "\n\t"                                       \
+    /* L3 = a ^ b (= b ^ c of next RND) */                            \
+    "xorl	%" #a ", " L3 "\n\t"                                  \
+    /* h = h + w_k + Sigma1(e) */                                     \
+    "addl	" L1 ", %" #h "\n\t"                                  \
+    /* L2 = a */                                                      \
+    "movl	%" #a ", " L2 "\n\t"                                  \
+
+#define RND_STEP_0_6(a,b,c,d,e,f,g,h,i)                               \
+    /* L3 = (a ^ b) & (b ^ c) */                                      \
+    "andl	" L3 ", " L4 "\n\t"                                   \
+    /* L2 = a>>>9 */                                                  \
+    "rorl	$9, " L2 "\n\t"                                       \
+    /* L2 = (a>>>9) ^ a */                                            \
+    "xorl	%" #a ", " L2 "\n\t"                                  \
+    /* L1 = Maj(a,b,c) */                                             \
+    "xorl	%" #b ", " L4 "\n\t"                                  \
+
+#define RND_STEP_0_7(a,b,c,d,e,f,g,h,i)                               \
+    /* L2 = ((a>>>9) ^ a) >>> 11 */                                   \
+    "rorl	$11, " L2 "\n\t"                                      \
+    /* d += h + w_k + Sigma1(e) + Ch(e,f,g) */                        \
+    "addl	%" #h ", %" #d "\n\t"                                 \
+    /* L2 = (((a>>>9) ^ a) >>> 11) ^ a */                             \
+    "xorl	%" #a ", " L2 "\n\t"                                  \
+    /* h = h + w_k + Sigma1(e) + Ch(e,f,g) + Maj(a,b,c) */            \
+    "addl	" L4 ", %" #h "\n\t"                                  \
+
+#define RND_STEP_0_8(a,b,c,d,e,f,g,h,i)                               \
+    /* L2 = ((((a>>>9) ^ a) >>> 11) ^ a) >>> 2 */                     \
+    "rorl	$2, " L2 "\n\t"                                       \
+    /* L1 = d (e of next RND) */                                      \
+    "movl	%" #d ", " L1 "\n\t"                                  \
+    /* h = h + w_k + Sigma1(e) Sigma0(a) + Ch(e,f,g) + Maj(a,b,c) */  \
+    "addl	" L2 ", %" #h "\n\t"                                  \
+
+#define RND_STEP_1_1(a,b,c,d,e,f,g,h,i)                               \
+    /* L1 = e>>>14 */                                                 \
+    "rorl	$14, " L1 "\n\t"                                      \
+
+#define RND_STEP_1_2(a,b,c,d,e,f,g,h,i)                               \
+    /* L3 = b */                                                      \
+    "movl	%" #b ", " L4 "\n\t"                                  \
+    /* L2 = f */                                                      \
+    "movl	%" #f ", " L2 "\n\t"                                  \
+    /* h += w_k */                                                    \
+    "addl	(" #i ")*4(" WK "), %" #h "\n\t"                      \
+    /* L2 = f ^ g */                                                  \
+    "xorl	%" #g ", " L2 "\n\t"                                  \
+
+#define RND_STEP_1_3(a,b,c,d,e,f,g,h,i)                               \
+    /* L1 = (e>>>14) ^ e */                                           \
+    "xorl	%" #e ", " L1 "\n\t"                                  \
+    /* L2 = (f ^ g) & e */                                            \
+    "andl	%" #e ", " L2 "\n\t"                                  \
+
+#define RND_STEP_1_4(a,b,c,d,e,f,g,h,i)                               \
+    /* L1 = ((e>>>14) ^ e) >>> 5 */                                   \
+    "rorl	$5, " L1 "\n\t"                                       \
+    /* L2 = Ch(e,f,g) */                                              \
+    "xorl	%" #g ", " L2 "\n\t"                                  \
+    /* L1 = (((e>>>14) ^ e) >>> 5) ^ e */                             \
+    "xorl	%" #e ", " L1 "\n\t"                                  \
+    /* h += Ch(e,f,g) */                                              \
+    "addl	" L2 ", %" #h "\n\t"                                  \
+
+#define RND_STEP_1_5(a,b,c,d,e,f,g,h,i)                               \
+    /* L1 = ((((e>>>14) ^ e) >>> 5) ^ e) >>> 6 */                     \
+    "rorl	$6, " L1 "\n\t"                                       \
+    /* L4 = a ^ b (= b ^ c of next RND) */                            \
+    "xorl	%" #a ", " L4 "\n\t"                                  \
+    /* h = h + w_k + Sigma1(e) */                                     \
+    "addl	" L1 ", %" #h "\n\t"                                  \
+    /* L2 = a */                                                      \
+    "movl	%" #a ", " L2 "\n\t"                                  \
+
+#define RND_STEP_1_6(a,b,c,d,e,f,g,h,i)                               \
+    /* L3 = (a ^ b) & (b ^ c)  */                                     \
+    "andl	" L4 ", " L3 "\n\t"                                   \
+    /* L2 = a>>>9 */                                                  \
+    "rorl	$9, " L2 "\n\t"                                       \
+    /* L2 = (a>>>9) ^ a */                                            \
+    "xorl	%" #a ", " L2 "\n\t"                                  \
+    /* L1 = Maj(a,b,c) */                                             \
+    "xorl	%" #b ", " L3 "\n\t"                                  \
+
+#define RND_STEP_1_7(a,b,c,d,e,f,g,h,i)                               \
+    /* L2 = ((a>>>9) ^ a) >>> 11 */                                   \
+    "rorl	$11, " L2 "\n\t"                                      \
+    /* d += h + w_k + Sigma1(e) + Ch(e,f,g) */                        \
+    "addl	%" #h ", %" #d "\n\t"                                 \
+    /* L2 = (((a>>>9) ^ a) >>> 11) ^ a */                             \
+    "xorl	%" #a ", " L2 "\n\t"                                  \
+    /* h = h + w_k + Sigma1(e) + Ch(e,f,g) + Maj(a,b,c) */            \
+    "addl	" L3 ", %" #h "\n\t"                                  \
+
+#define RND_STEP_1_8(a,b,c,d,e,f,g,h,i)                               \
+    /* L2 = ((((a>>>9) ^ a) >>> 11) ^ a) >>> 2 */                     \
+    "rorl	$2, " L2 "\n\t"                                       \
+    /* L1 = d (e of next RND) */                                      \
+    "movl	%" #d ", " L1 "\n\t"                                  \
+    /* h = h + w_k + Sigma1(e) Sigma0(a) + Ch(e,f,g) + Maj(a,b,c) */  \
+    "addl	" L2 ", %" #h "\n\t"                                  \
+
+#define _RND_ALL_0(a,b,c,d,e,f,g,h,i)                                 \
+    /* h += w_k */                                                    \
+    "addl	(" #i ")*4(" WK "), %" #h "\n\t"                      \
+    /* L2 = f */                                                      \
+    "movl	%" #f ", " L2 "\n\t"                                  \
+    /* L3 = b */                                                      \
+    "movl	%" #b ", " L3 "\n\t"                                  \
+    /* L2 = f ^ g */                                                  \
+    "xorl	%" #g ", " L2 "\n\t"                                  \
+    /* L1 = e>>>14 */                                                 \
+    "rorl	$14, " L1 "\n\t"                                      \
+    /* L2 = (f ^ g) & e */                                            \
+    "andl	%" #e ", " L2 "\n\t"                                  \
+    /* L1 = (e>>>14) ^ e */                                           \
+    "xorl	%" #e ", " L1 "\n\t"                                  \
+    /* L2 = Ch(e,f,g) */                                              \
+    "xorl	%" #g ", " L2 "\n\t"                                  \
+    /* L1 = ((e>>>14) ^ e) >>> 5 */                                   \
+    "rorl	$5, " L1 "\n\t"                                       \
+    /* h += Ch(e,f,g) */                                              \
+    "addl	" L2 ", %" #h "\n\t"                                  \
+    /* L1 = (((e>>>14) ^ e) >>> 5) ^ e */                             \
+    "xorl	%" #e ", " L1 "\n\t"                                  \
+    /* L3 = a ^ b */                                                  \
+    "xorl	%" #a ", " L3 "\n\t"                                  \
+    /* L1 = ((((e>>>14) ^ e) >>> 5) ^ e) >>> 6 */                     \
+    "rorl	$6, " L1 "\n\t"                                       \
+    /* L2 = a */                                                      \
+    "movl	%" #a ", " L2 "\n\t"                                  \
+    /* h = h + w_k + Sigma1(e) */                                     \
+    "addl	" L1 ", %" #h "\n\t"                                  \
+    /* L2 = a>>>9 */                                                  \
+    "rorl	$9, " L2 "\n\t"                                       \
+    /* L3 = (a ^ b) & (b ^ c) */                                      \
+    "andl	" L3 ", " L4 "\n\t"                                   \
+    /* L2 = (a>>>9) ^ a */                                            \
+    "xorl	%" #a ", " L2 "\n\t"                                  \
+    /* L1 = Maj(a,b,c) */                                             \
+    "xorl	%" #b ", " L4 "\n\t"                                  \
+    /* L2 = ((a>>>9) ^ a) >>> 11 */                                   \
+    "rorl	$11, " L2 "\n\t"                                      \
+    /* d += h + w_k + Sigma1(e) + Ch(e,f,g) */                        \
+    "addl	%" #h ", %" #d "\n\t"                                 \
+    /* L2 = (((a>>>9) ^ a) >>> 11) ^ a */                             \
+    "xorl	%" #a ", " L2 "\n\t"                                  \
+    /* h = h + w_k + Sigma1(e) + Ch(e,f,g) + Maj(a,b,c) */            \
+    "addl	" L4 ", %" #h "\n\t"                                  \
+    /* L2 = ((((a>>>9) ^ a) >>> 11) ^ a) >>> 2 */                     \
+    "rorl	$2, " L2 "\n\t"                                       \
+    /* L1 = d (e of next RND) */                                      \
+    "movl	%" #d ", " L1 "\n\t"                                  \
+    /* h = h + w_k + Sigma1(e) Sigma0(a) + Ch(e,f,g) + Maj(a,b,c) */  \
+    "addl	" L2 ", %" #h "\n\t"                                  \
+
+#define _RND_ALL_1(a,b,c,d,e,f,g,h,i)                                 \
+    /* h += w_k */                                                    \
+    "addl	(" #i ")*4(" WK "), %" #h "\n\t"                      \
+    /* L2 = f */                                                      \
+    "movl	%" #f ", " L2 "\n\t"                                  \
+    /* L3 = b */                                                      \
+    "movl	%" #b ", " L4 "\n\t"                                  \
+    /* L2 = f ^ g */                                                  \
+    "xorl	%" #g ", " L2 "\n\t"                                  \
+    /* L1 = e>>>14 */                                                 \
+    "rorl	$14, " L1 "\n\t"                                      \
+    /* L2 = (f ^ g) & e */                                            \
+    "andl	%" #e ", " L2 "\n\t"                                  \
+    /* L1 = (e>>>14) ^ e */                                           \
+    "xorl	%" #e ", " L1 "\n\t"                                  \
+    /* L2 = Ch(e,f,g) */                                              \
+    "xorl	%" #g ", " L2 "\n\t"                                  \
+    /* L1 = ((e>>>14) ^ e) >>> 5 */                                   \
+    "rorl	$5, " L1 "\n\t"                                       \
+    /* h += Ch(e,f,g) */                                              \
+    "addl	" L2 ", %" #h "\n\t"                                  \
+    /* L1 = (((e>>>14) ^ e) >>> 5) ^ e */                             \
+    "xorl	%" #e ", " L1 "\n\t"                                  \
+    /* L3 = a ^ b */                                                  \
+    "xorl	%" #a ", " L4 "\n\t"                                  \
+    /* L1 = ((((e>>>14) ^ e) >>> 5) ^ e) >>> 6 */                     \
+    "rorl	$6, " L1 "\n\t"                                       \
+    /* L2 = a */                                                      \
+    "movl	%" #a ", " L2 "\n\t"                                  \
+    /* h = h + w_k + Sigma1(e) */                                     \
+    "addl	" L1 ", %" #h "\n\t"                                  \
+    /* L2 = a>>>9 */                                                  \
+    "rorl	$9, " L2 "\n\t"                                       \
+    /* L3 = (a ^ b) & (b ^ c)  */                                     \
+    "andl	" L4 ", " L3 "\n\t"                                   \
+    /* L2 = (a>>>9) ^ a */                                            \
+    "xorl	%" #a", " L2 "\n\t"                                   \
+    /* L1 = Maj(a,b,c) */                                             \
+    "xorl	%" #b ", " L3 "\n\t"                                  \
+    /* L2 = ((a>>>9) ^ a) >>> 11 */                                   \
+    "rorl	$11, " L2 "\n\t"                                      \
+    /* d += h + w_k + Sigma1(e) + Ch(e,f,g) */                        \
     "addl	%"#h", %"#d"\n\t"                                        \
-    "# r8b = h + w_k + Sigma1(e) + Ch(e,f,g) + Maj(a,b,c)\n\t"           \
-    "addl	%"#h", %%r8d\n\t"                                        \
-    "# r8b = h + w_k + Sigma1(e) Sigma0(a) + Ch(e,f,g) + Maj(a,b,c)\n\t" \
-    "addl	%%edx, %%r8d\n\t"                                        \
-    "# h = h + w_k + Sigma1(e) + Sigma0(a) + Ch(e,f,g) + Maj(a,b,c)\n\t" \
-    "movl	%%r8d, %"#h"\n\t"
-
-#define RND_X(a,b,c,d,e,f,g,h,i) \
-       RND_STEP_1(a,b,c,d,e,f,g,h,i) \
-       RND_STEP_2(a,b,c,d,e,f,g,h,i) \
-       RND_STEP_3(a,b,c,d,e,f,g,h,i) \
-       RND_STEP_4(a,b,c,d,e,f,g,h,i) \
-       RND_STEP_5(a,b,c,d,e,f,g,h,i) \
-       RND_STEP_6(a,b,c,d,e,f,g,h,i) \
-       RND_STEP_7(a,b,c,d,e,f,g,h,i) \
-       RND_STEP_8(a,b,c,d,e,f,g,h,i)
-
-#define RND_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_X(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i)
-#define RND_7(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_X(S_7,S_0,S_1,S_2,S_3,S_4,S_5,S_6,_i)
-#define RND_6(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_X(S_6,S_7,S_0,S_1,S_2,S_3,S_4,S_5,_i)
-#define RND_5(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_X(S_5,S_6,S_7,S_0,S_1,S_2,S_3,S_4,_i)
-#define RND_4(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_X(S_4,S_5,S_6,S_7,S_0,S_1,S_2,S_3,_i)
-#define RND_3(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_X(S_3,S_4,S_5,S_6,S_7,S_0,S_1,S_2,_i)
-#define RND_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_X(S_2,S_3,S_4,S_5,S_6,S_7,S_0,S_1,_i)
-#define RND_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_X(S_1,S_2,S_3,S_4,S_5,S_6,S_7,S_0,_i)
-
-
-#define RND_1_3(a,b,c,d,e,f,g,h,i) \
-       RND_STEP_1(a,b,c,d,e,f,g,h,i) \
-       RND_STEP_2(a,b,c,d,e,f,g,h,i) \
-       RND_STEP_3(a,b,c,d,e,f,g,h,i)
-
-#define RND_4_6(a,b,c,d,e,f,g,h,i) \
-       RND_STEP_4(a,b,c,d,e,f,g,h,i) \
-       RND_STEP_5(a,b,c,d,e,f,g,h,i) \
-       RND_STEP_6(a,b,c,d,e,f,g,h,i)
-
-#define RND_7_8(a,b,c,d,e,f,g,h,i) \
-       RND_STEP_7(a,b,c,d,e,f,g,h,i) \
-       RND_STEP_8(a,b,c,d,e,f,g,h,i)
-
-#define RND_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_X(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i)
-#define RND_7(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_X(S_7,S_0,S_1,S_2,S_3,S_4,S_5,S_6,_i)
-#define RND_6(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_X(S_6,S_7,S_0,S_1,S_2,S_3,S_4,S_5,_i)
-#define RND_5(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_X(S_5,S_6,S_7,S_0,S_1,S_2,S_3,S_4,_i)
-#define RND_4(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_X(S_4,S_5,S_6,S_7,S_0,S_1,S_2,S_3,_i)
-#define RND_3(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_X(S_3,S_4,S_5,S_6,S_7,S_0,S_1,S_2,_i)
-#define RND_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_X(S_2,S_3,S_4,S_5,S_6,S_7,S_0,S_1,_i)
-#define RND_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_X(S_1,S_2,S_3,S_4,S_5,S_6,S_7,S_0,_i)
-
-
-#define RND_0_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_1_3(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i)
-#define RND_7_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_1_3(S_7,S_0,S_1,S_2,S_3,S_4,S_5,S_6,_i)
-#define RND_6_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_1_3(S_6,S_7,S_0,S_1,S_2,S_3,S_4,S_5,_i)
-#define RND_5_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_1_3(S_5,S_6,S_7,S_0,S_1,S_2,S_3,S_4,_i)
-#define RND_4_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_1_3(S_4,S_5,S_6,S_7,S_0,S_1,S_2,S_3,_i)
-#define RND_3_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_1_3(S_3,S_4,S_5,S_6,S_7,S_0,S_1,S_2,_i)
-#define RND_2_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_1_3(S_2,S_3,S_4,S_5,S_6,S_7,S_0,S_1,_i)
-#define RND_1_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_1_3(S_1,S_2,S_3,S_4,S_5,S_6,S_7,S_0,_i)
-
-#define RND_0_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_4_6(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i)
-#define RND_7_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_4_6(S_7,S_0,S_1,S_2,S_3,S_4,S_5,S_6,_i)
-#define RND_6_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_4_6(S_6,S_7,S_0,S_1,S_2,S_3,S_4,S_5,_i)
-#define RND_5_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_4_6(S_5,S_6,S_7,S_0,S_1,S_2,S_3,S_4,_i)
-#define RND_4_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_4_6(S_4,S_5,S_6,S_7,S_0,S_1,S_2,S_3,_i)
-#define RND_3_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_4_6(S_3,S_4,S_5,S_6,S_7,S_0,S_1,S_2,_i)
-#define RND_2_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_4_6(S_2,S_3,S_4,S_5,S_6,S_7,S_0,S_1,_i)
-#define RND_1_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_4_6(S_1,S_2,S_3,S_4,S_5,S_6,S_7,S_0,_i)
-
-#define RND_0_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_7_8(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i)
-#define RND_7_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_7_8(S_7,S_0,S_1,S_2,S_3,S_4,S_5,S_6,_i)
-#define RND_6_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_7_8(S_6,S_7,S_0,S_1,S_2,S_3,S_4,S_5,_i)
-#define RND_5_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_7_8(S_5,S_6,S_7,S_0,S_1,S_2,S_3,S_4,_i)
-#define RND_4_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_7_8(S_4,S_5,S_6,S_7,S_0,S_1,S_2,S_3,_i)
-#define RND_3_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_7_8(S_3,S_4,S_5,S_6,S_7,S_0,S_1,S_2,_i)
-#define RND_2_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_7_8(S_2,S_3,S_4,S_5,S_6,S_7,S_0,S_1,_i)
-#define RND_1_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,_i) RND_7_8(S_1,S_2,S_3,S_4,S_5,S_6,S_7,S_0,_i)
-
-#define FOR(cnt, init, max, inc, loop)  \
-    __asm__ volatile("movl $"#init", %0\n\t"#loop":"::"m"(cnt):)
-#define END(cnt, init, max, inc, loop)  \
-    __asm__ volatile("addl $"#inc", %0\n\tcmpl $"#max", %0\n\tjle "#loop"\n\t":"=m"(cnt)::);
+    /* L2 = (((a>>>9) ^ a) >>> 11) ^ a */                             \
+    "xorl	%" #a ", " L2 "\n\t"                                  \
+    /* h = h + w_k + Sigma1(e) + Ch(e,f,g) + Maj(a,b,c) */            \
+    "addl	" L3 ", %" #h "\n\t"                                  \
+    /* L2 = ((((a>>>9) ^ a) >>> 11) ^ a) >>> 2 */                     \
+    "rorl	$2, " L2 "\n\t"                                       \
+    /* L1 = d (e of next RND) */                                      \
+    "movl	%" #d ", " L1 "\n\t"                                  \
+    /* h = h + w_k + Sigma1(e) Sigma0(a) + Ch(e,f,g) + Maj(a,b,c) */  \
+    "addl	" L2 ", %" #h "\n\t"                                  \
+
+
+#define RND_ALL_0(a, b, c, d, e, f, g, h, i) \
+       _RND_ALL_0(a, b, c, d, e, f, g, h, i)
+#define RND_ALL_1(a, b, c, d, e, f, g, h, i) \
+       _RND_ALL_1(a, b, c, d, e, f, g, h, i)
+
+#define RND_ALL_4(a, b, c, d, e, f, g, h, i)   \
+        RND_ALL_0(a, b, c, d, e, f, g, h, i+0) \
+        RND_ALL_1(h, a, b, c, d, e, f, g, i+1) \
+        RND_ALL_0(g, h, a, b, c, d, e, f, i+2) \
+        RND_ALL_1(f, g, h, a, b, c, d, e, i+3)
 
 #endif  /* defined(HAVE_INTEL_AVX1) ||  defined(HAVE_INTEL_AVX2) */
@@ -1063,204 +1433,234 @@
 #if defined(HAVE_INTEL_AVX1) /* inline Assember for Intel AVX1 instructions */
 
-#define VPALIGNR(op1,op2,op3,op4) \
+#define _VPALIGNR(op1, op2, op3, op4)                    \
     "vpalignr	$"#op4", %"#op3", %"#op2", %"#op1"\n\t"
-#define VPADDD(op1,op2,op3)       \
+#define VPALIGNR(op1, op2, op3, op4)                     \
+        _VPALIGNR(op1, op2, op3, op4)
+#define _VPADDD(op1, op2, op3)                           \
     "vpaddd	%"#op3", %"#op2", %"#op1"\n\t"
-#define VPSRLD(op1,op2,op3)       \
+#define VPADDD(op1, op2, op3)                            \
+       _VPADDD(op1, op2, op3)
+#define _VPSRLD(op1, op2, op3)                           \
     "vpsrld	$"#op3", %"#op2", %"#op1"\n\t"
-#define VPSRLQ(op1,op2,op3)       \
+#define VPSRLD(op1, op2, op3)        \
+       _VPSRLD(op1, op2, op3)
+#define _VPSRLQ(op1, op2, op3)                           \
     "vpsrlq	$"#op3", %"#op2", %"#op1"\n\t"
-#define VPSLLD(op1,op2,op3)       \
+#define VPSRLQ(op1,op2,op3)        \
+       _VPSRLQ(op1,op2,op3)
+#define _VPSLLD(op1,op2,op3)                             \
     "vpslld	$"#op3", %"#op2", %"#op1"\n\t"
-#define VPOR(op1,op2,op3)         \
+#define VPSLLD(op1,op2,op3)        \
+       _VPSLLD(op1,op2,op3)
+#define _VPOR(op1,op2,op3)                               \
     "vpor	%"#op3", %"#op2", %"#op1"\n\t"
-#define VPXOR(op1,op2,op3)        \
+#define VPOR(op1,op2,op3)          \
+       _VPOR(op1,op2,op3)
+#define _VPXOR(op1,op2,op3)                              \
     "vpxor	%"#op3", %"#op2", %"#op1"\n\t"
-#define VPSHUFD(op1,op2,op3)      \
+#define VPXOR(op1,op2,op3)         \
+       _VPXOR(op1,op2,op3)
+#define _VPSHUFD(op1,op2,op3)                            \
     "vpshufd	$"#op3", %"#op2", %"#op1"\n\t"
-#define VPSHUFB(op1,op2,op3)      \
+#define VPSHUFD(op1,op2,op3)       \
+       _VPSHUFD(op1,op2,op3)
+#define _VPSHUFB(op1,op2,op3)                            \
     "vpshufb	%"#op3", %"#op2", %"#op1"\n\t"
-
-#define MessageSched(X0, X1, X2, X3, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5, XFER, SHUF_00BA, SHUF_DC00,\
-     a,b,c,d,e,f,g,h,_i)\
-            RND_STEP_1(a,b,c,d,e,f,g,h,_i)\
+#define VPSHUFB(op1,op2,op3)       \
+       _VPSHUFB(op1,op2,op3)
+#define _VPSLLDQ(op1,op2,op3)                            \
+    "vpslldq	$" #op3", %" #op2", %" #op1"\n\t"
+#define VPSLLDQ(op1,op2,op3)       \
+       _VPSLLDQ(op1,op2,op3)
+
+#define MsgSched(X0,X1,X2,X3,a,b,c,d,e,f,g,h,_i)                           \
+            RND_STEP_0_1(a,b,c,d,e,f,g,h,_i)                               \
+    VPALIGNR (XTMP1, X1, X0, 4)   /* XTMP1 = W[-15] */\
+    VPALIGNR (XTMP0, X3, X2, 4)    /* XTMP0 = W[-7] */                     \
+            RND_STEP_0_2(a,b,c,d,e,f,g,h,_i)                               \
+            RND_STEP_0_3(a,b,c,d,e,f,g,h,_i)                               \
+    VPSRLD   (XTMP2, XTMP1, 7)     /* XTMP2 = W[-15] >> 7 */               \
+    VPSLLD   (XTMP3, XTMP1, 25)    /* XTEMP3 = W[-15] << (32-7) */         \
+            RND_STEP_0_4(a,b,c,d,e,f,g,h,_i)                               \
+            RND_STEP_0_5(a,b,c,d,e,f,g,h,_i)                               \
+    VPSRLD   (XTMP4, XTMP1, 18)    /* XTEMP4 = W[-15] >> 18 */             \
+    VPSLLD   (XTMP5, XTMP1, 14)    /* XTEMP5 = W[-15] << (32-18) */        \
+            RND_STEP_0_6(a,b,c,d,e,f,g,h,_i)                               \
+            RND_STEP_0_7(a,b,c,d,e,f,g,h,_i)                               \
+    VPOR     (XTMP2, XTMP3, XTMP2) /* XTMP2 = W[-15] >>> 7 */              \
+    VPOR     (XTMP4, XTMP5, XTMP4) /* XTMP4 = W[-15] >>> 18 */             \
+            RND_STEP_0_8(a,b,c,d,e,f,g,h,_i)                               \
+            RND_STEP_1_1(h,a,b,c,d,e,f,g,_i+1)                             \
+            RND_STEP_1_2(h,a,b,c,d,e,f,g,_i+1)                             \
+    VPSRLD   (XTMP5, XTMP1, 3)     /* XTMP4 = W[-15] >> 3 */               \
+    VPXOR    (XTMP2, XTMP4, XTMP2)                                         \
+                          /* XTMP2 = W[-15] MY_ROR 7 ^ W[-15] MY_ROR 18 */ \
+            RND_STEP_1_3(h,a,b,c,d,e,f,g,_i+1)                             \
+            RND_STEP_1_4(h,a,b,c,d,e,f,g,_i+1)                             \
+    VPXOR    (XTMP1, XTMP5, XTMP2)  /* XTMP1 = s0 */                       \
+    VPSHUFD(XTMP2, X3, 0b11111010)  /* XTMP2 = W[-2] {BBAA}*/\
+            RND_STEP_1_5(h,a,b,c,d,e,f,g,_i+1)                             \
+            RND_STEP_1_6(h,a,b,c,d,e,f,g,_i+1)                             \
+    VPSRLD   (XTMP4, XTMP2, 10)      /* XTMP4 = W[-2] >> 10 {BBAA} */\
+    VPSRLQ   (XTMP3, XTMP2, 19)      /* XTMP3 = W[-2] MY_ROR 19 {xBxA} */\
+            RND_STEP_1_7(h,a,b,c,d,e,f,g,_i+1)                             \
+            RND_STEP_1_8(h,a,b,c,d,e,f,g,_i+1)                             \
+            RND_STEP_0_1(g,h,a,b,c,d,e,f,_i+2)                             \
+    VPSRLQ   (XTMP2, XTMP2, 17)      /* XTMP2 = W[-2] MY_ROR 17 {xBxA} */\
+    VPADDD   (XTMP0, XTMP0, X0)                                            \
+            RND_STEP_0_2(g,h,a,b,c,d,e,f,_i+2)                             \
+            RND_STEP_0_3(g,h,a,b,c,d,e,f,_i+2)                             \
+            RND_STEP_0_4(g,h,a,b,c,d,e,f,_i+2)                             \
+    VPXOR    (XTMP2, XTMP3, XTMP2)                                         \
+    VPADDD   (XTMP0, XTMP0, XTMP1)  /* XTMP0 = W[-16] + W[-7] + s0 */      \
+            RND_STEP_0_5(g,h,a,b,c,d,e,f,_i+2)                             \
+    VPXOR    (XTMP4, XTMP4, XTMP2)   /* XTMP4 = s1 {xBxA} */\
+            RND_STEP_0_6(g,h,a,b,c,d,e,f,_i+2)                             \
+    VPSHUFB  (XTMP4, XTMP4, SHUF_00BA)  /* XTMP4 = s1 {00BA} */\
+            RND_STEP_0_7(g,h,a,b,c,d,e,f,_i+2)                             \
+    VPADDD   (XTMP0, XTMP0, XTMP4)  /* XTMP0 = {..., ..., W[1], W[0]} */\
+            RND_STEP_0_8(g,h,a,b,c,d,e,f,_i+2)                             \
+            RND_STEP_1_1(f,g,h,a,b,c,d,e,_i+3)                             \
+    VPSHUFD  (XTMP2, XTMP0, 0b01010000) /* XTMP2 = W[-2] {DDCC} */\
+            RND_STEP_1_2(f,g,h,a,b,c,d,e,_i+3)                             \
+    VPSRLQ   (XTMP4, XTMP2, 17)      /* XTMP4 = W[-2] MY_ROR 17 {xDxC} */  \
+    VPSRLQ   (XTMP3, XTMP2, 19)       /* XTMP3 = W[-2] MY_ROR 19 {xDxC} */\
+            RND_STEP_1_3(f,g,h,a,b,c,d,e,_i+3)                             \
+            RND_STEP_1_4(f,g,h,a,b,c,d,e,_i+3)                             \
+    VPSRLD   (XTMP5, XTMP2, 10)       /* XTMP5 = W[-2] >> 10 {DDCC} */     \
+    VPXOR    (XTMP4, XTMP3, XTMP4)                                         \
+            RND_STEP_1_5(f,g,h,a,b,c,d,e,_i+3)                             \
+            RND_STEP_1_6(f,g,h,a,b,c,d,e,_i+3)                             \
+    VPXOR    (XTMP5, XTMP4, XTMP5)   /* XTMP5 = s1 {xDxC} */               \
+            RND_STEP_1_7(f,g,h,a,b,c,d,e,_i+3)                             \
+    VPSHUFB  (XTMP5, XTMP5, SHUF_DC00) /* XTMP5 = s1 {DC00} */\
+            RND_STEP_1_8(f,g,h,a,b,c,d,e,_i+3)                             \
+    VPADDD   (X0, XTMP5, XTMP0)      /* X0 = {W[3], W[2], W[1], W[0]} */
+
+#if defined(HAVE_INTEL_RORX)
+
+#define MsgSched_RORX(X0,X1,X2,X3,a,b,c,d,e,f,g,h,_i)                      \
+            RND_STEP_RORX_0_1(a,b,c,d,e,f,g,h,_i)                          \
     VPALIGNR (XTMP0, X3, X2, 4)\
-            RND_STEP_2(a,b,c,d,e,f,g,h,_i)\
-    VPADDD   (XTMP0, XTMP0, X0)\
-            RND_STEP_3(a,b,c,d,e,f,g,h,_i)\
     VPALIGNR (XTMP1, X1, X0, 4)   /* XTMP1 = W[-15] */\
-            RND_STEP_4(a,b,c,d,e,f,g,h,_i)\
+            RND_STEP_RORX_0_2(a,b,c,d,e,f,g,h,_i)                          \
+            RND_STEP_RORX_0_3(a,b,c,d,e,f,g,h,_i)                          \
     VPSRLD   (XTMP2, XTMP1, 7)\
-            RND_STEP_5(a,b,c,d,e,f,g,h,_i)\
     VPSLLD   (XTMP3, XTMP1, 25) /* VPSLLD   (XTMP3, XTMP1, (32-7)) */\
-            RND_STEP_6(a,b,c,d,e,f,g,h,_i)\
+            RND_STEP_RORX_0_4(a,b,c,d,e,f,g,h,_i)                          \
+            RND_STEP_RORX_0_5(a,b,c,d,e,f,g,h,_i)                          \
+    VPSRLD   (XTMP4, XTMP1, 3)  /* XTMP4 = W[-15] >> 3 */                  \
     VPOR     (XTMP3, XTMP3, XTMP2)  /* XTMP1 = W[-15] MY_ROR 7 */\
-            RND_STEP_7(a,b,c,d,e,f,g,h,_i)\
-    VPSRLD   (XTMP2, XTMP1,18)\
-            RND_STEP_8(a,b,c,d,e,f,g,h,_i)\
+            RND_STEP_RORX_0_6(a,b,c,d,e,f,g,h,_i)                          \
+            RND_STEP_RORX_0_7(a,b,c,d,e,f,g,h,_i)                          \
+            RND_STEP_RORX_0_8(a,b,c,d,e,f,g,h,_i)                          \
 \
-            RND_STEP_1(h,a,b,c,d,e,f,g,_i+1)\
-    VPSRLD   (XTMP4, XTMP1, 3)  /* XTMP4 = W[-15] >> 3 */\
-            RND_STEP_2(h,a,b,c,d,e,f,g,_i+1)\
+            RND_STEP_RORX_1_1(h,a,b,c,d,e,f,g,_i+1)                        \
+    VPSRLD   (XTMP2, XTMP1,18)                                             \
+            RND_STEP_RORX_1_2(h,a,b,c,d,e,f,g,_i+1)                        \
     VPSLLD   (XTMP1, XTMP1, 14) /* VPSLLD   (XTMP1, XTMP1, (32-18)) */\
-            RND_STEP_3(h,a,b,c,d,e,f,g,_i+1)\
+            RND_STEP_RORX_1_3(h,a,b,c,d,e,f,g,_i+1)                        \
     VPXOR    (XTMP3, XTMP3, XTMP1)\
-            RND_STEP_4(h,a,b,c,d,e,f,g,_i+1)\
-    VPXOR    (XTMP3, XTMP3, XTMP2)  /* XTMP1 = W[-15] MY_ROR 7 ^ W[-15] MY_ROR 18 */\
-            RND_STEP_5(h,a,b,c,d,e,f,g,_i+1)\
-    VPXOR    (XTMP1, XTMP3, XTMP4)  /* XTMP1 = s0 */\
-            RND_STEP_6(h,a,b,c,d,e,f,g,_i+1)\
+            RND_STEP_RORX_1_4(h,a,b,c,d,e,f,g,_i+1)                        \
+    VPXOR    (XTMP3, XTMP3, XTMP2)                                         \
+                          /* XTMP1 = W[-15] MY_ROR 7 ^ W[-15] MY_ROR 18 */ \
+            RND_STEP_RORX_1_5(h,a,b,c,d,e,f,g,_i+1)                        \
     VPSHUFD(XTMP2, X3, 0b11111010)  /* XTMP2 = W[-2] {BBAA}*/\
-            RND_STEP_7(h,a,b,c,d,e,f,g,_i+1)\
-    VPADDD   (XTMP0, XTMP0, XTMP1)  /* XTMP0 = W[-16] + W[-7] + s0 */\
-            RND_STEP_8(h,a,b,c,d,e,f,g,_i+1)\
+            RND_STEP_RORX_1_6(h,a,b,c,d,e,f,g,_i+1)                        \
+    VPXOR    (XTMP1, XTMP3, XTMP4)  /* XTMP1 = s0 */                       \
+            RND_STEP_RORX_1_7(h,a,b,c,d,e,f,g,_i+1)                        \
+    VPSRLD   (XTMP4, XTMP2, 10)      /* XTMP4 = W[-2] >> 10 {BBAA} */\
+            RND_STEP_RORX_1_8(h,a,b,c,d,e,f,g,_i+1)                        \
+                                                                           \
+            RND_STEP_RORX_0_1(g,h,a,b,c,d,e,f,_i+2)                        \
+    VPSRLQ   (XTMP3, XTMP2, 19)      /* XTMP3 = W[-2] MY_ROR 19 {xBxA} */\
+            RND_STEP_RORX_0_2(g,h,a,b,c,d,e,f,_i+2)                        \
+    VPSRLQ   (XTMP2, XTMP2, 17)      /* XTMP2 = W[-2] MY_ROR 17 {xBxA} */\
+    VPADDD   (XTMP0, XTMP0, X0)                                            \
+            RND_STEP_RORX_0_3(g,h,a,b,c,d,e,f,_i+2)                        \
+    VPADDD   (XTMP0, XTMP0, XTMP1)  /* XTMP0 = W[-16] + W[-7] + s0 */      \
+            RND_STEP_RORX_0_4(g,h,a,b,c,d,e,f,_i+2)                        \
+    VPXOR    (XTMP2, XTMP2, XTMP3)\
+            RND_STEP_RORX_0_5(g,h,a,b,c,d,e,f,_i+2)                        \
+    VPXOR    (XTMP4, XTMP4, XTMP2)   /* XTMP4 = s1 {xBxA} */\
+            RND_STEP_RORX_0_6(g,h,a,b,c,d,e,f,_i+2)                        \
+    VPSHUFB  (XTMP4, XTMP4, SHUF_00BA)  /* XTMP4 = s1 {00BA} */\
+            RND_STEP_RORX_0_7(g,h,a,b,c,d,e,f,_i+2)                        \
+    VPADDD   (XTMP0, XTMP0, XTMP4)  /* XTMP0 = {..., ..., W[1], W[0]} */\
+            RND_STEP_RORX_0_8(g,h,a,b,c,d,e,f,_i+2)                        \
 \
-            RND_STEP_1(g,h,a,b,c,d,e,f,_i+2)\
-    VPSRLD   (XTMP4, XTMP2, 10)      /* XTMP4 = W[-2] >> 10 {BBAA} */\
-            RND_STEP_2(g,h,a,b,c,d,e,f,_i+2)\
-    VPSRLQ   (XTMP3, XTMP2, 19)      /* XTMP3 = W[-2] MY_ROR 19 {xBxA} */\
-            RND_STEP_3(g,h,a,b,c,d,e,f,_i+2)\
-    VPSRLQ   (XTMP2, XTMP2, 17)      /* XTMP2 = W[-2] MY_ROR 17 {xBxA} */\
-            RND_STEP_4(g,h,a,b,c,d,e,f,_i+2)\
+            RND_STEP_RORX_1_1(f,g,h,a,b,c,d,e,_i+3)                        \
+    VPSHUFD  (XTMP2, XTMP0, 0b01010000) /* XTMP2 = W[-2] {DDCC} */\
+            RND_STEP_RORX_1_2(f,g,h,a,b,c,d,e,_i+3)                        \
+    VPSRLD   (XTMP5, XTMP2, 10)       /* XTMP5 = W[-2] >> 10 {DDCC} */\
+            RND_STEP_RORX_1_3(f,g,h,a,b,c,d,e,_i+3)                        \
+    VPSRLQ   (XTMP3, XTMP2, 19)       /* XTMP3 = W[-2] MY_ROR 19 {xDxC} */\
+            RND_STEP_RORX_1_4(f,g,h,a,b,c,d,e,_i+3)                        \
+    VPSRLQ   (XTMP2, XTMP2, 17)      /* XTMP2 = W[-2] MY_ROR 17 {xDxC} */\
+            RND_STEP_RORX_1_5(f,g,h,a,b,c,d,e,_i+3)                        \
     VPXOR    (XTMP2, XTMP2, XTMP3)\
-            RND_STEP_5(g,h,a,b,c,d,e,f,_i+2)\
-    VPXOR    (XTMP4, XTMP4, XTMP2)   /* XTMP4 = s1 {xBxA} */\
-            RND_STEP_6(g,h,a,b,c,d,e,f,_i+2)\
-    VPSHUFB  (XTMP4, XTMP4, SHUF_00BA)  /* XTMP4 = s1 {00BA} */\
-            RND_STEP_7(g,h,a,b,c,d,e,f,_i+2)\
-    VPADDD   (XTMP0, XTMP0, XTMP4)  /* XTMP0 = {..., ..., W[1], W[0]} */\
-            RND_STEP_8(g,h,a,b,c,d,e,f,_i+2)\
-\
-            RND_STEP_1(f,g,h,a,b,c,d,e,_i+3)\
-    VPSHUFD  (XTMP2, XTMP0, 0b01010000) /* XTMP2 = W[-2] {DDCC} */\
-            RND_STEP_2(f,g,h,a,b,c,d,e,_i+3)\
-    VPSRLD   (XTMP5, XTMP2, 10)       /* XTMP5 = W[-2] >> 10 {DDCC} */\
-            RND_STEP_3(f,g,h,a,b,c,d,e,_i+3)\
-    VPSRLQ   (XTMP3, XTMP2, 19)       /* XTMP3 = W[-2] MY_ROR 19 {xDxC} */\
-            RND_STEP_4(f,g,h,a,b,c,d,e,_i+3)\
-    VPSRLQ   (XTMP2, XTMP2, 17)      /* XTMP2 = W[-2] MY_ROR 17 {xDxC} */\
-            RND_STEP_5(f,g,h,a,b,c,d,e,_i+3)\
-    VPXOR    (XTMP2, XTMP2, XTMP3)\
-            RND_STEP_6(f,g,h,a,b,c,d,e,_i+3)\
+            RND_STEP_RORX_1_6(f,g,h,a,b,c,d,e,_i+3)                        \
     VPXOR    (XTMP5, XTMP5, XTMP2)   /* XTMP5 = s1 {xDxC} */\
-            RND_STEP_7(f,g,h,a,b,c,d,e,_i+3)\
+            RND_STEP_RORX_1_7(f,g,h,a,b,c,d,e,_i+3)                        \
     VPSHUFB  (XTMP5, XTMP5, SHUF_DC00) /* XTMP5 = s1 {DC00} */\
-            RND_STEP_8(f,g,h,a,b,c,d,e,_i+3)\
-    VPADDD   (X0, XTMP5, XTMP0)      /* X0 = {W[3], W[2], W[1], W[0]} */\
-
-#if defined(HAVE_INTEL_RORX)
-
-#define MessageSched_RORX(X0, X1, X2, X3, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5, \
-                          XFER, SHUF_00BA, SHUF_DC00,a,b,c,d,e,f,g,h,_i)\
-            RND_STEP_RORX_1(a,b,c,d,e,f,g,h,_i)\
-    VPALIGNR (XTMP0, X3, X2, 4)\
-            RND_STEP_RORX_2(a,b,c,d,e,f,g,h,_i)\
-    VPADDD   (XTMP0, XTMP0, X0)\
-            RND_STEP_RORX_3(a,b,c,d,e,f,g,h,_i)\
-    VPALIGNR (XTMP1, X1, X0, 4)   /* XTMP1 = W[-15] */\
-            RND_STEP_RORX_4(a,b,c,d,e,f,g,h,_i)\
-    VPSRLD   (XTMP2, XTMP1, 7)\
-            RND_STEP_RORX_5(a,b,c,d,e,f,g,h,_i)\
-    VPSLLD   (XTMP3, XTMP1, 25) /* VPSLLD   (XTMP3, XTMP1, (32-7)) */\
-            RND_STEP_RORX_6(a,b,c,d,e,f,g,h,_i)\
-    VPOR     (XTMP3, XTMP3, XTMP2)  /* XTMP1 = W[-15] MY_ROR 7 */\
-            RND_STEP_RORX_7(a,b,c,d,e,f,g,h,_i)\
-    VPSRLD   (XTMP2, XTMP1,18)\
-            RND_STEP_RORX_8(a,b,c,d,e,f,g,h,_i)\
-\
-            RND_STEP_RORX_1(h,a,b,c,d,e,f,g,_i+1)\
-    VPSRLD   (XTMP4, XTMP1, 3)  /* XTMP4 = W[-15] >> 3 */\
-            RND_STEP_RORX_2(h,a,b,c,d,e,f,g,_i+1)\
-    VPSLLD   (XTMP1, XTMP1, 14) /* VPSLLD   (XTMP1, XTMP1, (32-18)) */\
-            RND_STEP_RORX_3(h,a,b,c,d,e,f,g,_i+1)\
-    VPXOR    (XTMP3, XTMP3, XTMP1)\
-            RND_STEP_RORX_4(h,a,b,c,d,e,f,g,_i+1)\
-    VPXOR    (XTMP3, XTMP3, XTMP2)  /* XTMP1 = W[-15] MY_ROR 7 ^ W[-15] MY_ROR 18 */\
-            RND_STEP_RORX_5(h,a,b,c,d,e,f,g,_i+1)\
-    VPXOR    (XTMP1, XTMP3, XTMP4)  /* XTMP1 = s0 */\
-            RND_STEP_RORX_6(h,a,b,c,d,e,f,g,_i+1)\
-    VPSHUFD(XTMP2, X3, 0b11111010)  /* XTMP2 = W[-2] {BBAA}*/\
-            RND_STEP_RORX_7(h,a,b,c,d,e,f,g,_i+1)\
-    VPADDD   (XTMP0, XTMP0, XTMP1)  /* XTMP0 = W[-16] + W[-7] + s0 */\
-            RND_STEP_RORX_8(h,a,b,c,d,e,f,g,_i+1)\
-\
-            RND_STEP_RORX_1(g,h,a,b,c,d,e,f,_i+2)\
-    VPSRLD   (XTMP4, XTMP2, 10)      /* XTMP4 = W[-2] >> 10 {BBAA} */\
-            RND_STEP_RORX_2(g,h,a,b,c,d,e,f,_i+2)\
-    VPSRLQ   (XTMP3, XTMP2, 19)      /* XTMP3 = W[-2] MY_ROR 19 {xBxA} */\
-            RND_STEP_RORX_3(g,h,a,b,c,d,e,f,_i+2)\
-    VPSRLQ   (XTMP2, XTMP2, 17)      /* XTMP2 = W[-2] MY_ROR 17 {xBxA} */\
-            RND_STEP_RORX_4(g,h,a,b,c,d,e,f,_i+2)\
-    VPXOR    (XTMP2, XTMP2, XTMP3)\
-            RND_STEP_RORX_5(g,h,a,b,c,d,e,f,_i+2)\
-    VPXOR    (XTMP4, XTMP4, XTMP2)   /* XTMP4 = s1 {xBxA} */\
-            RND_STEP_RORX_6(g,h,a,b,c,d,e,f,_i+2)\
-    VPSHUFB  (XTMP4, XTMP4, SHUF_00BA)  /* XTMP4 = s1 {00BA} */\
-            RND_STEP_RORX_7(g,h,a,b,c,d,e,f,_i+2)\
-    VPADDD   (XTMP0, XTMP0, XTMP4)  /* XTMP0 = {..., ..., W[1], W[0]} */\
-            RND_STEP_RORX_8(g,h,a,b,c,d,e,f,_i+2)\
-\
-            RND_STEP_RORX_1(f,g,h,a,b,c,d,e,_i+3)\
-    VPSHUFD  (XTMP2, XTMP0, 0b01010000) /* XTMP2 = W[-2] {DDCC} */\
-            RND_STEP_RORX_2(f,g,h,a,b,c,d,e,_i+3)\
-    VPSRLD   (XTMP5, XTMP2, 10)       /* XTMP5 = W[-2] >> 10 {DDCC} */\
-            RND_STEP_RORX_3(f,g,h,a,b,c,d,e,_i+3)\
-    VPSRLQ   (XTMP3, XTMP2, 19)       /* XTMP3 = W[-2] MY_ROR 19 {xDxC} */\
-            RND_STEP_RORX_4(f,g,h,a,b,c,d,e,_i+3)\
-    VPSRLQ   (XTMP2, XTMP2, 17)      /* XTMP2 = W[-2] MY_ROR 17 {xDxC} */\
-            RND_STEP_RORX_5(f,g,h,a,b,c,d,e,_i+3)\
-    VPXOR    (XTMP2, XTMP2, XTMP3)\
-            RND_STEP_RORX_6(f,g,h,a,b,c,d,e,_i+3)\
-    VPXOR    (XTMP5, XTMP5, XTMP2)   /* XTMP5 = s1 {xDxC} */\
-            RND_STEP_RORX_7(f,g,h,a,b,c,d,e,_i+3)\
-    VPSHUFB  (XTMP5, XTMP5, SHUF_DC00) /* XTMP5 = s1 {DC00} */\
-            RND_STEP_RORX_8(f,g,h,a,b,c,d,e,_i+3)\
-    VPADDD   (X0, XTMP5, XTMP0)      /* X0 = {W[3], W[2], W[1], W[0]} */\
+            RND_STEP_RORX_1_8(f,g,h,a,b,c,d,e,_i+3)                        \
+    VPADDD   (X0, XTMP5, XTMP0)      /* X0 = {W[3], W[2], W[1], W[0]} */
 
 #endif /* HAVE_INTEL_RORX */
 
 
-#define W_K_from_buff()                      \
-    "leaq	%[buf], %%r8\n\t"            \
-    "vmovdqu	  (%%r8), %%xmm4\n\t"        \
-    "vpshufb	%%xmm13, %%xmm4, %%xmm4\n\t" \
-    "vmovdqu	16(%%r8), %%xmm5\n\t"        \
-    "vpshufb	%%xmm13, %%xmm5, %%xmm5\n\t" \
-    "vmovdqu	32(%%r8), %%xmm6\n\t"        \
-    "vpshufb	%%xmm13, %%xmm6, %%xmm6\n\t" \
-    "vmovdqu	48(%%r8), %%xmm7\n\t"        \
-    "vpshufb	%%xmm13, %%xmm7, %%xmm7\n\t"
-
-#define _SET_W_K_XFER(reg, i)                        \
-    "leaq	%[K], %%r8\n\t"                      \
-    "vpaddd	("#i")*4(%%r8), %"#reg", %%xmm9\n\t" \
-    "leaq	%[W_K], %%r8\n\t"                    \
-    "vmovdqa	%%xmm9, ("#i")*4(%%r8)\n\t"
-
-#define SET_W_K_XFER(reg, i) _SET_W_K_XFER(reg, i)
-
-static const ALIGN32 word64 mSHUF_00BA[] = { 0x0b0a090803020100, 0xFFFFFFFFFFFFFFFF }; /* shuffle xBxA -> 00BA */
-static const ALIGN32 word64 mSHUF_DC00[] = { 0xFFFFFFFFFFFFFFFF, 0x0b0a090803020100 }; /* shuffle xDxC -> DC00 */
-static const ALIGN32 word64 mBYTE_FLIP_MASK[] =  { 0x0405060700010203, 0x0c0d0e0f08090a0b };
-
+#define _W_K_from_buff(X0, X1, X2, X3, BYTE_FLIP_MASK) \
+    "# X0, X1, X2, X3 = W[0..15]\n\t"                  \
+    "vmovdqu	  (%%rax), %" #X0 "\n\t"               \
+    "vmovdqu	16(%%rax), %" #X1 "\n\t"               \
+    VPSHUFB(X0, X0, BYTE_FLIP_MASK)                    \
+    VPSHUFB(X1, X1, BYTE_FLIP_MASK)                    \
+    "vmovdqu	32(%%rax), %" #X2 "\n\t"               \
+    "vmovdqu	48(%%rax), %" #X3 "\n\t"               \
+    VPSHUFB(X2, X2, BYTE_FLIP_MASK)                    \
+    VPSHUFB(X3, X3, BYTE_FLIP_MASK)
+
+#define W_K_from_buff(X0, X1, X2, X3, BYTE_FLIP_MASK) \
+       _W_K_from_buff(X0, X1, X2, X3, BYTE_FLIP_MASK)
+
+
+#define _SET_W_K_XFER_4(i) \
+    "vpaddd	(" #i "*4)+ 0+%[K], %%xmm0, %%xmm4\n\t"  \
+    "vpaddd	(" #i "*4)+16+%[K], %%xmm1, %%xmm5\n\t"  \
+    "vmovdqu	%%xmm4,   (" WK ")\n\t"                  \
+    "vmovdqu	%%xmm5, 16(" WK ")\n\t"                  \
+    "vpaddd	(" #i "*4)+32+%[K], %%xmm2, %%xmm6\n\t"  \
+    "vpaddd	(" #i "*4)+48+%[K], %%xmm3, %%xmm7\n\t"  \
+    "vmovdqu	%%xmm6, 32(" WK ")\n\t"                  \
+    "vmovdqu	%%xmm7, 48(" WK ")\n\t"
+
+#define SET_W_K_XFER_4(i) \
+       _SET_W_K_XFER_4(i)
+
+
+static const ALIGN32 word64 mSHUF_00BA[] =
+    { 0x0b0a090803020100, 0xFFFFFFFFFFFFFFFF }; /* shuffle xBxA -> 00BA */
+static const ALIGN32 word64 mSHUF_DC00[] =
+    { 0xFFFFFFFFFFFFFFFF, 0x0b0a090803020100 }; /* shuffle xDxC -> DC00 */
+static const ALIGN32 word64 mBYTE_FLIP_MASK[] =
+    { 0x0405060700010203, 0x0c0d0e0f08090a0b };
 
 #define _Init_Masks(mask1, mask2, mask3)     \
-    "vmovdqu	%[FLIP], %"#mask1"\n\t"      \
-    "vmovdqu	%[SHUF00BA], %"#mask2"\n\t"  \
-    "vmovdqu	%[SHUFDC00], %"#mask3"\n\t"
+    "vmovdqa	%[FLIP], %" #mask1 "\n\t"      \
+    "vmovdqa	%[SHUF00BA], %" #mask2 "\n\t"  \
+    "vmovdqa	%[SHUFDC00], %" #mask3 "\n\t"
 
 #define Init_Masks(BYTE_FLIP_MASK, SHUF_00BA, SHUF_DC00)\
     _Init_Masks(BYTE_FLIP_MASK, SHUF_00BA, SHUF_DC00)
 
-#define X0 %xmm4
-#define X1 %xmm5
-#define X2 %xmm6
-#define X3 %xmm7
-#define X_ X0
-
-#define XTMP0 %xmm0
-#define XTMP1 %xmm1
-#define XTMP2 %xmm2
-#define XTMP3 %xmm3
+#define X0 %xmm0
+#define X1 %xmm1
+#define X2 %xmm2
+#define X3 %xmm3
+
+#define XTMP0 %xmm4
+#define XTMP1 %xmm5
+#define XTMP2 %xmm6
+#define XTMP3 %xmm7
 #define XTMP4 %xmm8
 #define XTMP5 %xmm9
@@ -1272,79 +1672,47 @@
 
 
-static int Transform_AVX1(wc_Sha256* sha256)
+SHA256_NOINLINE static int Transform_Sha256_AVX1(wc_Sha256* sha256)
 {
-    ALIGN32 word32 W_K[64];  /* temp for W+K */
-
     __asm__ __volatile__ (
 
+        "subq	$64, %%rsp\n\t"
+
+        "leaq	32(%[sha256]), %%rax\n\t"
     Init_Masks(BYTE_FLIP_MASK, SHUF_00BA, SHUF_DC00)
-    "# X0, X1, X2, X3 = W[0..15]; \n\t"
-    W_K_from_buff()
-
-    DigestToReg(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7)
-
-    SET_W_K_XFER(X0, 0)
-    MessageSched(X0, X1, X2, X3, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5, XFER,
-            SHUF_00BA, SHUF_DC00, S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,0)
-    SET_W_K_XFER(X1, 4)
-    MessageSched(X1, X2, X3, X0, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5, XFER,
-            SHUF_00BA, SHUF_DC00, S_4,S_5,S_6,S_7,S_0,S_1,S_2,S_3,4)
-    SET_W_K_XFER(X2, 8)
-    MessageSched(X2, X3, X0, X1, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5, XFER,
-            SHUF_00BA, SHUF_DC00, S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,8)
-    SET_W_K_XFER(X3, 12)
-    MessageSched(X3, X0, X1, X2, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5, XFER,
-            SHUF_00BA, SHUF_DC00, S_4,S_5,S_6,S_7,S_0,S_1,S_2,S_3,12)
-    SET_W_K_XFER(X0, 16)
-    MessageSched(X0, X1, X2, X3, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5, XFER,
-            SHUF_00BA, SHUF_DC00, S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,16)
-    SET_W_K_XFER(X1, 20)
-    MessageSched(X1, X2, X3, X0, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5, XFER,
-            SHUF_00BA, SHUF_DC00, S_4,S_5,S_6,S_7,S_0,S_1,S_2,S_3,20)
-    SET_W_K_XFER(X2, 24)
-    MessageSched(X2, X3, X0, X1, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5, XFER,
-            SHUF_00BA, SHUF_DC00, S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,24)
-    SET_W_K_XFER(X3, 28)
-    MessageSched(X3, X0, X1, X2, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5, XFER,
-            SHUF_00BA, SHUF_DC00, S_4,S_5,S_6,S_7,S_0,S_1,S_2,S_3,28)
-    SET_W_K_XFER(X0, 32)
-    MessageSched(X0, X1, X2, X3, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5, XFER,
-            SHUF_00BA, SHUF_DC00, S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,32)
-    SET_W_K_XFER(X1, 36)
-    MessageSched(X1, X2, X3, X0, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5, XFER,
-            SHUF_00BA, SHUF_DC00, S_4,S_5,S_6,S_7,S_0,S_1,S_2,S_3,36)
-    SET_W_K_XFER(X2, 40)
-    MessageSched(X2, X3, X0, X1, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5, XFER,
-            SHUF_00BA, SHUF_DC00, S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,40)
-    SET_W_K_XFER(X3, 44)
-    MessageSched(X3, X0, X1, X2, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5, XFER,
-            SHUF_00BA, SHUF_DC00, S_4,S_5,S_6,S_7,S_0,S_1,S_2,S_3,44)
-
-    SET_W_K_XFER(X0, 48)
-    SET_W_K_XFER(X1, 52)
-    SET_W_K_XFER(X2, 56)
-    SET_W_K_XFER(X3, 60)
-
-    RND_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,48)
-    RND_7(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,49)
-    RND_6(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,50)
-    RND_5(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,51)
-
-    RND_4(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,52)
-    RND_3(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,53)
-    RND_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,54)
-    RND_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,55)
-
-    RND_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,56)
-    RND_7(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,57)
-    RND_6(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,58)
-    RND_5(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,59)
-
-    RND_4(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,60)
-    RND_3(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,61)
-    RND_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,62)
-    RND_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,63)
-
-    RegToDigest(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7)
+    LOAD_DIGEST()
+
+    W_K_from_buff(X0, X1, X2, X3, BYTE_FLIP_MASK)
+
+        "movl	%%r9d, " L4 "\n\t"
+        "movl	%%r12d, " L1 "\n\t"
+        "xorl	%%r10d, " L4 "\n\t"
+
+    SET_W_K_XFER_4(0)
+    MsgSched(X0, X1, X2, X3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  0)
+    MsgSched(X1, X2, X3, X0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  4)
+    MsgSched(X2, X3, X0, X1, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  8)
+    MsgSched(X3, X0, X1, X2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 12)
+
+    SET_W_K_XFER_4(16)
+    MsgSched(X0, X1, X2, X3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  0)
+    MsgSched(X1, X2, X3, X0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  4)
+    MsgSched(X2, X3, X0, X1, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  8)
+    MsgSched(X3, X0, X1, X2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 12)
+
+    SET_W_K_XFER_4(32)
+    MsgSched(X0, X1, X2, X3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  0)
+    MsgSched(X1, X2, X3, X0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  4)
+    MsgSched(X2, X3, X0, X1, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  8)
+    MsgSched(X3, X0, X1, X2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 12)
+
+    SET_W_K_XFER_4(48)
+    RND_ALL_4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  0)
+    RND_ALL_4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  4)
+    RND_ALL_4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  8)
+    RND_ALL_4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 12)
+
+    STORE_ADD_DIGEST()
+
+        "addq	$64, %%rsp\n\t"
 
         :
@@ -1352,9 +1720,7 @@
           [SHUF00BA] "m" (mSHUF_00BA[0]),
           [SHUFDC00] "m" (mSHUF_DC00[0]),
-          [digest]   "m" (sha256->digest),
-          [buf]      "m" (sha256->buffer),
-          [K]        "m" (K),
-          [W_K]      "m" (W_K)
-        : SSE_REGs, "memory"
+          [sha256]   "r" (sha256),
+          [K]        "m" (K)
+        : WORK_REGS, STATE_REGS, XMM_REGS, "memory"
     );
 
@@ -1362,80 +1728,60 @@
 }
 
-#if defined(HAVE_INTEL_RORX)
-static int Transform_AVX1_RORX(wc_Sha256* sha256)
+SHA256_NOINLINE static int Transform_Sha256_AVX1_Len(wc_Sha256* sha256,
+                                                     word32 len)
 {
-    ALIGN32 word32 W_K[64];  /* temp for W+K */
-
     __asm__ __volatile__ (
 
+        "subq	$64, %%rsp\n\t"
+        "movq	120(%[sha256]), %%rax\n\t"
+
     Init_Masks(BYTE_FLIP_MASK, SHUF_00BA, SHUF_DC00)
-    "# X0, X1, X2, X3 = W[0..15]; \n\t"
-    W_K_from_buff()
-
-    DigestToReg(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7)
-
-    SET_W_K_XFER(X0, 0)
-    MessageSched(X0, X1, X2, X3, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5, XFER,
-            SHUF_00BA, SHUF_DC00, S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,0)
-    SET_W_K_XFER(X1, 4)
-    MessageSched_RORX(X1, X2, X3, X0, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5,
-            XFER, SHUF_00BA, SHUF_DC00, S_4,S_5,S_6,S_7,S_0,S_1,S_2,S_3,4)
-    SET_W_K_XFER(X2, 8)
-    MessageSched_RORX(X2, X3, X0, X1, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5,
-            XFER, SHUF_00BA, SHUF_DC00, S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,8)
-    SET_W_K_XFER(X3, 12)
-    MessageSched_RORX(X3, X0, X1, X2, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5,
-            XFER, SHUF_00BA, SHUF_DC00, S_4,S_5,S_6,S_7,S_0,S_1,S_2,S_3,12)
-    SET_W_K_XFER(X0, 16)
-    MessageSched_RORX(X0, X1, X2, X3, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5,
-            XFER, SHUF_00BA, SHUF_DC00, S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,16)
-    SET_W_K_XFER(X1, 20)
-    MessageSched_RORX(X1, X2, X3, X0, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5,
-            XFER, SHUF_00BA, SHUF_DC00, S_4,S_5,S_6,S_7,S_0,S_1,S_2,S_3,20)
-    SET_W_K_XFER(X2, 24)
-    MessageSched_RORX(X2, X3, X0, X1, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5,
-            XFER, SHUF_00BA, SHUF_DC00, S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,24)
-    SET_W_K_XFER(X3, 28)
-    MessageSched_RORX(X3, X0, X1, X2, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5,
-            XFER, SHUF_00BA, SHUF_DC00, S_4,S_5,S_6,S_7,S_0,S_1,S_2,S_3,28)
-    SET_W_K_XFER(X0, 32)
-    MessageSched_RORX(X0, X1, X2, X3, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5,
-            XFER, SHUF_00BA, SHUF_DC00, S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,32)
-    SET_W_K_XFER(X1, 36)
-    MessageSched_RORX(X1, X2, X3, X0, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5,
-            XFER, SHUF_00BA, SHUF_DC00, S_4,S_5,S_6,S_7,S_0,S_1,S_2,S_3,36)
-    SET_W_K_XFER(X2, 40)
-    MessageSched_RORX(X2, X3, X0, X1, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5,
-            XFER, SHUF_00BA, SHUF_DC00, S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,40)
-    SET_W_K_XFER(X3, 44)
-    MessageSched_RORX(X3, X0, X1, X2, XTMP0, XTMP1, XTMP2, XTMP3, XTMP4, XTMP5,
-            XFER, SHUF_00BA, SHUF_DC00, S_4,S_5,S_6,S_7,S_0,S_1,S_2,S_3,44)
-
-    SET_W_K_XFER(X0, 48)
-    SET_W_K_XFER(X1, 52)
-    SET_W_K_XFER(X2, 56)
-    SET_W_K_XFER(X3, 60)
-
-    RND_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,48)
-    RND_7(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,49)
-    RND_6(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,50)
-    RND_5(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,51)
-
-    RND_4(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,52)
-    RND_3(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,53)
-    RND_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,54)
-    RND_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,55)
-
-    RND_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,56)
-    RND_7(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,57)
-    RND_6(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,58)
-    RND_5(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,59)
-
-    RND_4(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,60)
-    RND_3(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,61)
-    RND_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,62)
-    RND_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,63)
-
-    RegToDigest(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7)
+    LOAD_DIGEST()
+
+        "# Start of loop processing a block\n"
+        "1:\n\t"
+
+    W_K_from_buff(X0, X1, X2, X3, BYTE_FLIP_MASK)
+
+        "movl	%%r9d, " L4 "\n\t"
+        "movl	%%r12d, " L1 "\n\t"
+        "xorl	%%r10d, " L4 "\n\t"
+
+    SET_W_K_XFER_4(0)
+    MsgSched(X0, X1, X2, X3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  0)
+    MsgSched(X1, X2, X3, X0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  4)
+    MsgSched(X2, X3, X0, X1, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  8)
+    MsgSched(X3, X0, X1, X2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 12)
+
+    SET_W_K_XFER_4(16)
+    MsgSched(X0, X1, X2, X3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  0)
+    MsgSched(X1, X2, X3, X0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  4)
+    MsgSched(X2, X3, X0, X1, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  8)
+    MsgSched(X3, X0, X1, X2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 12)
+
+    SET_W_K_XFER_4(32)
+    MsgSched(X0, X1, X2, X3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  0)
+    MsgSched(X1, X2, X3, X0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  4)
+    MsgSched(X2, X3, X0, X1, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  8)
+    MsgSched(X3, X0, X1, X2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 12)
+
+    SET_W_K_XFER_4(48)
+    RND_ALL_4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  0)
+    RND_ALL_4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  4)
+    RND_ALL_4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  8)
+    RND_ALL_4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 12)
+        "movq	120(%[sha256]), %%rax\n\t"
+
+    ADD_DIGEST()
+
+        "addq	$64, %%rax\n\t"
+        "subl	$64, %[len]\n\t"
+
+    STORE_DIGEST()
+
+        "movq	%%rax, 120(%[sha256])\n\t"
+        "jnz	1b\n\t"
+
+        "addq	$64, %%rsp\n\t"
 
         :
@@ -1443,730 +1789,811 @@
           [SHUF00BA] "m" (mSHUF_00BA[0]),
           [SHUFDC00] "m" (mSHUF_DC00[0]),
-          [digest]   "m" (sha256->digest),
-          [buf]      "m" (sha256->buffer),
-          [K]        "m" (K),
-          [W_K]      "m" (W_K)
-        : SSE_REGs, "memory"
+          [sha256]   "r" (sha256),
+          [len]      "r" (len),
+          [K]        "m" (K)
+        : WORK_REGS, STATE_REGS, XMM_REGS, "memory"
     );
 
     return 0;
 }
-#endif  /* HAVE_INTEL_RORX */
 #endif  /* HAVE_INTEL_AVX1 */
 
-
-#if defined(HAVE_INTEL_AVX2)
-
-#define _MOVE_to_REG(ymm, mem, i) \
-    "leaq	%["#mem"], %%r8\n\t" \
-    "vmovdqu ("#i")*4(%%r8), %%"#ymm"\n\t"
-#define _MOVE_to_MEM(mem, i, ymm) \
-    "leaq	%["#mem"], %%r8\n\t" \
-    "vmovdqu %%"#ymm",  "#i"*4(%%r8)\n\t"
-#define _BYTE_SWAP(ymm, map)   \
-    "vpshufb %["#map"], %%"#ymm", %%"#ymm"\n\t"
-#define _MOVE_128(ymm0, ymm1, ymm2, map) \
-    "vperm2i128  $"#map", %%"#ymm2", %%"#ymm1", %%"#ymm0"\n\t"
-#define _MOVE_BYTE(ymm0, ymm1, map) \
-    "vpshufb %["#map"], %%"#ymm1", %%"#ymm0"\n\t"
-#define _S_TEMP(dest, src, bits, temp) \
-    "vpsrld  $"#bits", %%"#src", %%"#dest"\n\t" \
-    "vpslld  $32-"#bits", %%"#src", %%"#temp"\n\t" \
-    "vpor %%"#temp",%%"#dest", %%"#dest"\n\t"
-#define _AVX2_R(dest, src, bits) \
-    "vpsrld  $"#bits", %%"#src", %%"#dest"\n\t"
-#define _XOR(dest, src1, src2) \
-    "vpxor   %%"#src1", %%"#src2", %%"#dest"\n\t"
-#define _OR(dest, src1, src2) \
-    "vpor    %%"#src1", %%"#src2", %%"#dest"\n\t"
-#define _ADD(dest, src1, src2) \
-    "vpaddd   %%"#src1", %%"#src2", %%"#dest"\n\t"
-#define _ADD_MEM(dest, src1, mem, i) \
-    "leaq	%["#mem"], %%r8\n\t" \
-    "vpaddd   "#i"*4(%%r8), %%"#src1", %%"#dest"\n\t"
-#define _BLEND(map, dest, src1, src2) \
-    "vpblendd    $"#map", %%"#src1",   %%"#src2", %%"#dest"\n\t"
-
-#define    _EXTRACT_XMM_0(xmm, mem) \
-    "vpextrd $0, %%"#xmm", %["#mem"]\n\t"
-#define    _EXTRACT_XMM_1(xmm, mem) \
-    "vpextrd $1, %%"#xmm", %["#mem"]\n\t"
-#define    _EXTRACT_XMM_2(xmm, mem) \
-    "vpextrd $2, %%"#xmm", %["#mem"]\n\t"
-#define    _EXTRACT_XMM_3(xmm, mem) \
-    "vpextrd $3, %%"#xmm", %["#mem"]\n\t"
-#define    _EXTRACT_XMM_4(ymm, xmm, mem) \
-    "vperm2i128 $0x1, %%"#ymm", %%"#ymm", %%"#ymm"\n\t" \
-    "vpextrd $0, %%"#xmm", %["#mem"]\n\t"
-#define    _EXTRACT_XMM_5(xmm, mem) \
-    "vpextrd $1, %%"#xmm", %["#mem"]\n\t"
-#define    _EXTRACT_XMM_6(xmm, mem) \
-    "vpextrd $2, %%"#xmm", %["#mem"]\n\t"
-#define    _EXTRACT_XMM_7(xmm, mem) \
-    "vpextrd $3, %%"#xmm", %["#mem"]\n\t"
-
-#define    _SWAP_YMM_HL(ymm)  \
-    "vperm2i128 $0x1, %%"#ymm", %%"#ymm", %%"#ymm"\n\t"
-#define     SWAP_YMM_HL(ymm)   _SWAP_YMM_HL(ymm)
-
-#define MOVE_to_REG(ymm, mem, i)   _MOVE_to_REG(ymm, mem, i)
-#define MOVE_to_MEM(mem, i, ymm)   _MOVE_to_MEM(mem, i, ymm)
-#define BYTE_SWAP(ymm, map)        _BYTE_SWAP(ymm, map)
-#define MOVE_128(ymm0, ymm1, ymm2, map) _MOVE_128(ymm0, ymm1, ymm2, map)
-#define MOVE_BYTE(ymm0, ymm1, map) _MOVE_BYTE(ymm0, ymm1, map)
-#define XOR(dest, src1, src2)      _XOR(dest, src1, src2)
-#define OR(dest, src1, src2)       _OR(dest, src1, src2)
-#define ADD(dest, src1, src2)      _ADD(dest, src1, src2)
-#define ADD_MEM(dest, src1, mem, i)  _ADD_MEM(dest, src1, mem, i)
-#define BLEND(map, dest, src1, src2) _BLEND(map, dest, src1, src2)
-
-#define S_TMP(dest, src, bits, temp) _S_TEMP(dest, src, bits, temp)
-#define AVX2_S(dest, src, bits)      S_TMP(dest, src, bits, S_TEMP)
-#define AVX2_R(dest, src, bits)      _AVX2_R(dest, src, bits)
-
-#define GAMMA0(dest, src)      AVX2_S(dest, src, 7)  AVX2_S(G_TEMP, src, 18) \
-    XOR(dest, G_TEMP, dest) AVX2_R(G_TEMP, src, 3)  XOR(dest, G_TEMP, dest)
-#define GAMMA0_1(dest, src)    AVX2_S(dest, src, 7)  AVX2_S(G_TEMP, src, 18)
-#define GAMMA0_2(dest, src)    XOR(dest, G_TEMP, dest) AVX2_R(G_TEMP, src, 3)  \
-    XOR(dest, G_TEMP, dest)
-
-#define GAMMA1(dest, src)      AVX2_S(dest, src, 17) AVX2_S(G_TEMP, src, 19) \
-    XOR(dest, G_TEMP, dest) AVX2_R(G_TEMP, src, 10) XOR(dest, G_TEMP, dest)
-#define GAMMA1_1(dest, src)    AVX2_S(dest, src, 17) AVX2_S(G_TEMP, src, 19)
-#define GAMMA1_2(dest, src)    XOR(dest, G_TEMP, dest) AVX2_R(G_TEMP, src, 10) \
-    XOR(dest, G_TEMP, dest)
-
-#define    FEEDBACK1_to_W_I_2    MOVE_BYTE(YMM_TEMP0, W_I, MAP1W_2) \
-    BLEND(0x0c, W_I_2, YMM_TEMP0, W_I_2)
-#define    FEEDBACK2_to_W_I_2    MOVE_128(YMM_TEMP0, W_I, W_I, 0x08)  \
-    MOVE_BYTE(YMM_TEMP0, YMM_TEMP0, MAP2W_2) BLEND(0x30, W_I_2, YMM_TEMP0, W_I_2)
-#define    FEEDBACK3_to_W_I_2    MOVE_BYTE(YMM_TEMP0, W_I, MAP3W_2) \
-    BLEND(0xc0, W_I_2, YMM_TEMP0, W_I_2)
-
-#define    FEEDBACK_to_W_I_7     MOVE_128(YMM_TEMP0, W_I, W_I, 0x08)\
-    MOVE_BYTE(YMM_TEMP0, YMM_TEMP0, MAPW_7) BLEND(0x80, W_I_7, YMM_TEMP0, W_I_7)
-
-#undef voitle
-
-#define W_I_16  ymm8
-#define W_I_15  ymm9
-#define W_I_7  ymm10
-#define W_I_2  ymm11
-#define W_I    ymm12
-#define G_TEMP     ymm13
-#define S_TEMP     ymm14
-#define YMM_TEMP0  ymm15
-#define YMM_TEMP0x xmm15
-#define W_I_TEMP   ymm7
-#define W_K_TEMP   ymm15
-#define W_K_TEMPx  xmm15
-
-#define MOVE_15_to_16(w_i_16, w_i_15, w_i_7)\
-    "vperm2i128	$0x01, %%"#w_i_15", %%"#w_i_15", %%"#w_i_15"\n\t" \
-    "vpblendd	$0x08, %%"#w_i_15", %%"#w_i_7",  %%"#w_i_16"\n\t" \
-    "vperm2i128	$0x01, %%"#w_i_7",  %%"#w_i_7",  %%"#w_i_15"\n\t" \
-    "vpblendd	$0x80, %%"#w_i_15", %%"#w_i_16", %%"#w_i_16"\n\t" \
-    "vpshufd	$0x93, %%"#w_i_16", %%"#w_i_16"\n\t"
-
-#define MOVE_7_to_15(w_i_15, w_i_7)\
-    "vmovdqu	%%"#w_i_7",  %%"#w_i_15"\n\t"
-
-#define MOVE_I_to_7(w_i_7, w_i)\
-    "vperm2i128	$0x01, %%"#w_i",   %%"#w_i", %%"#w_i_7"\n\t" \
-    "vpblendd	$0x01, %%"#w_i_7", %%"#w_i", %%"#w_i_7"\n\t" \
-    "vpshufd	$0x39, %%"#w_i_7", %%"#w_i_7"\n\t"
-
-#define MOVE_I_to_2(w_i_2, w_i)\
-    "vperm2i128	$0x01, %%"#w_i", %%"#w_i", %%"#w_i_2"\n\t" \
-    "vpshufd	$0x0e, %%"#w_i_2", %%"#w_i_2"\n\t"
-
-#define ROTATE_W(w_i_16, w_i_15, w_i_7, w_i_2, w_i)\
-    MOVE_15_to_16(w_i_16, w_i_15, w_i_7) \
-    MOVE_7_to_15(w_i_15, w_i_7) \
-    MOVE_I_to_7(w_i_7, w_i) \
-    MOVE_I_to_2(w_i_2, w_i)
-
-#define _DumpS(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7 )\
-  { word32 d[8];\
-    __asm__ volatile("movl %"#S_0", %0":"=r"(d[0])::SSE_REGs);\
-    __asm__ volatile("movl %"#S_1", %0":"=r"(d[1])::SSE_REGs);\
-    __asm__ volatile("movl %"#S_2", %0":"=r"(d[2])::SSE_REGs);\
-    __asm__ volatile("movl %"#S_3", %0":"=r"(d[3])::SSE_REGs);\
-    __asm__ volatile("movl %"#S_4", %0":"=r"(d[4])::SSE_REGs);\
-    __asm__ volatile("movl %"#S_5", %0":"=r"(d[5])::SSE_REGs);\
-    __asm__ volatile("movl %"#S_6", %0":"=r"(d[6])::SSE_REGs);\
-    __asm__ volatile("movl %"#S_7", %0":"=r"(d[7])::SSE_REGs);\
-        printf("S[0..7]=%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x\n", d[0],d[1],d[2],d[3],d[4],d[5],d[6],d[7]);\
-    __asm__ volatile("movl %0, %"#S_0::"r"(d[0]):SSE_REGs);\
-    __asm__ volatile("movl %0, %"#S_1::"r"(d[1]):SSE_REGs);\
-    __asm__ volatile("movl %0, %"#S_2::"r"(d[2]):SSE_REGs);\
-    __asm__ volatile("movl %0, %"#S_3::"r"(d[3]):SSE_REGs);\
-    __asm__ volatile("movl %0, %"#S_4::"r"(d[4]):SSE_REGs);\
-    __asm__ volatile("movl %0, %"#S_5::"r"(d[5]):SSE_REGs);\
-    __asm__ volatile("movl %0, %"#S_6::"r"(d[6]):SSE_REGs);\
-    __asm__ volatile("movl %0, %"#S_7::"r"(d[7]):SSE_REGs);\
-}
-
-
-#define DigestToReg(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7 )\
-    _DigestToReg(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7 )
-
-#define RegToDigest(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7 )\
-    _RegToDigest(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7 )
-
-#define DumS(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7 )\
-    _DumpS(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7 )
-
-
-    /* Byte swap Masks to ensure that rest of the words are filled with zero's. */
-    static const unsigned long mBYTE_FLIP_MASK_16[] =
-        { 0x0405060700010203, 0x0c0d0e0f08090a0b, 0x0405060700010203, 0x0c0d0e0f08090a0b };
-    static const unsigned long mBYTE_FLIP_MASK_15[] =
-        { 0x0405060700010203, 0x0c0d0e0f08090a0b, 0x0405060700010203, 0x0c0d0e0f08090a0b };
-    static const unsigned long mBYTE_FLIP_MASK_7 [] =
-        { 0x0405060700010203, 0x0c0d0e0f08090a0b, 0x0405060700010203, 0x8080808008090a0b };
-    static const unsigned long mBYTE_FLIP_MASK_2 [] =
-        { 0x0405060700010203, 0x8080808080808080, 0x8080808080808080, 0x8080808080808080 };
-
-    static const unsigned long mMAPtoW_I_7[] =
-        { 0x8080808080808080, 0x8080808080808080, 0x8080808080808080, 0x0302010080808080 };
-    static const unsigned long mMAP1toW_I_2[] =
-        { 0x8080808080808080, 0x0706050403020100, 0x8080808080808080, 0x8080808080808080 };
-    static const unsigned long mMAP2toW_I_2[] =
-        { 0x8080808080808080, 0x8080808080808080, 0x0f0e0d0c0b0a0908, 0x8080808080808080 };
-    static const unsigned long mMAP3toW_I_2[] =
-        { 0x8080808080808080, 0x8080808080808080, 0x8080808080808080, 0x0706050403020100 };
-
-static int Transform_AVX2(wc_Sha256* sha256)
+#if defined(HAVE_INTEL_AVX2) && defined(HAVE_INTEL_RORX)
+SHA256_NOINLINE static int Transform_Sha256_AVX1_RORX(wc_Sha256* sha256)
 {
-#ifdef WOLFSSL_SMALL_STACK
-    word32* W_K;
-    W_K = (word32*) XMALLOC(sizeof(word32) * 64, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-    if (W_K == NULL)
-        return MEMORY_E;
-#else
-    word32 W_K[64];
-#endif
-
     __asm__ __volatile__ (
 
-    MOVE_to_REG(W_I_16, buf, 0)     BYTE_SWAP(W_I_16, FLIP_16)
-    MOVE_to_REG(W_I_15, buf, 1)     BYTE_SWAP(W_I_15, FLIP_15)
-    MOVE_to_REG(W_I,    buf, 8)     BYTE_SWAP(W_I,    FLIP_16)
-    MOVE_to_REG(W_I_7,  buf, 16-7)  BYTE_SWAP(W_I_7,  FLIP_7)
-    MOVE_to_REG(W_I_2,  buf, 16-2)  BYTE_SWAP(W_I_2,  FLIP_2)
-
-    DigestToReg(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7)
-
-    ADD_MEM(W_K_TEMP, W_I_16, K, 0)
-    MOVE_to_MEM(W_K, 0, W_K_TEMP)
-
-    RND_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,0)
-    RND_7(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,1)
-    RND_6(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,2)
-    RND_5(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,3)
-    RND_4(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,4)
-    RND_3(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,5)
-    RND_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,6)
-    RND_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,7)
-
-    ADD_MEM(YMM_TEMP0, W_I, K, 8)
-    MOVE_to_MEM(W_K, 8, YMM_TEMP0)
-
-    /* W[i] = Gamma1(W[i-2]) + W[i-7] + Gamma0(W[i-15] + W[i-16]) */
-            RND_0_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,8)
-    GAMMA0_1(W_I_TEMP, W_I_15)
-            RND_0_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,8)
-    GAMMA0_2(W_I_TEMP, W_I_15)
-            RND_0_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,8)
-    ADD(W_I_TEMP, W_I_16, W_I_TEMP)/* for saving W_I before adding incomplete W_I_7 */
-            RND_7_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,9)
-    ADD(W_I, W_I_7, W_I_TEMP)
-            RND_7_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,9)
-    GAMMA1_1(YMM_TEMP0, W_I_2)
-            RND_7_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,9)
-    GAMMA1_2(YMM_TEMP0, W_I_2)
-            RND_6_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,10)
-    ADD(W_I, W_I, YMM_TEMP0)/* now W[16..17] are completed */
-            RND_6_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,10)
-    FEEDBACK1_to_W_I_2
-            RND_6_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,10)
-    FEEDBACK_to_W_I_7
-            RND_5_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,11)
-    ADD(W_I_TEMP, W_I_7, W_I_TEMP)
-            RND_5_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,11)
-    GAMMA1_1(YMM_TEMP0, W_I_2)
-            RND_5_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,11)
-    GAMMA1_2(YMM_TEMP0, W_I_2)
-            RND_4_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,12)
-    ADD(W_I, W_I_TEMP, YMM_TEMP0)/* now W[16..19] are completed */
-            RND_4_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,12)
-    FEEDBACK2_to_W_I_2
-            RND_4_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,12)
-    GAMMA1_1(YMM_TEMP0, W_I_2)
-            RND_3_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,13)
-    GAMMA1_2(YMM_TEMP0, W_I_2)
-            RND_3_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,13)
-    ADD(W_I, W_I_TEMP, YMM_TEMP0) /* now W[16..21] are completed */
-            RND_3_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,13)
-    FEEDBACK3_to_W_I_2
-            RND_2_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,14)
-    GAMMA1(YMM_TEMP0, W_I_2)
-            RND_2_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,14)
-            RND_2_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,14)
-    ADD(W_I, W_I_TEMP, YMM_TEMP0) /* now W[16..23] are completed */
-            RND_1_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,15)
-
-    MOVE_to_REG(YMM_TEMP0, K, 16)
-            RND_1_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,15)
-    ROTATE_W(W_I_16, W_I_15, W_I_7, W_I_2, W_I)
-            RND_1_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,15)
-    ADD(YMM_TEMP0, YMM_TEMP0, W_I)
-    MOVE_to_MEM(W_K, 16, YMM_TEMP0)
-
-    /* W[i] = Gamma1(W[i-2]) + W[i-7] + Gamma0(W[i-15] + W[i-16]) */
-            RND_0_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,16)
-    GAMMA0_1(W_I_TEMP, W_I_15)
-            RND_0_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,16)
-    GAMMA0_2(W_I_TEMP, W_I_15)
-            RND_0_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,16)
-    ADD(W_I_TEMP, W_I_16, W_I_TEMP)/* for saving W_I before adding incomplete W_I_7 */
-            RND_7_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,17)
-    ADD(W_I, W_I_7, W_I_TEMP)
-            RND_7_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,17)
-    GAMMA1_1(YMM_TEMP0, W_I_2)
-            RND_7_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,17)
-    GAMMA1_2(YMM_TEMP0, W_I_2)
-            RND_6_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,18)
-    ADD(W_I, W_I, YMM_TEMP0)/* now W[16..17] are completed */
-            RND_6_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,18)
-    FEEDBACK1_to_W_I_2
-            RND_6_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,18)
-    FEEDBACK_to_W_I_7
-            RND_5_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,19)
-    ADD(W_I_TEMP, W_I_7, W_I_TEMP)
-            RND_5_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,19)
-    GAMMA1(YMM_TEMP0, W_I_2)
-            RND_5_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,19)
-    GAMMA1_2(YMM_TEMP0, W_I_2)
-            RND_4_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,20)
-    ADD(W_I, W_I_TEMP, YMM_TEMP0)/* now W[16..19] are completed */
-            RND_4_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,20)
-    FEEDBACK2_to_W_I_2
-            RND_4_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,20)
-    GAMMA1_1(YMM_TEMP0, W_I_2)
-            RND_3_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,21)
-    GAMMA1_2(YMM_TEMP0, W_I_2)
-            RND_3_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,21)
-    ADD(W_I, W_I_TEMP, YMM_TEMP0) /* now W[16..21] are completed */
-            RND_3_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,21)
-    FEEDBACK3_to_W_I_2
-            RND_2_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,22)
-    GAMMA1_1(YMM_TEMP0, W_I_2)
-            RND_2_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,22)
-    GAMMA1_2(YMM_TEMP0, W_I_2)
-            RND_2_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,22)
-    ADD(W_I, W_I_TEMP, YMM_TEMP0) /* now W[16..23] are completed */
-            RND_1_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,23)
-
-    MOVE_to_REG(YMM_TEMP0, K, 24)
-            RND_1_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,23)
-    ROTATE_W(W_I_16, W_I_15, W_I_7, W_I_2, W_I)
-            RND_1_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,23)
-    ADD(YMM_TEMP0, YMM_TEMP0, W_I)
-    MOVE_to_MEM(W_K, 24, YMM_TEMP0)
-
-            /* W[i] = Gamma1(W[i-2]) + W[i-7] + Gamma0(W[i-15] + W[i-16]) */
-            RND_0_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,24)
-    GAMMA0_1(W_I_TEMP, W_I_15)
-            RND_0_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,24)
-    GAMMA0_2(W_I_TEMP, W_I_15)
-            RND_0_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,24)
-    ADD(W_I_TEMP, W_I_16, W_I_TEMP)/* for saving W_I before adding incomplete W_I_7 */
-            RND_7_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,25)
-    ADD(W_I, W_I_7, W_I_TEMP)
-            RND_7_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,25)
-    GAMMA1_1(YMM_TEMP0, W_I_2)
-            RND_7_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,25)
-    GAMMA1_2(YMM_TEMP0, W_I_2)
-            RND_6_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,26)
-    ADD(W_I, W_I, YMM_TEMP0)/* now W[16..17] are completed */
-            RND_6_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,26)
-    FEEDBACK1_to_W_I_2
-            RND_6_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,26)
-    FEEDBACK_to_W_I_7
-            RND_5_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,27)
-    ADD(W_I_TEMP, W_I_7, W_I_TEMP)
-            RND_5_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,27)
-    GAMMA1_1(YMM_TEMP0, W_I_2)
-            RND_5_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,27)
-    GAMMA1_2(YMM_TEMP0, W_I_2)
-            RND_4_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,28)
-    ADD(W_I, W_I_TEMP, YMM_TEMP0)/* now W[16..19] are completed */
-            RND_4_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,28)
-    FEEDBACK2_to_W_I_2
-            RND_4_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,28)
-    GAMMA1_1(YMM_TEMP0, W_I_2)
-            RND_3_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,29)
-    GAMMA1_2(YMM_TEMP0, W_I_2)
-            RND_3_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,29)
-    ADD(W_I, W_I_TEMP, YMM_TEMP0) /* now W[16..21] are completed */
-            RND_3_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,29)
-    FEEDBACK3_to_W_I_2
-            RND_2_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,30)
-    GAMMA1(YMM_TEMP0, W_I_2)
-            RND_2_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,30)
-            RND_2_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,30)
-    ADD(W_I, W_I_TEMP, YMM_TEMP0) /* now W[16..23] are completed */
-            RND_1_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,31)
-
-    MOVE_to_REG(YMM_TEMP0, K, 32)
-            RND_1_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,31)
-    ROTATE_W(W_I_16, W_I_15, W_I_7, W_I_2, W_I)
-            RND_1_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,31)
-    ADD(YMM_TEMP0, YMM_TEMP0, W_I)
-    MOVE_to_MEM(W_K, 32, YMM_TEMP0)
-
-
-            /* W[i] = Gamma1(W[i-2]) + W[i-7] + Gamma0(W[i-15] + W[i-16]) */
-            RND_0_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,32)
-    GAMMA0_1(W_I_TEMP, W_I_15)
-            RND_0_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,32)
-    GAMMA0_2(W_I_TEMP, W_I_15)
-            RND_0_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,32)
-    ADD(W_I_TEMP, W_I_16, W_I_TEMP)/* for saving W_I before adding incomplete W_I_7 */
-            RND_7_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,33)
-    ADD(W_I, W_I_7, W_I_TEMP)
-            RND_7_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,33)
-    GAMMA1_1(YMM_TEMP0, W_I_2)
-            RND_7_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,33)
-    GAMMA1_2(YMM_TEMP0, W_I_2)
-            RND_6_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,34)
-    ADD(W_I, W_I, YMM_TEMP0)/* now W[16..17] are completed */
-            RND_6_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,34)
-    FEEDBACK1_to_W_I_2
-            RND_6_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,34)
-    FEEDBACK_to_W_I_7
-            RND_5_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,35)
-    ADD(W_I_TEMP, W_I_7, W_I_TEMP)
-            RND_5_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,35)
-    GAMMA1_1(YMM_TEMP0, W_I_2)
-            RND_5_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,35)
-    GAMMA1_2(YMM_TEMP0, W_I_2)
-            RND_4_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,36)
-    ADD(W_I, W_I_TEMP, YMM_TEMP0)/* now W[16..19] are completed */
-            RND_4_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,36)
-    FEEDBACK2_to_W_I_2
-            RND_4_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,36)
-    GAMMA1_1(YMM_TEMP0, W_I_2)
-            RND_3_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,37)
-    GAMMA1_2(YMM_TEMP0, W_I_2)
-            RND_3_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,37)
-    ADD(W_I, W_I_TEMP, YMM_TEMP0) /* now W[16..21] are completed */
-            RND_3_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,37)
-    FEEDBACK3_to_W_I_2
-            RND_2_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,38)
-    GAMMA1_1(YMM_TEMP0, W_I_2)
-            RND_2_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,38)
-    GAMMA1_2(YMM_TEMP0, W_I_2)
-            RND_2_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,38)
-    ADD(W_I, W_I_TEMP, YMM_TEMP0) /* now W[16..23] are completed */
-            RND_1_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,39)
-
-    MOVE_to_REG(YMM_TEMP0, K, 40)
-            RND_1_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,39)
-    ROTATE_W(W_I_16, W_I_15, W_I_7, W_I_2, W_I)
-            RND_1_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,39)
-    ADD(YMM_TEMP0, YMM_TEMP0, W_I)
-    MOVE_to_MEM(W_K, 40, YMM_TEMP0)
-
-            /* W[i] = Gamma1(W[i-2]) + W[i-7] + Gamma0(W[i-15] + W[i-16]) */
-            RND_0_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,40)
-    GAMMA0_1(W_I_TEMP, W_I_15)
-            RND_0_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,40)
-    GAMMA0_2(W_I_TEMP, W_I_15)
-            RND_0_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,40)
-    ADD(W_I_TEMP, W_I_16, W_I_TEMP)/* for saving W_I before adding incomplete W_I_7 */
-            RND_7_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,41)
-    ADD(W_I, W_I_7, W_I_TEMP)
-            RND_7_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,41)
-    GAMMA1_1(YMM_TEMP0, W_I_2)
-            RND_7_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,41)
-    GAMMA1_2(YMM_TEMP0, W_I_2)
-            RND_6_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,42)
-    ADD(W_I, W_I, YMM_TEMP0)/* now W[16..17] are completed */
-            RND_6_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,42)
-    FEEDBACK1_to_W_I_2
-            RND_6_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,42)
-    FEEDBACK_to_W_I_7
-            RND_5_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,43)
-    ADD(W_I_TEMP, W_I_7, W_I_TEMP)
-            RND_5_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,43)
-    GAMMA1_1(YMM_TEMP0, W_I_2)
-            RND_5_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,43)
-    GAMMA1_2(YMM_TEMP0, W_I_2)
-            RND_4_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,44)
-    ADD(W_I, W_I_TEMP, YMM_TEMP0)/* now W[16..19] are completed */
-            RND_4_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,44)
-    FEEDBACK2_to_W_I_2
-            RND_4_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,44)
-    GAMMA1_1(YMM_TEMP0, W_I_2)
-            RND_3_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,45)
-    GAMMA1_2(YMM_TEMP0, W_I_2)
-            RND_3_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,45)
-    ADD(W_I, W_I_TEMP, YMM_TEMP0) /* now W[16..21] are completed */
-            RND_3_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,45)
-    FEEDBACK3_to_W_I_2
-            RND_2_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,46)
-    GAMMA1_1(YMM_TEMP0, W_I_2)
-            RND_2_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,46)
-    GAMMA1_2(YMM_TEMP0, W_I_2)
-            RND_2_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,46)
-    ADD(W_I, W_I_TEMP, YMM_TEMP0) /* now W[16..23] are completed */
-            RND_1_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,47)
-
-    MOVE_to_REG(YMM_TEMP0, K, 48)
-            RND_1_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,47)
-    ROTATE_W(W_I_16, W_I_15, W_I_7, W_I_2, W_I)
-            RND_1_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,47)
-    ADD(YMM_TEMP0, YMM_TEMP0, W_I)
-    MOVE_to_MEM(W_K, 48, YMM_TEMP0)
-
-            /* W[i] = Gamma1(W[i-2]) + W[i-7] + Gamma0(W[i-15] + W[i-16]) */
-            RND_0_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,48)
-    GAMMA0_1(W_I_TEMP, W_I_15)
-            RND_0_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,48)
-    GAMMA0_2(W_I_TEMP, W_I_15)
-            RND_0_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,48)
-    ADD(W_I_TEMP, W_I_16, W_I_TEMP)/* for saving W_I before adding incomplete W_I_7 */
-            RND_7_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,49)
-    ADD(W_I, W_I_7, W_I_TEMP)
-            RND_7_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,49)
-    GAMMA1_1(YMM_TEMP0, W_I_2)
-            RND_7_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,49)
-    GAMMA1_2(YMM_TEMP0, W_I_2)
-            RND_6_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,50)
-    ADD(W_I, W_I, YMM_TEMP0)/* now W[16..17] are completed */
-            RND_6_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,50)
-    FEEDBACK1_to_W_I_2
-            RND_6_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,50)
-    FEEDBACK_to_W_I_7
-            RND_5_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,51)
-    ADD(W_I_TEMP, W_I_7, W_I_TEMP)
-            RND_5_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,51)
-    GAMMA1_1(YMM_TEMP0, W_I_2)
-            RND_5_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,51)
-    GAMMA1_2(YMM_TEMP0, W_I_2)
-            RND_4_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,52)
-    ADD(W_I, W_I_TEMP, YMM_TEMP0)/* now W[16..19] are completed */
-            RND_4_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,52)
-    FEEDBACK2_to_W_I_2
-            RND_4_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,52)
-    GAMMA1_1(YMM_TEMP0, W_I_2)
-            RND_3_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,53)
-    GAMMA1_2(YMM_TEMP0, W_I_2)
-            RND_3_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,53)
-    ADD(W_I, W_I_TEMP, YMM_TEMP0) /* now W[16..21] are completed */
-            RND_3_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,53)
-    FEEDBACK3_to_W_I_2
-            RND_2_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,54)
-    GAMMA1_1(YMM_TEMP0, W_I_2)
-            RND_2_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,54)
-    GAMMA1_2(YMM_TEMP0, W_I_2)
-            RND_2_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,54)
-    ADD(W_I, W_I_TEMP, YMM_TEMP0) /* now W[16..23] are completed */
-            RND_1_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,55)
-
-    MOVE_to_REG(YMM_TEMP0, K, 56)
-            RND_1_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,55)
-    ROTATE_W(W_I_16, W_I_15, W_I_7, W_I_2, W_I)
-            RND_1_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,55)
-    ADD(YMM_TEMP0, YMM_TEMP0, W_I)
-    MOVE_to_MEM(W_K, 56, YMM_TEMP0)
-
-    RND_0(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,56)
-    RND_7(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,57)
-    RND_6(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,58)
-    RND_5(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,59)
-
-    RND_4(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,60)
-    RND_3(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,61)
-    RND_2(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,62)
-    RND_1(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7,63)
-
-    RegToDigest(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7)
+        "subq	$64, %%rsp\n\t"
+
+    Init_Masks(BYTE_FLIP_MASK, SHUF_00BA, SHUF_DC00)
+        "leaq	32(%[sha256]), %%rax\n\t"
+    W_K_from_buff(X0, X1, X2, X3, BYTE_FLIP_MASK)
+
+    LOAD_DIGEST()
+
+    SET_W_K_XFER_4(0)
+        "movl	%%r9d, " L4 "\n\t"
+        "rorx	$6, %%r12d, " L1 "\n\t"
+        "xorl	%%r10d, " L4 "\n\t"
+    MsgSched_RORX(X0, X1, X2, X3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  0)
+    MsgSched_RORX(X1, X2, X3, X0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  4)
+    MsgSched_RORX(X2, X3, X0, X1, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  8)
+    MsgSched_RORX(X3, X0, X1, X2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 12)
+
+    SET_W_K_XFER_4(16)
+    MsgSched_RORX(X0, X1, X2, X3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  0)
+    MsgSched_RORX(X1, X2, X3, X0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  4)
+    MsgSched_RORX(X2, X3, X0, X1, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  8)
+    MsgSched_RORX(X3, X0, X1, X2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 12)
+
+    SET_W_K_XFER_4(32)
+    MsgSched_RORX(X0, X1, X2, X3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  0)
+    MsgSched_RORX(X1, X2, X3, X0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  4)
+    MsgSched_RORX(X2, X3, X0, X1, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  8)
+    MsgSched_RORX(X3, X0, X1, X2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 12)
+
+    SET_W_K_XFER_4(48)
+        "xorl	" L3 ", " L3 "\n\t"
+    RND_RORX_X4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  0)
+    RND_RORX_X4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  4)
+    RND_RORX_X4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  8)
+    RND_RORX_X4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 12)
+        /* Prev RND: h += Maj(a,b,c) */
+        "addl	" L3 ", %%r8d\n\t"
+
+    STORE_ADD_DIGEST()
+
+        "addq	$64, %%rsp\n\t"
 
         :
-        : [FLIP_16] "m" (mBYTE_FLIP_MASK_16[0]),
-          [FLIP_15] "m" (mBYTE_FLIP_MASK_15[0]),
-          [FLIP_7]  "m" (mBYTE_FLIP_MASK_7[0]),
-          [FLIP_2]  "m" (mBYTE_FLIP_MASK_2),
-          [MAPW_7]  "m" (mMAPtoW_I_7[0]),
-          [MAP1W_2] "m" (mMAP1toW_I_2[0]),
-          [MAP2W_2] "m" (mMAP2toW_I_2[0]),
-          [MAP3W_2] "m" (mMAP3toW_I_2[0]),
-          [digest]  "m" (sha256->digest),
-          [buf]     "m" (sha256->buffer),
-          [K]       "m" (K),
-          [W_K]     "m" (W_K)
-        : SSE_REGs, "memory"
+        : [FLIP]     "m" (mBYTE_FLIP_MASK[0]),
+          [SHUF00BA] "m" (mSHUF_00BA[0]),
+          [SHUFDC00] "m" (mSHUF_DC00[0]),
+          [sha256]   "r" (sha256),
+          [K]        "m" (K)
+        : WORK_REGS, STATE_REGS, XMM_REGS, "memory"
     );
-
-#ifdef WOLFSSL_SMALL_STACK
-    XFREE(W_K, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
 
     return 0;
 }
 
-#endif   /* HAVE_INTEL_AVX2 */
+SHA256_NOINLINE static int Transform_Sha256_AVX1_RORX_Len(wc_Sha256* sha256,
+                                                          word32 len)
+{
+    __asm__ __volatile__ (
+
+        "subq	$64, %%rsp\n\t"
+        "movq	120(%[sha256]), %%rax\n\t"
+
+    Init_Masks(BYTE_FLIP_MASK, SHUF_00BA, SHUF_DC00)
+    LOAD_DIGEST()
+
+        "# Start of loop processing a block\n"
+        "1:\n\t"
+
+    W_K_from_buff(X0, X1, X2, X3, BYTE_FLIP_MASK)
+
+    SET_W_K_XFER_4(0)
+        "movl	%%r9d, " L4 "\n\t"
+        "rorx	$6, %%r12d, " L1 "\n\t"
+        "xorl	%%r10d, " L4 "\n\t"
+    MsgSched_RORX(X0, X1, X2, X3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  0)
+    MsgSched_RORX(X1, X2, X3, X0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  4)
+    MsgSched_RORX(X2, X3, X0, X1, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  8)
+    MsgSched_RORX(X3, X0, X1, X2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 12)
+
+    SET_W_K_XFER_4(16)
+    MsgSched_RORX(X0, X1, X2, X3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  0)
+    MsgSched_RORX(X1, X2, X3, X0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  4)
+    MsgSched_RORX(X2, X3, X0, X1, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  8)
+    MsgSched_RORX(X3, X0, X1, X2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 12)
+
+    SET_W_K_XFER_4(32)
+    MsgSched_RORX(X0, X1, X2, X3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  0)
+    MsgSched_RORX(X1, X2, X3, X0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  4)
+    MsgSched_RORX(X2, X3, X0, X1, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  8)
+    MsgSched_RORX(X3, X0, X1, X2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 12)
+
+    SET_W_K_XFER_4(48)
+        "xorl	" L3 ", " L3 "\n\t"
+        "xorl	" L2 ", " L2 "\n\t"
+    RND_RORX_X4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  0)
+    RND_RORX_X4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  4)
+    RND_RORX_X4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  8)
+    RND_RORX_X4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 12)
+        /* Prev RND: h += Maj(a,b,c) */
+        "addl	" L3 ", %%r8d\n\t"
+        "movq	120(%[sha256]), %%rax\n\t"
+
+    ADD_DIGEST()
+
+        "addq	$64, %%rax\n\t"
+        "subl	$64, %[len]\n\t"
+
+    STORE_DIGEST()
+
+        "movq	%%rax, 120(%[sha256])\n\t"
+        "jnz	1b\n\t"
+
+        "addq	$64, %%rsp\n\t"
+
+        :
+        : [FLIP]     "m" (mBYTE_FLIP_MASK[0]),
+          [SHUF00BA] "m" (mSHUF_00BA[0]),
+          [SHUFDC00] "m" (mSHUF_DC00[0]),
+          [sha256]   "r" (sha256),
+          [len]      "r" (len),
+          [K]        "m" (K)
+        : WORK_REGS, STATE_REGS, XMM_REGS, "memory"
+    );
+
+    return 0;
+}
+#endif /* HAVE_INTEL_AVX2 && HAVE_INTEL_RORX */
+
+
+#if defined(HAVE_INTEL_AVX2)
+#define Y0 %ymm0
+#define Y1 %ymm1
+#define Y2 %ymm2
+#define Y3 %ymm3
+
+#define YTMP0 %ymm4
+#define YTMP1 %ymm5
+#define YTMP2 %ymm6
+#define YTMP3 %ymm7
+#define YTMP4 %ymm8
+#define YTMP5 %ymm9
+#define YXFER %ymm10
+
+#define SHUF_Y_00BA       %ymm11 /* shuffle xBxA -> 00BA */
+#define SHUF_Y_DC00       %ymm12 /* shuffle xDxC -> DC00 */
+#define BYTE_FLIP_Y_MASK  %ymm13
+
+#define YMM_REGS "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", \
+                 "ymm7", "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13"
+
+#define MsgSched_Y(Y0,Y1,Y2,Y3,a,b,c,d,e,f,g,h,_i)                            \
+            RND_STEP_0_1(a,b,c,d,e,f,g,h,_i)                                  \
+    VPALIGNR (YTMP1, Y1, Y0, 4)    /* YTMP1 = W[-15] */                       \
+    VPALIGNR (YTMP0, Y3, Y2, 4)    /* YTMP0 = W[-7] */                        \
+            RND_STEP_0_2(a,b,c,d,e,f,g,h,_i)                                  \
+            RND_STEP_0_3(a,b,c,d,e,f,g,h,_i)                                  \
+    VPSRLD   (YTMP2, YTMP1, 7)     /* YTMP2 = W[-15] >> 7 */                  \
+    VPSLLD   (YTMP3, YTMP1, 25)    /* YTEMP3 = W[-15] << (32-7) */            \
+            RND_STEP_0_4(a,b,c,d,e,f,g,h,_i)                                  \
+            RND_STEP_0_5(a,b,c,d,e,f,g,h,_i)                                  \
+    VPSRLD   (YTMP4, YTMP1, 18)    /* YTEMP4 = W[-15] >> 18 */                \
+    VPSLLD   (YTMP5, YTMP1, 14)    /* YTEMP5 = W[-15] << (32-18) */           \
+            RND_STEP_0_6(a,b,c,d,e,f,g,h,_i)                                  \
+            RND_STEP_0_7(a,b,c,d,e,f,g,h,_i)                                  \
+    VPOR     (YTMP2, YTMP3, YTMP2) /* YTMP2 = W[-15] >>> 7 */                 \
+    VPOR     (YTMP4, YTMP5, YTMP4) /* YTMP4 = W[-15] >>> 18 */                \
+            RND_STEP_0_8(a,b,c,d,e,f,g,h,_i)                                  \
+            RND_STEP_1_1(h,a,b,c,d,e,f,g,_i+1)                                \
+            RND_STEP_1_2(h,a,b,c,d,e,f,g,_i+1)                                \
+    VPSRLD   (YTMP5, YTMP1, 3)     /* YTMP4 = W[-15] >> 3 */                  \
+    VPXOR    (YTMP2, YTMP4, YTMP2) /* YTMP2 = W[-15] >>> 7 ^ W[-15] >>> 18 */ \
+            RND_STEP_1_3(h,a,b,c,d,e,f,g,_i+1)                                \
+            RND_STEP_1_4(h,a,b,c,d,e,f,g,_i+1)                                \
+    VPXOR    (YTMP1, YTMP5, YTMP2)  /* YTMP1 = s0 */                          \
+    VPSHUFD  (YTMP2, Y3, 0b11111010)  /* YTMP2 = W[-2] {BBAA}*/               \
+            RND_STEP_1_5(h,a,b,c,d,e,f,g,_i+1)                                \
+            RND_STEP_1_6(h,a,b,c,d,e,f,g,_i+1)                                \
+    VPSRLD   (YTMP4, YTMP2, 10)      /* YTMP4 = W[-2] >> 10 {BBAA} */         \
+    VPSRLQ   (YTMP3, YTMP2, 19)      /* YTMP3 = W[-2] MY_ROR 19 {xBxA} */     \
+            RND_STEP_1_7(h,a,b,c,d,e,f,g,_i+1)                                \
+            RND_STEP_1_8(h,a,b,c,d,e,f,g,_i+1)                                \
+            RND_STEP_0_1(g,h,a,b,c,d,e,f,_i+2)                                \
+    VPSRLQ   (YTMP2, YTMP2, 17)      /* YTMP2 = W[-2] MY_ROR 17 {xBxA} */     \
+    VPADDD   (YTMP0, YTMP0, Y0)                                               \
+            RND_STEP_0_2(g,h,a,b,c,d,e,f,_i+2)                                \
+            RND_STEP_0_3(g,h,a,b,c,d,e,f,_i+2)                                \
+            RND_STEP_0_4(g,h,a,b,c,d,e,f,_i+2)                                \
+    VPXOR    (YTMP2, YTMP3, YTMP2)                                            \
+    VPADDD   (YTMP0, YTMP0, YTMP1)  /* YTMP0 = W[-16] + W[-7] + s0 */         \
+            RND_STEP_0_5(g,h,a,b,c,d,e,f,_i+2)                                \
+    VPXOR    (YTMP4, YTMP4, YTMP2)   /* YTMP4 = s1 {xBxA} */                  \
+            RND_STEP_0_6(g,h,a,b,c,d,e,f,_i+2)                                \
+    VPSHUFB  (YTMP4, YTMP4, SHUF_Y_00BA)  /* YTMP4 = s1 {00BA} */             \
+            RND_STEP_0_7(g,h,a,b,c,d,e,f,_i+2)                                \
+    VPADDD   (YTMP0, YTMP0, YTMP4)  /* YTMP0 = {..., ..., W[1], W[0]} */      \
+            RND_STEP_0_8(g,h,a,b,c,d,e,f,_i+2)                                \
+            RND_STEP_1_1(f,g,h,a,b,c,d,e,_i+3)                                \
+    VPSHUFD  (YTMP2, YTMP0, 0b01010000) /* YTMP2 = W[-2] {DDCC} */            \
+            RND_STEP_1_2(f,g,h,a,b,c,d,e,_i+3)                                \
+    VPSRLQ   (YTMP4, YTMP2, 17)      /* YTMP4 = W[-2] MY_ROR 17 {xDxC} */     \
+    VPSRLQ   (YTMP3, YTMP2, 19)       /* YTMP3 = W[-2] MY_ROR 19 {xDxC} */    \
+            RND_STEP_1_3(f,g,h,a,b,c,d,e,_i+3)                                \
+            RND_STEP_1_4(f,g,h,a,b,c,d,e,_i+3)                                \
+    VPSRLD   (YTMP5, YTMP2, 10)       /* YTMP5 = W[-2] >> 10 {DDCC} */        \
+    VPXOR    (YTMP4, YTMP3, YTMP4)                                            \
+            RND_STEP_1_5(f,g,h,a,b,c,d,e,_i+3)                                \
+            RND_STEP_1_6(f,g,h,a,b,c,d,e,_i+3)                                \
+    VPXOR    (YTMP5, YTMP4, YTMP5)   /* YTMP5 = s1 {xDxC} */                  \
+            RND_STEP_1_7(f,g,h,a,b,c,d,e,_i+3)                                \
+    VPSHUFB  (YTMP5, YTMP5, SHUF_Y_DC00) /* YTMP5 = s1 {DC00} */              \
+            RND_STEP_1_8(f,g,h,a,b,c,d,e,_i+3)                                \
+    VPADDD   (Y0, YTMP5, YTMP0)      /* Y0 = {W[3], W[2], W[1], W[0]} */
+
+#if defined(HAVE_INTEL_RORX)
+
+#define MsgSched_Y_RORX(Y0,Y1,Y2,Y3,a,b,c,d,e,f,g,h,_i)                       \
+            RND_STEP_RORX_0_1(a,b,c,d,e,f,g,h,_i)                             \
+    VPALIGNR (YTMP1, Y1, Y0, 4)    /* YTMP1 = W[-15] */                       \
+            RND_STEP_RORX_0_2(a,b,c,d,e,f,g,h,_i)                             \
+    VPALIGNR (YTMP0, Y3, Y2, 4)    /* YTMP0 = W[-7] */                        \
+            RND_STEP_RORX_0_3(a,b,c,d,e,f,g,h,_i)                             \
+    VPSRLD   (YTMP2, YTMP1, 7)     /* YTMP2 = W[-15] >> 7 */                  \
+            RND_STEP_RORX_0_4(a,b,c,d,e,f,g,h,_i)                             \
+    VPSLLD   (YTMP3, YTMP1, 25)    /* YTEMP3 = W[-15] << (32-7) */            \
+            RND_STEP_RORX_0_5(a,b,c,d,e,f,g,h,_i)                             \
+    VPSRLD   (YTMP4, YTMP1, 18)    /* YTEMP4 = W[-15] >> 18 */                \
+            RND_STEP_RORX_0_6(a,b,c,d,e,f,g,h,_i)                             \
+    VPSLLD   (YTMP5, YTMP1, 14)    /* YTEMP5 = W[-15] << (32-18) */           \
+            RND_STEP_RORX_0_7(a,b,c,d,e,f,g,h,_i)                             \
+    VPOR     (YTMP2, YTMP2, YTMP3) /* YTMP2 = W[-15] >>> 7 */                 \
+            RND_STEP_RORX_0_8(a,b,c,d,e,f,g,h,_i)                             \
+    VPOR     (YTMP4, YTMP4, YTMP5) /* YTMP4 = W[-15] >>> 18 */                \
+            RND_STEP_RORX_1_1(h,a,b,c,d,e,f,g,_i+1)                           \
+    VPSRLD   (YTMP5, YTMP1, 3)     /* YTMP4 = W[-15] >> 3 */                  \
+            RND_STEP_RORX_1_2(h,a,b,c,d,e,f,g,_i+1)                           \
+    VPXOR    (YTMP2, YTMP2, YTMP4) /* YTMP2 = W[-15] >>> 7 ^ W[-15] >>> 18 */ \
+            RND_STEP_RORX_1_3(h,a,b,c,d,e,f,g,_i+1)                           \
+    VPSHUFD  (YTMP3, Y3, 0b11111010)  /* YTMP2 = W[-2] {BBAA}*/               \
+            RND_STEP_RORX_1_4(h,a,b,c,d,e,f,g,_i+1)                           \
+    VPXOR    (YTMP1, YTMP5, YTMP2)  /* YTMP1 = s0 */                          \
+            RND_STEP_RORX_1_5(h,a,b,c,d,e,f,g,_i+1)                           \
+    VPSRLD   (YTMP4, YTMP3, 10)      /* YTMP4 = W[-2] >> 10 {BBAA} */         \
+            RND_STEP_RORX_1_6(h,a,b,c,d,e,f,g,_i+1)                           \
+    VPSRLQ   (YTMP2, YTMP3, 19)      /* YTMP3 = W[-2] MY_ROR 19 {xBxA} */     \
+            RND_STEP_RORX_1_7(h,a,b,c,d,e,f,g,_i+1)                           \
+    VPSRLQ   (YTMP3, YTMP3, 17)      /* YTMP2 = W[-2] MY_ROR 17 {xBxA} */     \
+            RND_STEP_RORX_1_8(h,a,b,c,d,e,f,g,_i+1)                           \
+    VPADDD   (YTMP0, YTMP0, Y0)                                               \
+            RND_STEP_RORX_0_1(g,h,a,b,c,d,e,f,_i+2)                           \
+    VPXOR    (YTMP2, YTMP2, YTMP3)                                            \
+            RND_STEP_RORX_0_2(g,h,a,b,c,d,e,f,_i+2)                           \
+    VPXOR    (YTMP4, YTMP4, YTMP2)   /* YTMP4 = s1 {xBxA} */                  \
+            RND_STEP_RORX_0_3(g,h,a,b,c,d,e,f,_i+2)                           \
+    VPADDD   (YTMP0, YTMP0, YTMP1)  /* YTMP0 = W[-16] + W[-7] + s0 */         \
+            RND_STEP_RORX_0_4(g,h,a,b,c,d,e,f,_i+2)                           \
+    VPSHUFB  (YTMP4, YTMP4, SHUF_Y_00BA)  /* YTMP4 = s1 {00BA} */             \
+            RND_STEP_RORX_0_5(g,h,a,b,c,d,e,f,_i+2)                           \
+    VPADDD   (YTMP0, YTMP0, YTMP4)  /* YTMP0 = {..., ..., W[1], W[0]} */      \
+            RND_STEP_RORX_0_6(g,h,a,b,c,d,e,f,_i+2)                           \
+    VPSHUFD  (YTMP2, YTMP0, 0b01010000) /* YTMP2 = W[-2] {DDCC} */            \
+            RND_STEP_RORX_0_7(g,h,a,b,c,d,e,f,_i+2)                           \
+            RND_STEP_RORX_0_8(g,h,a,b,c,d,e,f,_i+2)                           \
+    VPSRLQ   (YTMP4, YTMP2, 17)      /* YTMP4 = W[-2] MY_ROR 17 {xDxC} */     \
+            RND_STEP_RORX_1_1(f,g,h,a,b,c,d,e,_i+3)                           \
+    VPSRLQ   (YTMP3, YTMP2, 19)       /* YTMP3 = W[-2] MY_ROR 19 {xDxC} */    \
+            RND_STEP_RORX_1_2(f,g,h,a,b,c,d,e,_i+3)                           \
+    VPSRLD   (YTMP5, YTMP2, 10)       /* YTMP5 = W[-2] >> 10 {DDCC} */        \
+            RND_STEP_RORX_1_3(f,g,h,a,b,c,d,e,_i+3)                           \
+    VPXOR    (YTMP4, YTMP4, YTMP3)                                            \
+            RND_STEP_RORX_1_4(f,g,h,a,b,c,d,e,_i+3)                           \
+    VPXOR    (YTMP5, YTMP5, YTMP4)   /* YTMP5 = s1 {xDxC} */                  \
+            RND_STEP_RORX_1_5(f,g,h,a,b,c,d,e,_i+3)                           \
+            RND_STEP_RORX_1_6(f,g,h,a,b,c,d,e,_i+3)                           \
+    VPSHUFB  (YTMP5, YTMP5, SHUF_Y_DC00) /* YTMP5 = s1 {DC00} */              \
+            RND_STEP_RORX_1_7(f,g,h,a,b,c,d,e,_i+3)                           \
+            RND_STEP_RORX_1_8(f,g,h,a,b,c,d,e,_i+3)                           \
+    VPADDD   (Y0, YTMP5, YTMP0)      /* Y0 = {W[3], W[2], W[1], W[0]} */      \
+
+#endif /* HAVE_INTEL_RORX */
+
+#define _VINSERTI128(op1,op2,op3,op4) \
+    "vinserti128	$" #op4 ", %" #op3 ", %" #op2 ", %" #op1 "\n\t"
+#define VINSERTI128(op1,op2,op3,op4)  \
+       _VINSERTI128(op1,op2,op3,op4)
+
+
+#define _LOAD_W_K_LOW(BYTE_FLIP_MASK, reg)   \
+    "# X0, X1, X2, X3 = W[0..15]\n\t"        \
+    "vmovdqu	  (%%" #reg "), %%xmm0\n\t"  \
+    "vmovdqu	16(%%" #reg "), %%xmm1\n\t"  \
+    VPSHUFB(X0, X0, BYTE_FLIP_MASK)          \
+    VPSHUFB(X1, X1, BYTE_FLIP_MASK)          \
+    "vmovdqu	32(%%" #reg "), %%xmm2\n\t"  \
+    "vmovdqu	48(%%" #reg "), %%xmm3\n\t"  \
+    VPSHUFB(X2, X2, BYTE_FLIP_MASK)          \
+    VPSHUFB(X3, X3, BYTE_FLIP_MASK)
+
+#define LOAD_W_K_LOW(BYTE_FLIP_MASK, reg) \
+       _LOAD_W_K_LOW(BYTE_FLIP_MASK, reg)
+
+
+#define _LOAD_W_K(BYTE_FLIP_Y_MASK, reg)      \
+    "# X0, X1, X2, X3 = W[0..15]\n\t"         \
+    "vmovdqu	   (%%" #reg "), %%xmm0\n\t"  \
+    "vmovdqu	 16(%%" #reg "), %%xmm1\n\t"  \
+    "vmovdqu	 64(%%" #reg "), %%xmm4\n\t"  \
+    "vmovdqu	 80(%%" #reg "), %%xmm5\n\t"  \
+    VINSERTI128(Y0, Y0, XTMP0, 1)             \
+    VINSERTI128(Y1, Y1, XTMP1, 1)             \
+    VPSHUFB(Y0, Y0, BYTE_FLIP_Y_MASK)         \
+    VPSHUFB(Y1, Y1, BYTE_FLIP_Y_MASK)         \
+    "vmovdqu	 32(%%" #reg "), %%xmm2\n\t"  \
+    "vmovdqu	 48(%%" #reg "), %%xmm3\n\t"  \
+    "vmovdqu	 96(%%" #reg "), %%xmm6\n\t"  \
+    "vmovdqu	112(%%" #reg "), %%xmm7\n\t"  \
+    VINSERTI128(Y2, Y2, XTMP2, 1)             \
+    VINSERTI128(Y3, Y3, XTMP3, 1)             \
+    VPSHUFB(Y2, Y2, BYTE_FLIP_Y_MASK)         \
+    VPSHUFB(Y3, Y3, BYTE_FLIP_Y_MASK)
+
+#define LOAD_W_K(BYTE_FLIP_Y_MASK, reg) \
+       _LOAD_W_K(BYTE_FLIP_Y_MASK, reg)
+
+
+#define _SET_W_Y_4(i)  \
+    "vpaddd	(" #i "*8)+ 0+%[K], %%ymm0, %%ymm4\n\t" \
+    "vpaddd	(" #i "*8)+32+%[K], %%ymm1, %%ymm5\n\t" \
+    "vmovdqu	%%ymm4, (" #i "*8)+ 0(" WK ")\n\t"      \
+    "vmovdqu	%%ymm5, (" #i "*8)+32(" WK ")\n\t"      \
+    "vpaddd	(" #i "*8)+64+%[K], %%ymm2, %%ymm4\n\t" \
+    "vpaddd	(" #i "*8)+96+%[K], %%ymm3, %%ymm5\n\t" \
+    "vmovdqu	%%ymm4, (" #i "*8)+64(" WK ")\n\t"      \
+    "vmovdqu	%%ymm5, (" #i "*8)+96(" WK ")\n\t"
+
+#define SET_W_Y_4(i) \
+       _SET_W_Y_4(i)
+
+
+static const ALIGN32 word64 mSHUF_Y_00BA[] =
+    { 0x0b0a090803020100, 0xFFFFFFFFFFFFFFFF,
+      0x0b0a090803020100, 0xFFFFFFFFFFFFFFFF }; /* shuffle xBxA -> 00BA */
+static const ALIGN32 word64 mSHUF_Y_DC00[] =
+    { 0xFFFFFFFFFFFFFFFF, 0x0b0a090803020100,
+      0xFFFFFFFFFFFFFFFF, 0x0b0a090803020100 }; /* shuffle xDxC -> DC00 */
+static const ALIGN32 word64 mBYTE_FLIP_Y_MASK[] =
+    { 0x0405060700010203, 0x0c0d0e0f08090a0b,
+      0x0405060700010203, 0x0c0d0e0f08090a0b };
+
+#define _INIT_MASKS_Y(BYTE_FLIP_MASK, SHUF_00BA, SHUF_DC00) \
+    "vmovdqa	%[FLIP], %" #BYTE_FLIP_MASK "\n\t"          \
+    "vmovdqa	%[SHUF00BA], %" #SHUF_00BA "\n\t"           \
+    "vmovdqa	%[SHUFDC00], %" #SHUF_DC00 "\n\t"
+
+#define INIT_MASKS_Y(BYTE_FLIP_MASK, SHUF_00BA, SHUF_DC00) \
+       _INIT_MASKS_Y(BYTE_FLIP_MASK, SHUF_00BA, SHUF_DC00)
+
+static const ALIGN32 word32 K256[128] = {
+    0x428A2F98L, 0x71374491L, 0xB5C0FBCFL, 0xE9B5DBA5L,
+    0x428A2F98L, 0x71374491L, 0xB5C0FBCFL, 0xE9B5DBA5L,
+    0x3956C25BL, 0x59F111F1L, 0x923F82A4L, 0xAB1C5ED5L,
+    0x3956C25BL, 0x59F111F1L, 0x923F82A4L, 0xAB1C5ED5L,
+    0xD807AA98L, 0x12835B01L, 0x243185BEL, 0x550C7DC3L,
+    0xD807AA98L, 0x12835B01L, 0x243185BEL, 0x550C7DC3L,
+    0x72BE5D74L, 0x80DEB1FEL, 0x9BDC06A7L, 0xC19BF174L,
+    0x72BE5D74L, 0x80DEB1FEL, 0x9BDC06A7L, 0xC19BF174L,
+    0xE49B69C1L, 0xEFBE4786L, 0x0FC19DC6L, 0x240CA1CCL,
+    0xE49B69C1L, 0xEFBE4786L, 0x0FC19DC6L, 0x240CA1CCL,
+    0x2DE92C6FL, 0x4A7484AAL, 0x5CB0A9DCL, 0x76F988DAL,
+    0x2DE92C6FL, 0x4A7484AAL, 0x5CB0A9DCL, 0x76F988DAL,
+    0x983E5152L, 0xA831C66DL, 0xB00327C8L, 0xBF597FC7L,
+    0x983E5152L, 0xA831C66DL, 0xB00327C8L, 0xBF597FC7L,
+    0xC6E00BF3L, 0xD5A79147L, 0x06CA6351L, 0x14292967L,
+    0xC6E00BF3L, 0xD5A79147L, 0x06CA6351L, 0x14292967L,
+    0x27B70A85L, 0x2E1B2138L, 0x4D2C6DFCL, 0x53380D13L,
+    0x27B70A85L, 0x2E1B2138L, 0x4D2C6DFCL, 0x53380D13L,
+    0x650A7354L, 0x766A0ABBL, 0x81C2C92EL, 0x92722C85L,
+    0x650A7354L, 0x766A0ABBL, 0x81C2C92EL, 0x92722C85L,
+    0xA2BFE8A1L, 0xA81A664BL, 0xC24B8B70L, 0xC76C51A3L,
+    0xA2BFE8A1L, 0xA81A664BL, 0xC24B8B70L, 0xC76C51A3L,
+    0xD192E819L, 0xD6990624L, 0xF40E3585L, 0x106AA070L,
+    0xD192E819L, 0xD6990624L, 0xF40E3585L, 0x106AA070L,
+    0x19A4C116L, 0x1E376C08L, 0x2748774CL, 0x34B0BCB5L,
+    0x19A4C116L, 0x1E376C08L, 0x2748774CL, 0x34B0BCB5L,
+    0x391C0CB3L, 0x4ED8AA4AL, 0x5B9CCA4FL, 0x682E6FF3L,
+    0x391C0CB3L, 0x4ED8AA4AL, 0x5B9CCA4FL, 0x682E6FF3L,
+    0x748F82EEL, 0x78A5636FL, 0x84C87814L, 0x8CC70208L,
+    0x748F82EEL, 0x78A5636FL, 0x84C87814L, 0x8CC70208L,
+    0x90BEFFFAL, 0xA4506CEBL, 0xBEF9A3F7L, 0xC67178F2L,
+    0x90BEFFFAL, 0xA4506CEBL, 0xBEF9A3F7L, 0xC67178F2L
+};
+
+SHA256_NOINLINE static int Transform_Sha256_AVX2(wc_Sha256* sha256)
+{
+    __asm__ __volatile__ (
+
+        "subq	$512, %%rsp\n\t"
+        "leaq	32(%[sha256]), %%rax\n\t"
+
+    INIT_MASKS_Y(BYTE_FLIP_MASK, SHUF_Y_00BA, SHUF_Y_DC00)
+    LOAD_DIGEST()
+
+    LOAD_W_K_LOW(BYTE_FLIP_MASK, rax)
+
+        "movl	%%r9d, " L4 "\n\t"
+        "movl	%%r12d, " L1 "\n\t"
+        "xorl	%%r10d, " L4 "\n\t"
+
+    SET_W_Y_4(0)
+    MsgSched_Y(Y0, Y1, Y2, Y3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  0)
+    MsgSched_Y(Y1, Y2, Y3, Y0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  8)
+    MsgSched_Y(Y2, Y3, Y0, Y1, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 16)
+    MsgSched_Y(Y3, Y0, Y1, Y2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 24)
+
+    SET_W_Y_4(16)
+    MsgSched_Y(Y0, Y1, Y2, Y3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 32)
+    MsgSched_Y(Y1, Y2, Y3, Y0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 40)
+    MsgSched_Y(Y2, Y3, Y0, Y1, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 48)
+    MsgSched_Y(Y3, Y0, Y1, Y2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 56)
+
+    SET_W_Y_4(32)
+    MsgSched_Y(Y0, Y1, Y2, Y3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 64)
+    MsgSched_Y(Y1, Y2, Y3, Y0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 72)
+    MsgSched_Y(Y2, Y3, Y0, Y1, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 80)
+    MsgSched_Y(Y3, Y0, Y1, Y2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 88)
+
+    SET_W_Y_4(48)
+    RND_ALL_4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  96)
+    RND_ALL_4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 104)
+    RND_ALL_4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 112)
+    RND_ALL_4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 120)
+
+    STORE_ADD_DIGEST()
+
+        "addq	$512, %%rsp\n\t"
+
+        :
+        : [FLIP]     "m" (mBYTE_FLIP_MASK[0]),
+          [SHUF00BA] "m" (mSHUF_Y_00BA[0]),
+          [SHUFDC00] "m" (mSHUF_Y_DC00[0]),
+          [sha256]   "r" (sha256),
+          [K]        "m" (K256)
+        : WORK_REGS, STATE_REGS, YMM_REGS, "memory"
+    );
+
+    return 0;
+}
+
+SHA256_NOINLINE static int Transform_Sha256_AVX2_Len(wc_Sha256* sha256,
+                                                     word32 len)
+{
+    if ((len & WC_SHA256_BLOCK_SIZE) != 0) {
+        XMEMCPY(sha256->buffer, sha256->data, WC_SHA256_BLOCK_SIZE);
+        Transform_Sha256_AVX2(sha256);
+        sha256->data += WC_SHA256_BLOCK_SIZE;
+        len -= WC_SHA256_BLOCK_SIZE;
+        if (len == 0)
+    return 0;
+}
+
+    __asm__ __volatile__ (
+
+        "subq	$512, %%rsp\n\t"
+        "movq	120(%[sha256]), %%rax\n\t"
+
+    INIT_MASKS_Y(BYTE_FLIP_Y_MASK, SHUF_Y_00BA, SHUF_Y_DC00)
+    LOAD_DIGEST()
+
+        "# Start of loop processing two blocks\n"
+        "1:\n\t"
+
+    LOAD_W_K(BYTE_FLIP_Y_MASK, rax)
+
+        "movl	%%r9d, " L4 "\n\t"
+        "movl	%%r12d, " L1 "\n\t"
+        "xorl	%%r10d, " L4 "\n\t"
+
+    SET_W_Y_4(0)
+    MsgSched_Y(Y0, Y1, Y2, Y3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  0)
+    MsgSched_Y(Y1, Y2, Y3, Y0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  8)
+    MsgSched_Y(Y2, Y3, Y0, Y1, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 16)
+    MsgSched_Y(Y3, Y0, Y1, Y2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 24)
+
+    SET_W_Y_4(16)
+    MsgSched_Y(Y0, Y1, Y2, Y3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 32)
+    MsgSched_Y(Y1, Y2, Y3, Y0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 40)
+    MsgSched_Y(Y2, Y3, Y0, Y1, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 48)
+    MsgSched_Y(Y3, Y0, Y1, Y2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 56)
+
+    SET_W_Y_4(32)
+    MsgSched_Y(Y0, Y1, Y2, Y3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 64)
+    MsgSched_Y(Y1, Y2, Y3, Y0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 72)
+    MsgSched_Y(Y2, Y3, Y0, Y1, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 80)
+    MsgSched_Y(Y3, Y0, Y1, Y2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 88)
+
+    SET_W_Y_4(48)
+    RND_ALL_4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  96)
+    RND_ALL_4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 104)
+    RND_ALL_4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 112)
+    RND_ALL_4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 120)
+
+    ADD_DIGEST()
+    STORE_DIGEST()
+
+        "movl	%%r9d, " L4 "\n\t"
+        "movl	%%r12d, " L1 "\n\t"
+        "xorl	%%r10d, " L4 "\n\t"
+
+    RND_ALL_4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,   4)
+    RND_ALL_4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  12)
+    RND_ALL_4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  20)
+    RND_ALL_4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  28)
+    RND_ALL_4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  36)
+    RND_ALL_4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  44)
+    RND_ALL_4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  52)
+    RND_ALL_4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  60)
+    RND_ALL_4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  68)
+    RND_ALL_4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  76)
+    RND_ALL_4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  84)
+    RND_ALL_4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  92)
+    RND_ALL_4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 100)
+    RND_ALL_4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 108)
+    RND_ALL_4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 116)
+    RND_ALL_4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 124)
+
+    ADD_DIGEST()
+
+        "movq	120(%[sha256]), %%rax\n\t"
+        "addq	$128, %%rax\n\t"
+        "subl	$128, %[len]\n\t"
+
+    STORE_DIGEST()
+
+        "movq	%%rax, 120(%[sha256])\n\t"
+        "jnz	1b\n\t"
+
+        "addq	$512, %%rsp\n\t"
+
+        :
+        : [FLIP]     "m" (mBYTE_FLIP_Y_MASK[0]),
+          [SHUF00BA] "m" (mSHUF_Y_00BA[0]),
+          [SHUFDC00] "m" (mSHUF_Y_DC00[0]),
+          [sha256]   "r" (sha256),
+          [len]      "r" (len),
+          [K]        "m" (K256)
+        : WORK_REGS, STATE_REGS, YMM_REGS, "memory"
+    );
+
+    return 0;
+        }
+
+#if defined(HAVE_INTEL_RORX)
+SHA256_NOINLINE static int Transform_Sha256_AVX2_RORX(wc_Sha256* sha256)
+{
+    __asm__ __volatile__ (
+
+        "subq	$512, %%rsp\n\t"
+        "leaq	32(%[sha256]), %%rax\n\t"
+
+    INIT_MASKS_Y(BYTE_FLIP_MASK, SHUF_Y_00BA, SHUF_Y_DC00)
+    LOAD_W_K_LOW(BYTE_FLIP_MASK, rax)
+
+    LOAD_DIGEST()
+
+        "movl	%%r9d, " L4 "\n\t"
+        "rorx	$6, %%r12d, " L1 "\n\t"
+        "xorl	%%r10d, " L4 "\n\t"
+
+    SET_W_Y_4(0)
+    MsgSched_Y_RORX(Y0, Y1, Y2, Y3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  0)
+    MsgSched_Y_RORX(Y1, Y2, Y3, Y0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  8)
+    MsgSched_Y_RORX(Y2, Y3, Y0, Y1, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 16)
+    MsgSched_Y_RORX(Y3, Y0, Y1, Y2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 24)
+
+    SET_W_Y_4(16)
+    MsgSched_Y_RORX(Y0, Y1, Y2, Y3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 32)
+    MsgSched_Y_RORX(Y1, Y2, Y3, Y0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 40)
+    MsgSched_Y_RORX(Y2, Y3, Y0, Y1, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 48)
+    MsgSched_Y_RORX(Y3, Y0, Y1, Y2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 56)
+
+    SET_W_Y_4(32)
+    MsgSched_Y_RORX(Y0, Y1, Y2, Y3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 64)
+    MsgSched_Y_RORX(Y1, Y2, Y3, Y0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 72)
+    MsgSched_Y_RORX(Y2, Y3, Y0, Y1, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 80)
+    MsgSched_Y_RORX(Y3, Y0, Y1, Y2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 88)
+
+    SET_W_Y_4(48)
+        "xorl	" L3 ", " L3 "\n\t"
+        "xorl	" L2 ", " L2 "\n\t"
+    RND_RORX_X4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  96)
+    RND_RORX_X4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 104)
+    RND_RORX_X4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 112)
+    RND_RORX_X4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 120)
+        /* Prev RND: h += Maj(a,b,c) */
+        "addl	" L3 ", %%r8d\n\t"
+
+    STORE_ADD_DIGEST()
+
+        "addq	$512, %%rsp\n\t"
+
+        :
+        : [FLIP]     "m" (mBYTE_FLIP_MASK[0]),
+          [SHUF00BA] "m" (mSHUF_Y_00BA[0]),
+          [SHUFDC00] "m" (mSHUF_Y_DC00[0]),
+          [sha256]   "r" (sha256),
+          [K]        "m" (K256)
+        : WORK_REGS, STATE_REGS, YMM_REGS, "memory"
+    );
+
+        return 0;
+    }
+
+SHA256_NOINLINE static int Transform_Sha256_AVX2_RORX_Len(wc_Sha256* sha256,
+                                                          word32 len)
+    {
+    if ((len & WC_SHA256_BLOCK_SIZE) != 0) {
+        XMEMCPY(sha256->buffer, sha256->data, WC_SHA256_BLOCK_SIZE);
+        Transform_Sha256_AVX2_RORX(sha256);
+        sha256->data += WC_SHA256_BLOCK_SIZE;
+        len -= WC_SHA256_BLOCK_SIZE;
+        if (len == 0)
+            return 0;
+    }
+
+    __asm__ __volatile__ (
+
+        "subq	$512, %%rsp\n\t"
+        "movq	120(%[sha256]), %%rax\n\t"
+
+    INIT_MASKS_Y(BYTE_FLIP_Y_MASK, SHUF_Y_00BA, SHUF_Y_DC00)
+    LOAD_DIGEST()
+
+        "# Start of loop processing two blocks\n"
+        "1:\n\t"
+
+    LOAD_W_K(BYTE_FLIP_Y_MASK, rax)
+
+        "movl	%%r9d, " L4 "\n\t"
+        "rorx	$6, %%r12d, " L1 "\n\t"
+        "xorl	%%r10d, " L4 "\n\t"
+
+    SET_W_Y_4(0)
+    MsgSched_Y_RORX(Y0, Y1, Y2, Y3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  0)
+    MsgSched_Y_RORX(Y1, Y2, Y3, Y0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  8)
+    MsgSched_Y_RORX(Y2, Y3, Y0, Y1, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 16)
+    MsgSched_Y_RORX(Y3, Y0, Y1, Y2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 24)
+
+    SET_W_Y_4(16)
+    MsgSched_Y_RORX(Y0, Y1, Y2, Y3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 32)
+    MsgSched_Y_RORX(Y1, Y2, Y3, Y0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 40)
+    MsgSched_Y_RORX(Y2, Y3, Y0, Y1, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 48)
+    MsgSched_Y_RORX(Y3, Y0, Y1, Y2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 56)
+
+    SET_W_Y_4(32)
+    MsgSched_Y_RORX(Y0, Y1, Y2, Y3, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 64)
+    MsgSched_Y_RORX(Y1, Y2, Y3, Y0, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 72)
+    MsgSched_Y_RORX(Y2, Y3, Y0, Y1, S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 80)
+    MsgSched_Y_RORX(Y3, Y0, Y1, Y2, S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 88)
+
+    SET_W_Y_4(48)
+        "xorl	" L3 ", " L3 "\n\t"
+        "xorl	" L2 ", " L2 "\n\t"
+    RND_RORX_X4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  96)
+    RND_RORX_X4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 104)
+    RND_RORX_X4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 112)
+    RND_RORX_X4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 120)
+        /* Prev RND: h += Maj(a,b,c) */
+        "addl	" L3 ", %%r8d\n\t"
+        "xorl	" L2 ", " L2 "\n\t"
+
+    ADD_DIGEST()
+    STORE_DIGEST()
+
+        "movl	%%r9d, " L4 "\n\t"
+        "xorl	" L3 ", " L3 "\n\t"
+        "xorl	%%r10d, " L4 "\n\t"
+
+    RND_RORX_X4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,   4)
+    RND_RORX_X4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  12)
+    RND_RORX_X4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  20)
+    RND_RORX_X4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  28)
+    RND_RORX_X4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  36)
+    RND_RORX_X4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  44)
+    RND_RORX_X4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  52)
+    RND_RORX_X4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  60)
+    RND_RORX_X4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  68)
+    RND_RORX_X4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  76)
+    RND_RORX_X4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7,  84)
+    RND_RORX_X4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3,  92)
+    RND_RORX_X4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 100)
+    RND_RORX_X4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 108)
+    RND_RORX_X4(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, 116)
+    RND_RORX_X4(S_4, S_5, S_6, S_7, S_0, S_1, S_2, S_3, 124)
+        /* Prev RND: h += Maj(a,b,c) */
+        "addl	" L3 ", %%r8d\n\t"
+        "movq	120(%[sha256]), %%rax\n\t"
+
+    ADD_DIGEST()
+
+        "addq	$128, %%rax\n\t"
+        "subl	$128, %[len]\n\t"
+
+    STORE_DIGEST()
+
+        "movq	%%rax, 120(%[sha256])\n\t"
+        "jnz	1b\n\t"
+
+        "addq	$512, %%rsp\n\t"
+
+        :
+        : [FLIP]     "m" (mBYTE_FLIP_Y_MASK[0]),
+          [SHUF00BA] "m" (mSHUF_Y_00BA[0]),
+          [SHUFDC00] "m" (mSHUF_Y_DC00[0]),
+          [sha256]   "r" (sha256),
+          [len]      "r" (len),
+          [K]        "m" (K256)
+        : WORK_REGS, STATE_REGS, YMM_REGS, "memory"
+    );
+
+    return 0;
+                }
+#endif  /* HAVE_INTEL_RORX */
+#endif  /* HAVE_INTEL_AVX2 */
 
 
 #ifdef WOLFSSL_SHA224
 
-#ifdef STM32_HASH
-
-    #define Sha256Update Sha224Update
-    #define Sha256Final  Sha224Final
-
-    /*
-     * STM32F2/F4/F7 hardware SHA224 support through the HASH_* API's from the
-     * Standard Peripheral Library or CubeMX (See note in README).
-     */
-
-    /* STM32 register size, bytes */
-    #ifdef WOLFSSL_STM32_CUBEMX
-        #define SHA224_REG_SIZE  WC_SHA224_BLOCK_SIZE
-    #else
-        #define SHA224_REG_SIZE  4
-        /* STM32 struct notes:
-         * sha224->buffer  = first 4 bytes used to hold partial block if needed
-         * sha224->buffLen = num bytes currently stored in sha256->buffer
-         * sha224->loLen   = num bytes that have been written to STM32 FIFO
-         */
-    #endif
-    #define SHA224_HW_TIMEOUT 0xFF
-
-    static int InitSha224(wc_Sha224* sha224)
+#ifdef STM32_HASH_SHA2
+
+    /* Supports CubeMX HAL or Standard Peripheral Library */
+
+    int wc_InitSha224_ex(wc_Sha224* sha224, void* heap, int devId)
     {
         if (sha224 == NULL)
             return BAD_FUNC_ARG;
 
-        XMEMSET(sha224->buffer, 0, sizeof(sha224->buffer));
-        sha224->buffLen = 0;
-        sha224->loLen = 0;
-        sha224->hiLen = 0;
-
-        /* initialize HASH peripheral */
-    #ifdef WOLFSSL_STM32_CUBEMX
-        HAL_HASH_DeInit(&sha224->hashHandle);
-        sha224->hashHandle.Init.DataType = HASH_DATATYPE_8B;
-        if (HAL_HASH_Init(&sha224->hashHandle) != HAL_OK) {
-            return ASYNC_INIT_E;
-        }
-        /* required because Cube MX is not clearing algo bits */
-        HASH->CR &= ~HASH_CR_ALGO;
-    #else
-        HASH_DeInit();
-
-        /* reset the hash control register */
-        /* required because Cube MX is not clearing algo bits */
-        HASH->CR &= ~ (HASH_CR_ALGO | HASH_CR_DATATYPE | HASH_CR_MODE);
-
-        /* configure algo used, algo mode, datatype */
-        HASH->CR |= (HASH_AlgoSelection_SHA224 | HASH_AlgoMode_HASH
-                   | HASH_DataType_8b);
-
-        /* reset HASH processor */
-        HASH->CR |= HASH_CR_INIT;
-    #endif
-
+        (void)devId;
+        (void)heap;
+
+        wc_Stm32_Hash_Init(&sha224->stmCtx);
         return 0;
     }
 
-    static int Sha224Update(wc_Sha256* sha224, const byte* data, word32 len)
+    int wc_Sha224Update(wc_Sha224* sha224, const byte* data, word32 len)
     {
         int ret = 0;
-        byte* local;
-
-        /* do block size increments */
-        local = (byte*)sha224->buffer;
-
-        /* check that internal buffLen is valid */
-        if (sha224->buffLen >= SHA224_REG_SIZE)
-            return BUFFER_E;
-
-        while (len) {
-            word32 add = min(len, SHA224_REG_SIZE - sha224->buffLen);
-            XMEMCPY(&local[sha224->buffLen], data, add);
-
-            sha224->buffLen += add;
-            data         += add;
-            len          -= add;
-
-            if (sha224->buffLen == SHA224_REG_SIZE) {
-            #ifdef WOLFSSL_STM32_CUBEMX
-                if (HAL_HASHEx_SHA224_Accumulate(
-                        &sha224->hashHandle, local, SHA224_REG_SIZE) != HAL_OK) {
-                    ret = ASYNC_OP_E;
-                }
-            #else
-                HASH_DataIn(*(uint32_t*)local);
-            #endif
-
-                AddLength(sha224, SHA224_REG_SIZE);
-                sha224->buffLen = 0;
+
+        if (sha224 == NULL || (data == NULL && len > 0)) {
+            return BAD_FUNC_ARG;
             }
+
+        ret = wolfSSL_CryptHwMutexLock();
+        if (ret == 0) {
+            ret = wc_Stm32_Hash_Update(&sha224->stmCtx,
+                HASH_AlgoSelection_SHA224, data, len);
+            wolfSSL_CryptHwMutexUnLock();
         }
         return ret;
     }
 
-    static int Sha224Final(wc_Sha256* sha224)
+    int wc_Sha224Final(wc_Sha224* sha224, byte* hash)
     {
         int ret = 0;
 
-    #ifdef WOLFSSL_STM32_CUBEMX
-        if (HAL_HASHEx_SHA224_Start(&sha224->hashHandle,
-                (byte*)sha224->buffer, sha224->buffLen,
-                (byte*)sha224->digest, SHA224_HW_TIMEOUT) != HAL_OK) {
-            ret = ASYNC_OP_E;
-        }
-    #else
-        __IO uint16_t nbvalidbitsdata = 0;
-
-        /* finish reading any trailing bytes into FIFO */
-        if (sha224->buffLen > 0) {
-            HASH_DataIn(*(uint32_t*)sha224->buffer);
-            AddLength(sha224, sha224->buffLen);
-        }
-
-        /* calculate number of valid bits in last word of input data */
-        nbvalidbitsdata = 8 * (sha224->loLen % SHA224_REG_SIZE);
-
-        /* configure number of valid bits in last word of the data */
-        HASH_SetLastWordValidBitsNbr(nbvalidbitsdata);
-
-        /* start HASH processor */
-        HASH_StartDigest();
-
-        /* wait until Busy flag == RESET */
-        while (HASH_GetFlagStatus(HASH_FLAG_BUSY) != RESET) {}
-
-        /* read message digest */
-        sha224->digest[0] = HASH->HR[0];
-        sha224->digest[1] = HASH->HR[1];
-        sha224->digest[2] = HASH->HR[2];
-        sha224->digest[3] = HASH->HR[3];
-        sha224->digest[4] = HASH->HR[4];
-        sha224->digest[5] = HASH_DIGEST->HR[5];
-        sha224->digest[6] = HASH_DIGEST->HR[6];
-
-        ByteReverseWords(sha224->digest, sha224->digest, SHA224_DIGEST_SIZE);
-    #endif /* WOLFSSL_STM32_CUBEMX */
+        if (sha224 == NULL || hash == NULL) {
+            return BAD_FUNC_ARG;
+        }
+
+        ret = wolfSSL_CryptHwMutexLock();
+        if (ret == 0) {
+            ret = wc_Stm32_Hash_Final(&sha224->stmCtx,
+                HASH_AlgoSelection_SHA224, hash, WC_SHA224_DIGEST_SIZE);
+            wolfSSL_CryptHwMutexUnLock();
+        }
+
+        (void)wc_InitSha224(sha224); /* reset state */
 
         return ret;
     }
 
+#elif defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_HASH)
+    /* functions defined in wolfcrypt/src/port/caam/caam_sha256.c */
+
+#elif defined(WOLFSSL_AFALG_HASH)
+    #error SHA224 currently not supported with AF_ALG enabled
+
+#elif defined(WOLFSSL_DEVCRYPTO_HASH)
+    /* implemented in wolfcrypt/src/port/devcrypto/devcrypt_hash.c */
+
 #else
+
+    #define NEED_SOFT_SHA224
+
 
     static int InitSha224(wc_Sha224* sha224)
@@ -2199,6 +2626,7 @@
     }
 
-#endif /* STM32_HASH */
-
+#endif
+
+#ifdef NEED_SOFT_SHA224
     int wc_InitSha224_ex(wc_Sha224* sha224, void* heap, int devId)
     {
@@ -2213,4 +2641,8 @@
         if (ret != 0)
             return ret;
+
+    #ifdef WOLFSSL_SMALL_STACK_CACHE
+        sha224->W = NULL;
+    #endif
 
     #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_SHA224)
@@ -2224,9 +2656,4 @@
     }
 
-    int wc_InitSha224(wc_Sha224* sha224)
-    {
-        return wc_InitSha224_ex(sha224, NULL, INVALID_DEVID);
-    }
-
     int wc_Sha224Update(wc_Sha224* sha224, const byte* data, word32 len)
     {
@@ -2271,5 +2698,5 @@
             return ret;
 
-    #if defined(LITTLE_ENDIAN_ORDER) && !defined(STM32_HASH)
+    #if defined(LITTLE_ENDIAN_ORDER)
         ByteReverseWords(sha224->digest, sha224->digest, WC_SHA224_DIGEST_SIZE);
     #endif
@@ -2277,4 +2704,10 @@
 
         return InitSha224(sha224);  /* reset state */
+    }
+#endif /* end of SHA224 software implementation */
+
+    int wc_InitSha224(wc_Sha224* sha224)
+    {
+        return wc_InitSha224_ex(sha224, NULL, INVALID_DEVID);
     }
 
@@ -2283,10 +2716,20 @@
         if (sha224 == NULL)
             return;
+
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+    if (sha224->W != NULL) {
+        XFREE(sha224->W, NULL, DYNAMIC_TYPE_DIGEST);
+        sha224->W = NULL;
+    }
+#endif
 
     #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_SHA224)
         wolfAsync_DevCtxFree(&sha224->asyncDev, WOLFSSL_ASYNC_MARKER_SHA224);
     #endif /* WOLFSSL_ASYNC_CRYPT */
-    }
-
+
+    #ifdef WOLFSSL_PIC32MZ_HASH
+        wc_Sha256Pic32Free(sha224);
+    #endif
+    }
 #endif /* WOLFSSL_SHA224 */
 
@@ -2302,7 +2745,37 @@
         return;
 
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+    if (sha256->W != NULL) {
+        XFREE(sha256->W, NULL, DYNAMIC_TYPE_DIGEST);
+        sha256->W = NULL;
+    }
+#endif
+
 #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_SHA256)
     wolfAsync_DevCtxFree(&sha256->asyncDev, WOLFSSL_ASYNC_MARKER_SHA256);
 #endif /* WOLFSSL_ASYNC_CRYPT */
+#ifdef WOLFSSL_PIC32MZ_HASH
+    wc_Sha256Pic32Free(sha256);
+#endif
+#if defined(WOLFSSL_AFALG_HASH)
+    if (sha256->alFd > 0) {
+        close(sha256->alFd);
+        sha256->alFd = -1; /* avoid possible double close on socket */
+    }
+    if (sha256->rdFd > 0) {
+        close(sha256->rdFd);
+        sha256->rdFd = -1; /* avoid possible double close on socket */
+    }
+#endif /* WOLFSSL_AFALG_HASH */
+#ifdef WOLFSSL_DEVCRYPTO_HASH
+    wc_DevCryptoFree(&sha256->ctx);
+#endif /* WOLFSSL_DEVCRYPTO */
+#if defined(WOLFSSL_AFALG_HASH_KEEP) || \
+    (defined(WOLFSSL_DEVCRYPTO_HASH) && defined(WOLFSSL_DEVCRYPTO_HASH_KEEP))
+    if (sha256->msg != NULL) {
+        XFREE(sha256->msg, sha256->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        sha256->msg = NULL;
+    }
+#endif
 }
 
@@ -2324,4 +2797,5 @@
         if (ret == 0) {
             ret = wc_Sha224Final(&tmpSha224, hash);
+            wc_Sha224Free(&tmpSha224);
         }
         return ret;
@@ -2335,4 +2809,7 @@
 
         XMEMCPY(dst, src, sizeof(wc_Sha224));
+    #ifdef WOLFSSL_SMALL_STACK_CACHE
+        dst->W = NULL;
+    #endif
 
     #ifdef WOLFSSL_ASYNC_CRYPT
@@ -2343,4 +2820,12 @@
     }
 #endif /* WOLFSSL_SHA224 */
+
+#ifdef WOLFSSL_AFALG_HASH
+    /* implemented in wolfcrypt/src/port/af_alg/afalg_hash.c */
+
+#elif defined(WOLFSSL_DEVCRYPTO_HASH)
+    /* implemented in wolfcrypt/src/port/devcrypto/devcrypt_hash.c */
+
+#else
 
 int wc_Sha256GetHash(wc_Sha256* sha256, byte* hash)
@@ -2355,4 +2840,5 @@
     if (ret == 0) {
         ret = wc_Sha256Final(&tmpSha256, hash);
+        wc_Sha256Free(&tmpSha256);
     }
     return ret;
@@ -2366,4 +2852,7 @@
 
     XMEMCPY(dst, src, sizeof(wc_Sha256));
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+    dst->W = NULL;
+#endif
 
 #ifdef WOLFSSL_ASYNC_CRYPT
@@ -2376,4 +2865,5 @@
     return ret;
 }
+#endif
 #endif /* !WOLFSSL_TI_HASH */
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/sha512.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/sha512.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/sha512.c	(revision 372)
@@ -27,11 +27,33 @@
 #include <wolfssl/wolfcrypt/settings.h>
 
-#ifdef WOLFSSL_SHA512
+#if defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384)
+
+#if defined(HAVE_FIPS) && \
+	defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+
+    /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+    #define FIPS_NO_WRAPPERS
+
+    #ifdef USE_WINDOWS_API
+        #pragma code_seg(".fipsA$k")
+        #pragma const_seg(".fipsB$k")
+    #endif
+#endif
+
 #include <wolfssl/wolfcrypt/sha512.h>
 #include <wolfssl/wolfcrypt/error-crypt.h>
 #include <wolfssl/wolfcrypt/cpuid.h>
 
+/* deprecated USE_SLOW_SHA2 (replaced with USE_SLOW_SHA512) */
+#if defined(USE_SLOW_SHA2) && !defined(USE_SLOW_SHA512)
+    #define USE_SLOW_SHA512
+#endif
+
 /* fips wrapper calls, user can call direct */
-#ifdef HAVE_FIPS
+#if defined(HAVE_FIPS) && \
+    (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))
+
+    #ifdef WOLFSSL_SHA512
+
     int wc_InitSha512(wc_Sha512* sha)
     {
@@ -72,4 +94,5 @@
         /* Not supported in FIPS */
     }
+    #endif
 
     #if defined(WOLFSSL_SHA384) || defined(HAVE_AESGCM)
@@ -111,5 +134,5 @@
     #endif /* WOLFSSL_SHA384 || HAVE_AESGCM */
 
-#else /* else build without using fips */
+#else /* else build without fips, or for FIPS v2 */
 
 #include <wolfssl/wolfcrypt/logging.h>
@@ -124,6 +147,20 @@
 
 #if defined(USE_INTEL_SPEEDUP)
+    #if defined(__GNUC__) && ((__GNUC__ < 4) || \
+                              (__GNUC__ == 4 && __GNUC_MINOR__ <= 8))
+        #undef  NO_AVX2_SUPPORT
+        #define NO_AVX2_SUPPORT
+    #endif
+    #if defined(__clang__) && ((__clang_major__ < 3) || \
+                               (__clang_major__ == 3 && __clang_minor__ <= 5))
+        #define NO_AVX2_SUPPORT
+    #elif defined(__clang__) && defined(NO_AVX2_SUPPORT)
+        #undef NO_AVX2_SUPPORT
+    #endif
+
     #define HAVE_INTEL_AVX1
+    #ifndef NO_AVX2_SUPPORT
     #define HAVE_INTEL_AVX2
+#endif
 #endif
 
@@ -136,23 +173,4 @@
     /* #define DEBUG_YMM  */
 #endif
-
-
-#if defined(HAVE_INTEL_RORX)
-    #define ROTR(func, bits, x) \
-    word64 func(word64 x) {  word64 ret ;\
-        __asm__ ("rorx $"#bits", %1, %0\n\t":"=r"(ret):"r"(x)) ;\
-        return ret ;\
-    }
-
-    static INLINE ROTR(rotrFixed64_28, 28, x);
-    static INLINE ROTR(rotrFixed64_34, 34, x);
-    static INLINE ROTR(rotrFixed64_39, 39, x);
-    static INLINE ROTR(rotrFixed64_14, 14, x);
-    static INLINE ROTR(rotrFixed64_18, 18, x);
-    static INLINE ROTR(rotrFixed64_41, 41, x);
-
-    #define S0_RORX(x) (rotrFixed64_28(x)^rotrFixed64_34(x)^rotrFixed64_39(x))
-    #define S1_RORX(x) (rotrFixed64_14(x)^rotrFixed64_18(x)^rotrFixed64_41(x))
-#endif /* HAVE_INTEL_RORX */
 
 #if defined(HAVE_BYTEREVERSE64) && \
@@ -167,4 +185,10 @@
 #endif
 
+#if defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_HASH)
+    /* functions defined in wolfcrypt/src/port/caam/caam_sha.c */
+#else
+
+#ifdef WOLFSSL_SHA512
+
 static int InitSha512(wc_Sha512* sha512)
 {
@@ -188,7 +212,10 @@
 }
 
+#endif /* WOLFSSL_SHA512 */
 
 /* Hardware Acceleration */
 #if defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
+
+#ifdef WOLFSSL_SHA512
 
     /*****
@@ -208,9 +235,9 @@
 
     #if defined(HAVE_INTEL_AVX1)|| defined(HAVE_INTEL_AVX2)
-      Transform_AVX1(); # Function prototype
-      Transform_AVX2(); #
+      Transform_Sha512_AVX1(); # Function prototype
+      Transform_Sha512_AVX2(); #
     #endif
 
-      _Transform() {     # Native Transform Function body
+      _Transform_Sha512() {     # Native Transform Function body
 
       }
@@ -241,5 +268,5 @@
     #if defnied(HAVE_INTEL_AVX1)
 
-      int Transform_AVX1() {
+      int Transform_Sha512_AVX1() {
           Stitched Message Sched/Round
       }
@@ -249,5 +276,5 @@
     #if defnied(HAVE_INTEL_AVX2)
 
-      int Transform_AVX2() {
+      int Transform_Sha512_AVX2() {
           Stitched Message Sched/Round
       }
@@ -262,28 +289,27 @@
 
     #if defined(HAVE_INTEL_AVX1)
-        static int Transform_AVX1(wc_Sha512 *sha512);
+        static int Transform_Sha512_AVX1(wc_Sha512 *sha512);
+        static int Transform_Sha512_AVX1_Len(wc_Sha512 *sha512, word32 len);
     #endif
     #if defined(HAVE_INTEL_AVX2)
-        static int Transform_AVX2(wc_Sha512 *sha512);
-        #if defined(HAVE_INTEL_AVX1) && defined(HAVE_INTEL_AVX2) && defined(HAVE_INTEL_RORX)
-            static int Transform_AVX1_RORX(wc_Sha512 *sha512);
+        static int Transform_Sha512_AVX2(wc_Sha512 *sha512);
+        static int Transform_Sha512_AVX2_Len(wc_Sha512 *sha512, word32 len);
+        #if defined(HAVE_INTEL_RORX)
+            static int Transform_Sha512_AVX1_RORX(wc_Sha512 *sha512);
+            static int Transform_Sha512_AVX1_RORX_Len(wc_Sha512 *sha512,
+                                                      word32 len);
+            static int Transform_Sha512_AVX2_RORX(wc_Sha512 *sha512);
+            static int Transform_Sha512_AVX2_RORX_Len(wc_Sha512 *sha512,
+                                                      word32 len);
         #endif
     #endif
-    static int _Transform(wc_Sha512 *sha512);
-    static int (*Transform_p)(wc_Sha512* sha512) = _Transform;
+    static int _Transform_Sha512(wc_Sha512 *sha512);
+    static int (*Transform_Sha512_p)(wc_Sha512* sha512) = _Transform_Sha512;
+    static int (*Transform_Sha512_Len_p)(wc_Sha512* sha512, word32 len) = NULL;
     static int transform_check = 0;
     static int intel_flags;
-    #define Transform(sha512) (*Transform_p)(sha512)
-
-    /* Dummy for saving MM_REGs on behalf of Transform */
-    /* #if defined(HAVE_INTEL_AVX2)
-     #define SAVE_XMM_YMM   __asm__ volatile("orq %%r8, %%r8":::\
-       "%ymm0","%ymm1","%ymm2","%ymm3","%ymm4","%ymm5","%ymm6","%ymm7","%ymm8","%ymm9","%ymm10","%ymm11",\
-       "%ymm12","%ymm13","%ymm14","%ymm15")
-    */
-    #if defined(HAVE_INTEL_AVX1)
-        #define SAVE_XMM_YMM   __asm__ volatile("orq %%r8, %%r8":::\
-            "xmm0","xmm1","xmm2","xmm3","xmm4","xmm5","xmm6","xmm7","xmm8","xmm9","xmm10","xmm11","xmm12","xmm13","xmm14","xmm15")
-    #endif
+    #define Transform_Sha512(sha512)     (*Transform_Sha512_p)(sha512)
+    #define Transform_Sha512_Len(sha512, len) \
+        (*Transform_Sha512_Len_p)(sha512, len)
 
     static void Sha512_SetTransform()
@@ -295,38 +321,44 @@
 
     #if defined(HAVE_INTEL_AVX2)
-        if (IS_INTEL_AVX2(intel_flags) && IS_INTEL_BMI2(intel_flags)) {
-            if (1)
-                Transform_p = Transform_AVX1_RORX;
+        if (IS_INTEL_AVX2(intel_flags)) {
+        #ifdef HAVE_INTEL_RORX
+            if (IS_INTEL_BMI2(intel_flags)) {
+                Transform_Sha512_p = Transform_Sha512_AVX2_RORX;
+                Transform_Sha512_Len_p = Transform_Sha512_AVX2_RORX_Len;
+            }
             else
-                Transform_p = Transform_AVX2;
+        #endif
+            if (1) {
+                Transform_Sha512_p = Transform_Sha512_AVX2;
+                Transform_Sha512_Len_p = Transform_Sha512_AVX2_Len;
+            }
+        #ifdef HAVE_INTEL_RORX
+            else {
+                Transform_Sha512_p = Transform_Sha512_AVX1_RORX;
+                Transform_Sha512_Len_p = Transform_Sha512_AVX1_RORX_Len;
+            }
+        #endif
         }
         else
     #endif
     #if defined(HAVE_INTEL_AVX1)
-        if (1) {
-            Transform_p = ((IS_INTEL_AVX1(intel_flags)) ? Transform_AVX1 :
-                                                                    _Transform);
+        if (IS_INTEL_AVX1(intel_flags)) {
+            Transform_Sha512_p = Transform_Sha512_AVX1;
+            Transform_Sha512_Len_p = Transform_Sha512_AVX1_Len;
         }
         else
     #endif
-            Transform_p = _Transform;
+            Transform_Sha512_p = _Transform_Sha512;
 
         transform_check = 1;
     }
-
-    int wc_InitSha512_ex(wc_Sha512* sha512, void* heap, int devId)
-    {
-        int ret = InitSha512(sha512);
-
-        (void)heap;
-        (void)devId;
-
-        Sha512_SetTransform();
-
-        return ret;
-    }
+#endif /* WOLFSSL_SHA512 */
 
 #else
-    #define Transform(sha512) _Transform(sha512)
+    #define Transform_Sha512(sha512) _Transform_Sha512(sha512)
+
+#endif
+
+#ifdef WOLFSSL_SHA512
 
     int wc_InitSha512_ex(wc_Sha512* sha512, void* heap, int devId)
@@ -342,4 +374,12 @@
         if (ret != 0)
             return ret;
+
+#if defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
+    Sha512_SetTransform();
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+    sha512->W = NULL;
+#endif
 
     #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_SHA512)
@@ -353,9 +393,6 @@
     }
 
-#endif /* Hardware Acceleration */
-
-#ifndef SAVE_XMM_YMM
-    #define SAVE_XMM_YMM
-#endif
+#endif /* WOLFSSL_SHA512 */
+
 
 static const word64 K512[80] = {
@@ -402,9 +439,12 @@
 };
 
-
-
 #define blk0(i) (W[i] = sha512->buffer[i])
 
-#define blk2(i) (W[i&15]+=s1(W[(i-2)&15])+W[(i-7)&15]+s0(W[(i-15)&15]))
+#define blk2(i) (\
+               W[ i     & 15] += \
+            s1(W[(i-2)  & 15])+ \
+               W[(i-7)  & 15] + \
+            s0(W[(i-15) & 15])  \
+        )
 
 #define Ch(x,y,z) (z^(x&(y^z)))
@@ -425,16 +465,25 @@
 #define s1(x) (rotrFixed64(x,19)^rotrFixed64(x,61)^(x>>6))
 
-#define R(i) h(i)+=S1(e(i))+Ch(e(i),f(i),g(i))+K[i+j]+(j?blk2(i):blk0(i));\
-    d(i)+=h(i);h(i)+=S0(a(i))+Maj(a(i),b(i),c(i))
-
-static int _Transform(wc_Sha512* sha512)
+#define R(i) \
+    h(i) += S1(e(i)) + Ch(e(i),f(i),g(i)) + K[i+j] + (j ? blk2(i) : blk0(i)); \
+    d(i) += h(i); \
+    h(i) += S0(a(i)) + Maj(a(i),b(i),c(i))
+
+static int _Transform_Sha512(wc_Sha512* sha512)
 {
     const word64* K = K512;
-
     word32 j;
     word64 T[8];
 
-
-#ifdef WOLFSSL_SMALL_STACK
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+    word64* W = sha512->W;
+    if (W == NULL) {
+        W = (word64*) XMALLOC(sizeof(word64) * 16, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+        if (W == NULL)
+            return MEMORY_E;
+        sha512->W = W;
+    }
+#elif defined(WOLFSSL_SMALL_STACK)
     word64* W;
     W = (word64*) XMALLOC(sizeof(word64) * 16, NULL, DYNAMIC_TYPE_TMP_BUFFER);
@@ -448,5 +497,5 @@
     XMEMCPY(T, sha512->digest, sizeof(T));
 
-#ifdef USE_SLOW_SHA2
+#ifdef USE_SLOW_SHA512
     /* over twice as small, but 50% slower */
     /* 80 operations, not unrolled */
@@ -465,8 +514,7 @@
         R(12); R(13); R(14); R(15);
     }
-#endif /* USE_SLOW_SHA2 */
+#endif /* USE_SLOW_SHA512 */
 
     /* Add the working vars back into digest */
-
     sha512->digest[0] += a(0);
     sha512->digest[1] += b(0);
@@ -482,5 +530,5 @@
     ForceZero(T, sizeof(T));
 
-#ifdef WOLFSSL_SMALL_STACK
+#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE)
     XFREE(W, NULL, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
@@ -490,5 +538,5 @@
 
 
-static INLINE void AddLength(wc_Sha512* sha512, word32 len)
+static WC_INLINE void AddLength(wc_Sha512* sha512, word32 len)
 {
     word64 tmp = sha512->loLen;
@@ -497,5 +545,5 @@
 }
 
-static INLINE int Sha512Update(wc_Sha512* sha512, const byte* data, word32 len)
+static WC_INLINE int Sha512Update(wc_Sha512* sha512, const byte* data, word32 len)
 {
     int ret = 0;
@@ -507,8 +555,7 @@
         return BUFFER_E;
 
-    SAVE_XMM_YMM; /* for Intel AVX */
-
-    while (len) {
+    if (sha512->buffLen > 0) {
         word32 add = min(len, WC_SHA512_BLOCK_SIZE - sha512->buffLen);
+        if (add > 0) {
         XMEMCPY(&local[sha512->buffLen], data, add);
 
@@ -516,4 +563,5 @@
         data            += add;
         len             -= add;
+        }
 
         if (sha512->buffLen == WC_SHA512_BLOCK_SIZE) {
@@ -527,15 +575,75 @@
             }
     #endif
-            ret = Transform(sha512);
+            ret = Transform_Sha512(sha512);
+            if (ret == 0) {
+                AddLength(sha512, WC_SHA512_BLOCK_SIZE);
+                sha512->buffLen = 0;
+            }
+            else
+                len = 0;
+        }
+    }
+
+#if defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
+    if (Transform_Sha512_Len_p != NULL) {
+        word32 blocksLen = len & ~(WC_SHA512_BLOCK_SIZE-1);
+
+        if (blocksLen > 0) {
+            AddLength(sha512, blocksLen);
+            sha512->data = data;
+            /* Byte reversal performed in function if required. */
+            Transform_Sha512_Len(sha512, blocksLen);
+            data += blocksLen;
+            len  -= blocksLen;
+        }
+    }
+    else
+#endif
+#if !defined(LITTLE_ENDIAN_ORDER) || defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
+    {
+        word32 blocksLen = len & ~(WC_SHA512_BLOCK_SIZE-1);
+
+        AddLength(sha512, blocksLen);
+        while (len >= WC_SHA512_BLOCK_SIZE) {
+            XMEMCPY(local, data, WC_SHA512_BLOCK_SIZE);
+
+            data += WC_SHA512_BLOCK_SIZE;
+            len  -= WC_SHA512_BLOCK_SIZE;
+
+            /* Byte reversal performed in function if required. */
+            ret = Transform_Sha512(sha512);
             if (ret != 0)
                 break;
-
-            AddLength(sha512, WC_SHA512_BLOCK_SIZE);
-            sha512->buffLen = 0;
         }
+    }
+#else
+    {
+        word32 blocksLen = len & ~(WC_SHA512_BLOCK_SIZE-1);
+
+        AddLength(sha512, blocksLen);
+        while (len >= WC_SHA512_BLOCK_SIZE) {
+            XMEMCPY(local, data, WC_SHA512_BLOCK_SIZE);
+
+            data += WC_SHA512_BLOCK_SIZE;
+            len  -= WC_SHA512_BLOCK_SIZE;
+
+            ByteReverseWords64(sha512->buffer, sha512->buffer,
+                                                          WC_SHA512_BLOCK_SIZE);
+            ret = Transform_Sha512(sha512);
+            if (ret != 0)
+                break;
+        }
+    }
+#endif
+
+    if (len > 0) {
+        XMEMCPY(local, data, len);
+        sha512->buffLen = len;
     }
 
     return ret;
 }
+
+#ifdef WOLFSSL_SHA512
 
 int wc_Sha512Update(wc_Sha512* sha512, const byte* data, word32 len)
@@ -556,6 +664,9 @@
 }
 
-
-static INLINE int Sha512Final(wc_Sha512* sha512)
+#endif /* WOLFSSL_SHA512 */
+
+#endif /* WOLFSSL_IMX6_CAAM */
+
+static WC_INLINE int Sha512Final(wc_Sha512* sha512)
 {
     byte* local = (byte*)sha512->buffer;
@@ -566,5 +677,4 @@
     }
 
-    SAVE_XMM_YMM ; /* for Intel AVX */
     AddLength(sha512, sha512->buffLen);               /* before adding pads */
 
@@ -584,5 +694,5 @@
         }
 #endif /* LITTLE_ENDIAN_ORDER */
-        ret = Transform(sha512);
+        ret = Transform_Sha512(sha512);
         if (ret != 0)
             return ret;
@@ -614,5 +724,5 @@
                            WC_SHA512_BLOCK_SIZE - WC_SHA512_PAD_SIZE);
 #endif
-    ret = Transform(sha512);
+    ret = Transform_Sha512(sha512);
     if (ret != 0)
         return ret;
@@ -621,4 +731,27 @@
         ByteReverseWords64(sha512->digest, sha512->digest, WC_SHA512_DIGEST_SIZE);
     #endif
+
+    return 0;
+}
+
+#ifdef WOLFSSL_SHA512
+
+int wc_Sha512FinalRaw(wc_Sha512* sha512, byte* hash)
+{
+#ifdef LITTLE_ENDIAN_ORDER
+    word64 digest[WC_SHA512_DIGEST_SIZE / sizeof(word64)];
+#endif
+
+    if (sha512 == NULL || hash == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+#ifdef LITTLE_ENDIAN_ORDER
+    ByteReverseWords64((word64*)digest, (word64*)sha512->digest,
+                                                         WC_SHA512_DIGEST_SIZE);
+    XMEMCPY(hash, digest, WC_SHA512_DIGEST_SIZE);
+#else
+    XMEMCPY(hash, sha512->digest, WC_SHA512_DIGEST_SIZE);
+#endif
 
     return 0;
@@ -662,4 +795,11 @@
         return;
 
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+    if (sha512->W != NULL) {
+        XFREE(sha512->W, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        sha512->W = NULL;
+    }
+#endif
+
 #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_SHA512)
     wolfAsync_DevCtxFree(&sha512->asyncDev, WOLFSSL_ASYNC_MARKER_SHA512);
@@ -670,419 +810,751 @@
 #if defined(HAVE_INTEL_AVX1)
 
-#define Rx_1(i) h(i)+=S1(e(i))+Ch(e(i),f(i),g(i))+K[i+j] + W_X[i];
-#define Rx_2(i) d(i)+=h(i);
-#define Rx_3(i) h(i)+=S0(a(i))+Maj(a(i),b(i),c(i));
+static word64 mBYTE_FLIP_MASK[] =  { 0x0001020304050607, 0x08090a0b0c0d0e0f };
+
+#define W_0     xmm0
+#define W_2     xmm1
+#define W_4     xmm2
+#define W_6     xmm3
+#define W_8     xmm4
+#define W_10    xmm5
+#define W_12    xmm6
+#define W_14    xmm7
+
+#define W_M15   xmm12
+#define W_M7    xmm13
+#define MASK    xmm14
+
+#define XTMP1   xmm8
+#define XTMP2   xmm9
+#define XTMP3   xmm10
+#define XTMP4   xmm11
+
+#define XMM_REGS \
+    "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",       \
+    "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
+
+#define _VPALIGNR(dest, src1, src2, bits)                               \
+    "vpalignr	$" #bits ", %%" #src2 ", %%" #src1 ", %%" #dest "\n\t"
+#define VPALIGNR(dest, src1, src2, bits) \
+       _VPALIGNR(dest, src1, src2, bits)
+
+#define _V_SHIFT_R(dest, src, bits)                             \
+    "vpsrlq	$" #bits ", %%" #src ", %%" #dest "\n\t"
+#define V_SHIFT_R(dest, src, bits) \
+       _V_SHIFT_R(dest, src, bits)
+
+#define _V_SHIFT_L(dest, src, bits)                             \
+    "vpsllq	$" #bits ", %%" #src ", %%" #dest "\n\t"
+#define V_SHIFT_L(dest, src, bits) \
+       _V_SHIFT_L(dest, src, bits)
+
+#define _V_ADD(dest, src1, src2)                                \
+    "vpaddq	%%" #src1 ", %%" #src2 ", %%" #dest "\n\t"
+#define V_ADD(dest, src1, src2) \
+       _V_ADD(dest, src1, src2)
+
+#define _V_XOR(dest, src1, src2)                                \
+    "vpxor	%%" #src1 ", %%" #src2 ", %%" #dest "\n\t"
+#define V_XOR(dest, src1, src2) \
+       _V_XOR(dest, src1, src2)
+
+#define _V_OR(dest, src1, src2)                                 \
+    "vpor	%%" #src1 ", %%" #src2 ", %%" #dest "\n\t"
+#define V_OR(dest, src1, src2) \
+       _V_OR(dest, src1, src2)
+
+#define RA  %%r8
+#define RB  %%r9
+#define RC  %%r10
+#define RD  %%r11
+#define RE  %%r12
+#define RF  %%r13
+#define RG  %%r14
+#define RH  %%r15
+
+#define STATE_REGS "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
+
+#define L1  "%%rax"
+#define L2  "%%rcx"
+#define L3  "%%rdx"
+#define L4  "%%rbx"
+#define WX  "%%rsp"
+
+#define WORK_REGS "rax", "rbx", "rcx", "rdx"
+
+#define RND_0_1(a,b,c,d,e,f,g,h,i)                   \
+    /* L1 = e >>> 23 */                              \
+    "rorq	 $23, " L1 "\n\t"                    \
+
+#define RND_0_2(a,b,c,d,e,f,g,h,i)                   \
+    /* L3 = a */                                     \
+    "movq	"#a", " L3 "\n\t"                    \
+    /* L2 = f */                                     \
+    "movq	"#f", " L2 "\n\t"                    \
+    /* h += W_X[i] */                                \
+    "addq	("#i")*8(" WX "), "#h"\n\t"          \
+    /* L2 = f ^ g */                                 \
+    "xorq	"#g", " L2 "\n\t"                    \
+
+#define RND_0_2_A(a,b,c,d,e,f,g,h,i)                 \
+    /* L3 = a */                                     \
+    "movq	"#a", " L3 "\n\t"                    \
+    /* L2 = f */                                     \
+    "movq	"#f", " L2 "\n\t"                    \
+
+#define RND_0_2_B(a,b,c,d,e,f,g,h,i)                 \
+    /* h += W_X[i] */                                \
+    "addq	("#i")*8(" WX "), "#h"\n\t"          \
+    /* L2 = f ^ g */                                 \
+    "xorq	"#g", " L2 "\n\t"                    \
+
+#define RND_0_3(a,b,c,d,e,f,g,h,i)                   \
+    /* L1 = (e >>> 23) ^ e */                        \
+    "xorq	"#e", " L1 "\n\t"                    \
+    /* L2 = (f ^ g) & e */                           \
+    "andq	"#e", " L2 "\n\t"                    \
+
+#define RND_0_4(a,b,c,d,e,f,g,h,i)                   \
+    /* L1 = ((e >>> 23) ^ e) >>> 4 */                \
+    "rorq	 $4, " L1 "\n\t"                     \
+    /* L2 = ((f ^ g) & e) ^ g */                     \
+    "xorq	"#g", " L2 "\n\t"                    \
+
+#define RND_0_5(a,b,c,d,e,f,g,h,i)                   \
+    /* L1 = (((e >>> 23) ^ e) >>> 4) ^ e */          \
+    "xorq	"#e", " L1 "\n\t"                    \
+    /* h += Ch(e,f,g) */                             \
+    "addq	" L2 ", "#h"\n\t"                    \
+
+#define RND_0_6(a,b,c,d,e,f,g,h,i)                   \
+    /* L1 = ((((e >>> 23) ^ e) >>> 4) ^ e) >>> 14 */ \
+    "rorq	$14, " L1 "\n\t"                     \
+    /* L3 = a ^ b */                                 \
+    "xorq	"#b", " L3 "\n\t"                    \
+
+#define RND_0_7(a,b,c,d,e,f,g,h,i)                   \
+    /* h += Sigma1(e) */                             \
+    "addq	" L1 ", "#h"\n\t"                    \
+    /* L2 = a */                                     \
+    "movq	"#a", " L2 "\n\t"                    \
+
+#define RND_0_8(a,b,c,d,e,f,g,h,i)                   \
+    /* L4 = (a ^ b) & (b ^ c) */                     \
+    "andq	" L3 ", " L4 "\n\t"                  \
+    /* L2 = a >>> 5 */                               \
+    "rorq	$5, " L2 "\n\t"                      \
+
+#define RND_0_9(a,b,c,d,e,f,g,h,i)                   \
+    /* L2 = (a >>> 5) ^ a */                         \
+    "xorq	"#a", " L2 "\n\t"                    \
+    /* L4 = ((a ^ b) & (b ^ c) ^ b */                \
+    "xorq	"#b", " L4 "\n\t"                    \
+
+#define RND_0_10(a,b,c,d,e,f,g,h,i)                  \
+    /* L2 = ((a >>> 5) ^ a) >>> 6 */                 \
+    "rorq	 $6, " L2 "\n\t"                     \
+    /* d += h */                                     \
+    "addq	"#h", "#d"\n\t"                      \
+
+#define RND_0_11(a,b,c,d,e,f,g,h,i)                  \
+    /* L2 = (((a >>> 5) ^ a) >>> 6) ^ a */           \
+    "xorq	"#a", " L2 "\n\t"                    \
+    /* h += Sigma0(a) */                             \
+    "addq	" L4 ", "#h"\n\t"                    \
+
+#define RND_0_12(a,b,c,d,e,f,g,h,i)                  \
+    /* L2 = ((((a >>> 5) ^ a) >>> 6) ^ a) >>> 28 */  \
+    "rorq	$28, " L2 "\n\t"                     \
+    /* d (= e next RND) */                           \
+    "movq	"#d", " L1 "\n\t"                    \
+    /* h += Maj(a,b,c) */                            \
+    "addq	" L2 ", "#h"\n\t"                    \
+
+#define RND_1_1(a,b,c,d,e,f,g,h,i)                   \
+    /* L1 = e >>> 23 */                              \
+    "rorq	 $23, " L1 "\n\t"                    \
+
+#define RND_1_2(a,b,c,d,e,f,g,h,i)                   \
+    /* L4 = a */                                     \
+    "movq	"#a", " L4 "\n\t"                    \
+    /* L2 = f */                                     \
+    "movq	"#f", " L2 "\n\t"                    \
+    /* h += W_X[i] */                                \
+    "addq	("#i")*8(" WX "), "#h"\n\t"          \
+    /* L2 = f ^ g */                                 \
+    "xorq	"#g", " L2 "\n\t"                    \
+
+#define RND_1_2_A(a,b,c,d,e,f,g,h,i)                 \
+    /* L4 = a */                                     \
+    "movq	"#a", " L4 "\n\t"                    \
+    /* L2 = f */                                     \
+    "movq	"#f", " L2 "\n\t"                    \
+
+#define RND_1_2_B(a,b,c,d,e,f,g,h,i)                 \
+    /* h += W_X[i] */                                \
+    "addq	("#i")*8(" WX "), "#h"\n\t"          \
+    /* L2 = f ^ g */                                 \
+    "xorq	"#g", " L2 "\n\t"                    \
+
+#define RND_1_3(a,b,c,d,e,f,g,h,i)                   \
+    /* L1 = (e >>> 23) ^ e */                        \
+    "xorq	"#e", " L1 "\n\t"                    \
+    /* L2 = (f ^ g) & e */                           \
+    "andq	"#e", " L2 "\n\t"                    \
+
+#define RND_1_4(a,b,c,d,e,f,g,h,i)                   \
+    /* ((e >>> 23) ^ e) >>> 4 */                     \
+    "rorq	 $4, " L1 "\n\t"                     \
+    /* ((f ^ g) & e) ^ g */                          \
+    "xorq	"#g", " L2 "\n\t"                    \
+
+#define RND_1_5(a,b,c,d,e,f,g,h,i)                   \
+    /* (((e >>> 23) ^ e) >>> 4) ^ e */               \
+    "xorq	"#e", " L1 "\n\t"                    \
+    /* h += Ch(e,f,g) */                             \
+    "addq	" L2 ", "#h"\n\t"                    \
+
+#define RND_1_6(a,b,c,d,e,f,g,h,i)                   \
+    /* L1 = ((((e >>> 23) ^ e) >>> 4) ^ e) >>> 14 */ \
+    "rorq	$14, " L1 "\n\t"                     \
+    /* L4 = a ^ b */                                 \
+    "xorq	"#b", " L4 "\n\t"                    \
+
+#define RND_1_7(a,b,c,d,e,f,g,h,i)                   \
+    /* h += Sigma1(e) */                             \
+    "addq	" L1 ", "#h"\n\t"                    \
+    /* L2 = a */                                     \
+    "movq	"#a", " L2 "\n\t"                    \
+
+#define RND_1_8(a,b,c,d,e,f,g,h,i)                   \
+    /* L3 = (a ^ b) & (b ^ c) */                     \
+    "andq	" L4 ", " L3 "\n\t"                  \
+    /* L2 = a >>> 5 */                               \
+    "rorq	$5, " L2 "\n\t"                      \
+
+#define RND_1_9(a,b,c,d,e,f,g,h,i)                   \
+    /* L2 = (a >>> 5) ^ a */                         \
+    "xorq	"#a", " L2 "\n\t"                    \
+    /* L3 = ((a ^ b) & (b ^ c) ^ b */                \
+    "xorq	"#b", " L3 "\n\t"                    \
+
+#define RND_1_10(a,b,c,d,e,f,g,h,i)                  \
+    /* L2 = ((a >>> 5) ^ a) >>> 6 */                 \
+    "rorq	 $6, " L2 "\n\t"                     \
+    /* d += h */                                     \
+    "addq	"#h", "#d"\n\t"                      \
+
+#define RND_1_11(a,b,c,d,e,f,g,h,i)                  \
+    /* L2 = (((a >>> 5) ^ a) >>> 6) ^ a */           \
+    "xorq	"#a", " L2 "\n\t"                    \
+    /* h += Sigma0(a) */                             \
+    "addq	" L3 ", "#h"\n\t"                    \
+
+#define RND_1_12(a,b,c,d,e,f,g,h,i)                  \
+    /* L2 = ((((a >>> 5) ^ a) >>> 6) ^ a) >>> 28 */  \
+    "rorq	$28, " L2 "\n\t"                     \
+    /* d (= e next RND) */                           \
+    "movq	"#d", " L1 "\n\t"                    \
+    /* h += Maj(a,b,c) */                            \
+    "addq	" L2 ", "#h"\n\t"                    \
+
+
+#define MsgSched2(W_0,W_2,W_4,W_6,W_8,W_10,W_12,W_14,a,b,c,d,e,f,g,h,i) \
+            RND_0_1(a,b,c,d,e,f,g,h,i)                                  \
+    VPALIGNR(W_M15, W_2, W_0, 8)                                        \
+    VPALIGNR(W_M7, W_10, W_8, 8)                                        \
+            RND_0_2(a,b,c,d,e,f,g,h,i)                                  \
+    V_SHIFT_R(XTMP1, W_M15, 1)                                          \
+    V_SHIFT_L(XTMP2, W_M15, 63)                                         \
+            RND_0_3(a,b,c,d,e,f,g,h,i)                                  \
+            RND_0_4(a,b,c,d,e,f,g,h,i)                                  \
+    V_SHIFT_R(XTMP3, W_M15, 8)                                          \
+    V_SHIFT_L(XTMP4, W_M15, 56)                                         \
+            RND_0_5(a,b,c,d,e,f,g,h,i)                                  \
+            RND_0_6(a,b,c,d,e,f,g,h,i)                                  \
+    V_OR(XTMP1, XTMP2, XTMP1)                                           \
+    V_OR(XTMP3, XTMP4, XTMP3)                                           \
+            RND_0_7(a,b,c,d,e,f,g,h,i)                                  \
+            RND_0_8(a,b,c,d,e,f,g,h,i)                                  \
+    V_SHIFT_R(XTMP4, W_M15, 7)                                          \
+    V_XOR(XTMP1, XTMP3, XTMP1)                                          \
+            RND_0_9(a,b,c,d,e,f,g,h,i)                                  \
+            RND_0_10(a,b,c,d,e,f,g,h,i)                                 \
+    V_XOR(XTMP1, XTMP4, XTMP1)                                          \
+    V_ADD(W_0, W_0, W_M7)                                               \
+            RND_0_11(a,b,c,d,e,f,g,h,i)                                 \
+            RND_0_12(a,b,c,d,e,f,g,h,i)                                 \
+            RND_1_1(h,a,b,c,d,e,f,g,i+1)                                \
+    V_ADD(W_0, W_0, XTMP1)                                              \
+            RND_1_2(h,a,b,c,d,e,f,g,i+1)                                \
+    V_SHIFT_R(XTMP1, W_14, 19)                                          \
+    V_SHIFT_L(XTMP2, W_14, 45)                                          \
+            RND_1_3(h,a,b,c,d,e,f,g,i+1)                                \
+            RND_1_4(h,a,b,c,d,e,f,g,i+1)                                \
+    V_SHIFT_R(XTMP3, W_14, 61)                                          \
+    V_SHIFT_L(XTMP4, W_14, 3)                                           \
+            RND_1_5(h,a,b,c,d,e,f,g,i+1)                                \
+            RND_1_6(h,a,b,c,d,e,f,g,i+1)                                \
+            RND_1_7(h,a,b,c,d,e,f,g,i+1)                                \
+    V_OR(XTMP1, XTMP2, XTMP1)                                           \
+    V_OR(XTMP3, XTMP4, XTMP3)                                           \
+            RND_1_8(h,a,b,c,d,e,f,g,i+1)                                \
+            RND_1_9(h,a,b,c,d,e,f,g,i+1)                                \
+    V_XOR(XTMP1, XTMP3, XTMP1)                                          \
+    V_SHIFT_R(XTMP4, W_14, 6)                                           \
+            RND_1_10(h,a,b,c,d,e,f,g,i+1)                               \
+            RND_1_11(h,a,b,c,d,e,f,g,i+1)                               \
+    V_XOR(XTMP1, XTMP4, XTMP1)                                          \
+            RND_1_12(h,a,b,c,d,e,f,g,i+1)                               \
+    V_ADD(W_0, W_0, XTMP1)                                              \
+
+#define RND_ALL_2(a, b, c, d, e, f, g, h, i) \
+    RND_0_1 (a, b, c, d, e, f, g, h, i )     \
+    RND_0_2 (a, b, c, d, e, f, g, h, i )     \
+    RND_0_3 (a, b, c, d, e, f, g, h, i )     \
+    RND_0_4 (a, b, c, d, e, f, g, h, i )     \
+    RND_0_5 (a, b, c, d, e, f, g, h, i )     \
+    RND_0_6 (a, b, c, d, e, f, g, h, i )     \
+    RND_0_7 (a, b, c, d, e, f, g, h, i )     \
+    RND_0_8 (a, b, c, d, e, f, g, h, i )     \
+    RND_0_9 (a, b, c, d, e, f, g, h, i )     \
+    RND_0_10(a, b, c, d, e, f, g, h, i )     \
+    RND_0_11(a, b, c, d, e, f, g, h, i )     \
+    RND_0_12(a, b, c, d, e, f, g, h, i )     \
+    RND_1_1 (h, a, b, c, d, e, f, g, i+1)    \
+    RND_1_2 (h, a, b, c, d, e, f, g, i+1)    \
+    RND_1_3 (h, a, b, c, d, e, f, g, i+1)    \
+    RND_1_4 (h, a, b, c, d, e, f, g, i+1)    \
+    RND_1_5 (h, a, b, c, d, e, f, g, i+1)    \
+    RND_1_6 (h, a, b, c, d, e, f, g, i+1)    \
+    RND_1_7 (h, a, b, c, d, e, f, g, i+1)    \
+    RND_1_8 (h, a, b, c, d, e, f, g, i+1)    \
+    RND_1_9 (h, a, b, c, d, e, f, g, i+1)    \
+    RND_1_10(h, a, b, c, d, e, f, g, i+1)    \
+    RND_1_11(h, a, b, c, d, e, f, g, i+1)    \
+    RND_1_12(h, a, b, c, d, e, f, g, i+1)
+
 
 #if defined(HAVE_INTEL_RORX)
 
-    #define Rx_RORX_1(i) h(i)+=S1_RORX(e(i))+Ch(e(i),f(i),g(i))+K[i+j] + W_X[i];
-    #define Rx_RORX_2(i) d(i)+=h(i);
-    #define Rx_RORX_3(i) h(i)+=S0_RORX(a(i))+Maj(a(i),b(i),c(i));
-#endif /* HAVE_INTEL_RORX */
+#define RND_RORX_0_1(a, b, c, d, e, f, g, h, i) \
+    /* L1 = e>>>14 */                           \
+    "rorxq	$14, "#e", " L1 "\n\t"          \
+    /* L2 = e>>>18 */                           \
+    "rorxq	$18, "#e", " L2 "\n\t"          \
+    /* Prev RND: h += Maj(a,b,c) */             \
+    "addq	" L3 ", "#a"\n\t"               \
+
+#define RND_RORX_0_2(a, b, c, d, e, f, g, h, i) \
+    /* h += w_k */                              \
+    "addq	("#i")*8(" WX "), "#h"\n\t"     \
+    /* L3 = f */                                \
+    "movq	"#f", " L3 "\n\t"               \
+    /* L2 = (e>>>14) ^ (e>>>18) */              \
+    "xorq	" L1 ", " L2 "\n\t"             \
+
+#define RND_RORX_0_3(a, b, c, d, e, f, g, h, i) \
+    /* L3 = f ^ g */                            \
+    "xorq	"#g", " L3 "\n\t"               \
+    /* L1 = e>>>41 */                           \
+    "rorxq	$41, "#e", " L1 "\n\t"          \
+    /* L1 = Sigma1(e) */                        \
+    "xorq	" L2 ", " L1 "\n\t"             \
+
+#define RND_RORX_0_4(a, b, c, d, e, f, g, h, i) \
+    /* L3 = (f ^ g) & e */                      \
+    "andq	"#e", " L3 "\n\t"               \
+    /* h += Sigma1(e) */                        \
+    "addq	" L1 ", "#h"\n\t"               \
+    /* L1 = a>>>28 */                           \
+    "rorxq	$28, "#a", " L1 "\n\t"          \
+
+#define RND_RORX_0_5(a, b, c, d, e, f, g, h, i) \
+    /* L2 = a>>>34 */                           \
+    "rorxq	$34, "#a", " L2 "\n\t"          \
+    /* L3 = Ch(e,f,g) */                        \
+    "xorq	"#g", " L3 "\n\t"               \
+    /* L2 = (a>>>28) ^ (a>>>34) */              \
+    "xorq	" L1 ", " L2 "\n\t"             \
+
+#define RND_RORX_0_6(a, b, c, d, e, f, g, h, i) \
+    /* L1 = a>>>39 */                           \
+    "rorxq	$39, "#a", " L1 "\n\t"          \
+    /* h += Ch(e,f,g) */                        \
+    "addq	" L3 ", "#h"\n\t"               \
+    /* L1 = Sigma0(a) */                        \
+    "xorq	" L2 ", " L1 "\n\t"             \
+
+#define RND_RORX_0_7(a, b, c, d, e, f, g, h, i) \
+    /* L3 = b */                                \
+    "movq	"#b", " L3 "\n\t"               \
+    /* d += h + w_k + Sigma1(e) + Ch(e,f,g) */  \
+    "addq	"#h", "#d"\n\t"                 \
+    /* L3 = a ^ b */                            \
+    "xorq	"#a", " L3 "\n\t"               \
+
+#define RND_RORX_0_8(a, b, c, d, e, f, g, h, i) \
+    /* L4 = (a ^ b) & (b ^ c) */                \
+    "andq	" L3 ", " L4 "\n\t"             \
+    /* h += Sigma0(a) */                        \
+    "addq	" L1 ", "#h"\n\t"               \
+    /* L4 = Maj(a,b,c) */                       \
+    "xorq	"#b", " L4 "\n\t"               \
+
+#define RND_RORX_1_1(a, b, c, d, e, f, g, h, i) \
+    /* L1 = e>>>14 */                           \
+    "rorxq	$14, "#e", " L1 "\n\t"          \
+    /* L2 = e>>>18 */                           \
+    "rorxq	$18, "#e", " L2 "\n\t"          \
+    /* Prev RND: h += Maj(a,b,c) */             \
+    "addq	" L4 ", "#a"\n\t"               \
+
+#define RND_RORX_1_2(a, b, c, d, e, f, g, h, i) \
+    /* h += w_k */                              \
+    "addq	("#i")*8(" WX "), "#h"\n\t"     \
+    /* L4 = f */                                \
+    "movq	"#f", " L4 "\n\t"               \
+    /* L2 = (e>>>14) ^ (e>>>18) */              \
+    "xorq	" L1 ", " L2 "\n\t"             \
+
+#define RND_RORX_1_3(a, b, c, d, e, f, g, h, i) \
+    /* L4 = f ^ g */                            \
+    "xorq	"#g", " L4 "\n\t"               \
+    /* L1 = e>>>41 */                           \
+    "rorxq	$41, "#e", " L1 "\n\t"          \
+    /* L1 = Sigma1(e) */                        \
+    "xorq	" L2 ", " L1 "\n\t"             \
+
+#define RND_RORX_1_4(a, b, c, d, e, f, g, h, i) \
+    /* L4 = (f ^ g) & e */                      \
+    "andq	"#e", " L4 "\n\t"               \
+    /* h += Sigma1(e) */                        \
+    "addq	" L1 ", "#h"\n\t"               \
+    /* L1 = a>>>28 */                           \
+    "rorxq	$28, "#a", " L1 "\n\t"          \
+
+#define RND_RORX_1_5(a, b, c, d, e, f, g, h, i) \
+    /* L2 = a>>>34 */                           \
+    "rorxq	$34, "#a", " L2 "\n\t"          \
+    /* L4 = Ch(e,f,g) */                        \
+    "xorq	"#g", " L4 "\n\t"               \
+    /* L2 = (a>>>28) ^ (a>>>34) */              \
+    "xorq	" L1 ", " L2 "\n\t"             \
+
+#define RND_RORX_1_6(a, b, c, d, e, f, g, h, i) \
+    /* L1 = a>>>39 */                           \
+    "rorxq	$39, "#a", " L1 "\n\t"          \
+    /* h += Ch(e,f,g) */                        \
+    "addq	" L4 ", "#h"\n\t"               \
+    /* L1 = Sigma0(a) */                        \
+    "xorq	" L2 ", " L1 "\n\t"             \
+
+#define RND_RORX_1_7(a, b, c, d, e, f, g, h, i) \
+    /* L4 = b */                                \
+    "movq	"#b", " L4 "\n\t"               \
+    /* d += h + w_k + Sigma1(e) + Ch(e,f,g) */  \
+    "addq	"#h", "#d"\n\t"                 \
+    /* L4 = a ^ b */                            \
+    "xorq	"#a", " L4 "\n\t"               \
+
+#define RND_RORX_1_8(a, b, c, d, e, f, g, h, i) \
+    /* L2 = (a ^ b) & (b ^ c) */                \
+    "andq	" L4 ", " L3 "\n\t"             \
+    /* h += Sigma0(a) */                        \
+    "addq	" L1 ", "#h"\n\t"               \
+    /* L3 = Maj(a,b,c) */                       \
+    "xorq	"#b", " L3 "\n\t"               \
+
+#define RND_RORX_ALL_2(a, b, c, d, e, f, g, h, i) \
+    RND_RORX_0_1(a, b, c, d, e, f, g, h, i+0)     \
+    RND_RORX_0_2(a, b, c, d, e, f, g, h, i+0)     \
+    RND_RORX_0_3(a, b, c, d, e, f, g, h, i+0)     \
+    RND_RORX_0_4(a, b, c, d, e, f, g, h, i+0)     \
+    RND_RORX_0_5(a, b, c, d, e, f, g, h, i+0)     \
+    RND_RORX_0_6(a, b, c, d, e, f, g, h, i+0)     \
+    RND_RORX_0_7(a, b, c, d, e, f, g, h, i+0)     \
+    RND_RORX_0_8(a, b, c, d, e, f, g, h, i+0)     \
+    RND_RORX_1_1(h, a, b, c, d, e, f, g, i+1)     \
+    RND_RORX_1_2(h, a, b, c, d, e, f, g, i+1)     \
+    RND_RORX_1_3(h, a, b, c, d, e, f, g, i+1)     \
+    RND_RORX_1_4(h, a, b, c, d, e, f, g, i+1)     \
+    RND_RORX_1_5(h, a, b, c, d, e, f, g, i+1)     \
+    RND_RORX_1_6(h, a, b, c, d, e, f, g, i+1)     \
+    RND_RORX_1_7(h, a, b, c, d, e, f, g, i+1)     \
+    RND_RORX_1_8(h, a, b, c, d, e, f, g, i+1)     \
+
+#define RND_RORX_ALL_4(a, b, c, d, e, f, g, h, i) \
+    RND_RORX_ALL_2(a, b, c, d, e, f, g, h, i+0)   \
+    RND_RORX_ALL_2(g, h, a, b, c, d, e, f, i+2)
+
+#define MsgSched_RORX(W_0,W_2,W_4,W_6,W_8,W_10,W_12,W_14,a,b,c,d,e,f,g,h,i) \
+            RND_RORX_0_1(a,b,c,d,e,f,g,h,i)                                 \
+    VPALIGNR(W_M15, W_2, W_0, 8)                                            \
+    VPALIGNR(W_M7, W_10, W_8, 8)                                            \
+            RND_RORX_0_2(a,b,c,d,e,f,g,h,i)                                 \
+    V_SHIFT_R(XTMP1, W_M15, 1)                                              \
+    V_SHIFT_L(XTMP2, W_M15, 63)                                             \
+            RND_RORX_0_3(a,b,c,d,e,f,g,h,i)                                 \
+    V_SHIFT_R(XTMP3, W_M15, 8)                                              \
+    V_SHIFT_L(XTMP4, W_M15, 56)                                             \
+            RND_RORX_0_4(a,b,c,d,e,f,g,h,i)                                 \
+    V_OR(XTMP1, XTMP2, XTMP1)                                               \
+    V_OR(XTMP3, XTMP4, XTMP3)                                               \
+            RND_RORX_0_5(a,b,c,d,e,f,g,h,i)                                 \
+    V_SHIFT_R(XTMP4, W_M15, 7)                                              \
+    V_XOR(XTMP1, XTMP3, XTMP1)                                              \
+            RND_RORX_0_6(a,b,c,d,e,f,g,h,i)                                 \
+    V_XOR(XTMP1, XTMP4, XTMP1)                                              \
+    V_ADD(W_0, W_0, W_M7)                                                   \
+            RND_RORX_0_7(a,b,c,d,e,f,g,h,i)                                 \
+            RND_RORX_0_8(a,b,c,d,e,f,g,h,i)                                 \
+    V_ADD(W_0, W_0, XTMP1)                                                  \
+            RND_RORX_1_1(h,a,b,c,d,e,f,g,i+1)                               \
+    V_SHIFT_R(XTMP1, W_14, 19)                                              \
+    V_SHIFT_L(XTMP2, W_14, 45)                                              \
+            RND_RORX_1_2(h,a,b,c,d,e,f,g,i+1)                               \
+    V_SHIFT_R(XTMP3, W_14, 61)                                              \
+    V_SHIFT_L(XTMP4, W_14, 3)                                               \
+            RND_RORX_1_3(h,a,b,c,d,e,f,g,i+1)                               \
+    V_OR(XTMP1, XTMP2, XTMP1)                                               \
+    V_OR(XTMP3, XTMP4, XTMP3)                                               \
+            RND_RORX_1_4(h,a,b,c,d,e,f,g,i+1)                               \
+            RND_RORX_1_5(h,a,b,c,d,e,f,g,i+1)                               \
+    V_XOR(XTMP1, XTMP3, XTMP1)                                              \
+    V_SHIFT_R(XTMP4, W_14, 6)                                               \
+            RND_RORX_1_6(h,a,b,c,d,e,f,g,i+1)                               \
+            RND_RORX_1_7(h,a,b,c,d,e,f,g,i+1)                               \
+    V_XOR(XTMP1, XTMP4, XTMP1)                                              \
+            RND_RORX_1_8(h,a,b,c,d,e,f,g,i+1)                               \
+    V_ADD(W_0, W_0, XTMP1)                                                  \
+
+#endif
+
+#define _INIT_MASK(mask) \
+    "vmovdqu %[mask], %%" #mask "\n\t"
+#define INIT_MASK(mask) \
+       _INIT_MASK(mask)
+
+#define _LOAD_W_2(i1, i2, xmm1, xmm2, mask, reg)           \
+    "vmovdqu	" #i1 "*16(%%" #reg "), %%" #xmm1 "\n\t"   \
+    "vmovdqu	" #i2 "*16(%%" #reg "), %%" #xmm2 "\n\t"   \
+    "vpshufb	%%" #mask ", %%" #xmm1 ", %%" #xmm1 "\n\t" \
+    "vpshufb	%%" #mask ", %%" #xmm2 ", %%" #xmm2 "\n\t"
+#define LOAD_W_2(i1, i2, xmm1, xmm2, mask, reg) \
+       _LOAD_W_2(i1, i2, xmm1, xmm2, mask, reg)
+
+#define LOAD_W(mask, reg)                           \
+    /* X0..3(xmm4..7), W[0..15] = buffer[0.15];  */ \
+    LOAD_W_2(0, 1, W_0 , W_2 , mask, reg)           \
+    LOAD_W_2(2, 3, W_4 , W_6 , mask, reg)           \
+    LOAD_W_2(4, 5, W_8 , W_10, mask, reg)           \
+    LOAD_W_2(6, 7, W_12, W_14, mask, reg)
+
+#define _SET_W_X_2(xmm0, xmm1, reg, i)                          \
+    "vpaddq	" #i "+ 0(%%" #reg "), %%" #xmm0 ", %%xmm8\n\t" \
+    "vpaddq	" #i "+16(%%" #reg "), %%" #xmm1 ", %%xmm9\n\t" \
+    "vmovdqu	%%xmm8, " #i "+ 0(" WX ")\n\t"                  \
+    "vmovdqu	%%xmm9, " #i "+16(" WX ")\n\t"                  \
+
+#define SET_W_X_2(xmm0, xmm1, reg, i) \
+       _SET_W_X_2(xmm0, xmm1, reg, i)
+
+#define SET_W_X(reg)                \
+    SET_W_X_2(W_0 , W_2 , reg,  0)  \
+    SET_W_X_2(W_4 , W_6 , reg, 32)  \
+    SET_W_X_2(W_8 , W_10, reg, 64)  \
+    SET_W_X_2(W_12, W_14, reg, 96)
+
+#define LOAD_DIGEST()                     \
+    "movq	  (%[sha512]), %%r8 \n\t" \
+    "movq	 8(%[sha512]), %%r9 \n\t" \
+    "movq	16(%[sha512]), %%r10\n\t" \
+    "movq	24(%[sha512]), %%r11\n\t" \
+    "movq	32(%[sha512]), %%r12\n\t" \
+    "movq	40(%[sha512]), %%r13\n\t" \
+    "movq	48(%[sha512]), %%r14\n\t" \
+    "movq	56(%[sha512]), %%r15\n\t"
+
+#define STORE_ADD_DIGEST()                \
+    "addq	 %%r8,   (%[sha512])\n\t" \
+    "addq	 %%r9,  8(%[sha512])\n\t" \
+    "addq	%%r10, 16(%[sha512])\n\t" \
+    "addq	%%r11, 24(%[sha512])\n\t" \
+    "addq	%%r12, 32(%[sha512])\n\t" \
+    "addq	%%r13, 40(%[sha512])\n\t" \
+    "addq	%%r14, 48(%[sha512])\n\t" \
+    "addq	%%r15, 56(%[sha512])\n\t"
+
+#define ADD_DIGEST()                      \
+    "addq	  (%[sha512]), %%r8 \n\t" \
+    "addq	 8(%[sha512]), %%r9 \n\t" \
+    "addq	16(%[sha512]), %%r10\n\t" \
+    "addq	24(%[sha512]), %%r11\n\t" \
+    "addq	32(%[sha512]), %%r12\n\t" \
+    "addq	40(%[sha512]), %%r13\n\t" \
+    "addq	48(%[sha512]), %%r14\n\t" \
+    "addq	56(%[sha512]), %%r15\n\t"
+
+#define STORE_DIGEST()                    \
+    "movq	 %%r8,   (%[sha512])\n\t" \
+    "movq	 %%r9,  8(%[sha512])\n\t" \
+    "movq	%%r10, 16(%[sha512])\n\t" \
+    "movq	%%r11, 24(%[sha512])\n\t" \
+    "movq	%%r12, 32(%[sha512])\n\t" \
+    "movq	%%r13, 40(%[sha512])\n\t" \
+    "movq	%%r14, 48(%[sha512])\n\t" \
+    "movq	%%r15, 56(%[sha512])\n\t"
 
 #endif /* HAVE_INTEL_AVX1 */
-
-#if defined(HAVE_INTEL_AVX2)
-#define Ry_1(i, w) h(i)+=S1(e(i))+Ch(e(i),f(i),g(i))+K[i+j] + w;
-#define Ry_2(i, w) d(i)+=h(i);
-#define Ry_3(i, w) h(i)+=S0(a(i))+Maj(a(i),b(i),c(i));
-#endif /* HAVE_INTEL_AVX2 */
-
-/* INLINE Assember for Intel AVX1 instructions */
-#if defined(HAVE_INTEL_AVX1)
-#if defined(DEBUG_XMM)
-    #define SAVE_REG(i)     __asm__ volatile("vmovdqu %%xmm"#i", %0 \n\t":"=m"(reg[i][0]):);
-    #define RECV_REG(i)     __asm__ volatile("vmovdqu %0, %%xmm"#i" \n\t"::"m"(reg[i][0]));
-
-    #define _DUMP_REG(REG, name)\
-        { word64 buf[16];word64 reg[16][2];int k;\
-          SAVE_REG(0); SAVE_REG(1); SAVE_REG(2);  SAVE_REG(3);  SAVE_REG(4);  \
-          SAVE_REG(5);   SAVE_REG(6); SAVE_REG(7);SAVE_REG(8); SAVE_REG(9); SAVE_REG(10);\
-           SAVE_REG(11); SAVE_REG(12); SAVE_REG(13); SAVE_REG(14); SAVE_REG(15); \
-          __asm__ volatile("vmovdqu %%"#REG", %0 \n\t":"=m"(buf[0]):);\
-          printf(" "#name":\t"); for(k=0; k<2; k++) printf("%016lx.", (word64)(buf[k])); printf("\n"); \
-          RECV_REG(0); RECV_REG(1); RECV_REG(2);  RECV_REG(3);  RECV_REG(4);\
-          RECV_REG(5);   RECV_REG(6); RECV_REG(7); RECV_REG(8); RECV_REG(9);\
-          RECV_REG(10); RECV_REG(11); RECV_REG(12); RECV_REG(13); RECV_REG(14); RECV_REG(15);\
-        }
-
-    #define DUMP_REG(REG) _DUMP_REG(REG, #REG)
-    #define PRINTF(fmt, ...)
-#else
-    #define DUMP_REG(REG)
-    #define PRINTF(fmt, ...)
-#endif /* DEBUG_XMM */
-
-#define _MOVE_to_REG(xymm, mem)       __asm__ volatile("vmovdqu %0, %%"#xymm" "\
-        :: "m"(mem));
-#define _MOVE_to_MEM(mem,i, xymm)     __asm__ volatile("vmovdqu %%"#xymm", %0" :\
-         "=m"(mem[i]),"=m"(mem[i+1]),"=m"(mem[i+2]),"=m"(mem[i+3]):);
-#define _MOVE(dest, src)              __asm__ volatile("vmovdqu %%"#src",  %%"\
-        #dest" "::);
-
-#define _S_TEMP(dest, src, bits, temp)  __asm__ volatile("vpsrlq  $"#bits", %%"\
-        #src", %%"#dest"\n\tvpsllq  $64-"#bits", %%"#src", %%"#temp"\n\tvpor %%"\
-        #temp",%%"#dest", %%"#dest" "::);
-#define _AVX1_R(dest, src, bits)      __asm__ volatile("vpsrlq  $"#bits", %%"\
-        #src", %%"#dest" "::);
-#define _XOR(dest, src1, src2)        __asm__ volatile("vpxor   %%"#src1", %%"\
-        #src2", %%"#dest" "::);
-#define _OR(dest, src1, src2)         __asm__ volatile("vpor    %%"#src1", %%"\
-        #src2", %%"#dest" "::);
-#define _ADD(dest, src1, src2)        __asm__ volatile("vpaddq   %%"#src1", %%"\
-        #src2", %%"#dest" "::);
-#define _ADD_MEM(dest, src1, mem)     __asm__ volatile("vpaddq   %0, %%"#src1", %%"\
-        #dest" "::"m"(mem));
-
-#define MOVE_to_REG(xymm, mem)      _MOVE_to_REG(xymm, mem)
-#define MOVE_to_MEM(mem, i, xymm)   _MOVE_to_MEM(mem, i, xymm)
-#define MOVE(dest, src)             _MOVE(dest, src)
-
-#define XOR(dest, src1, src2)      _XOR(dest, src1, src2)
-#define OR(dest, src1, src2)       _OR(dest, src1, src2)
-#define ADD(dest, src1, src2)      _ADD(dest, src1, src2)
-
-#define S_TMP(dest, src, bits, temp) _S_TEMP(dest, src, bits, temp);
-#define AVX1_S(dest, src, bits)      S_TMP(dest, src, bits, S_TEMP)
-#define AVX1_R(dest, src, bits)      _AVX1_R(dest, src, bits)
-
-#define Init_Mask(mask) \
-     __asm__ volatile("vmovdqu %0, %%xmm1\n\t"::"m"(mask):"%xmm1");
-
-#define _W_from_buff1(w, buff, xmm) \
-    /* X0..3(xmm4..7), W[0..15] = sha512->buffer[0.15];  */\
-     __asm__ volatile("vmovdqu %1, %%"#xmm"\n\t"\
-                      "vpshufb %%xmm1, %%"#xmm", %%"#xmm"\n\t"\
-                      "vmovdqu %%"#xmm", %0"\
-                      :"=m"(w): "m"(buff):"%xmm0");
-
-#define W_from_buff1(w, buff, xmm) _W_from_buff1(w, buff, xmm)
-
-#define W_from_buff(w, buff)\
-     Init_Mask(mBYTE_FLIP_MASK[0]);\
-     W_from_buff1(w[0], buff[0], W_0);\
-     W_from_buff1(w[2], buff[2], W_2);\
-     W_from_buff1(w[4], buff[4], W_4);\
-     W_from_buff1(w[6], buff[6], W_6);\
-     W_from_buff1(w[8], buff[8], W_8);\
-     W_from_buff1(w[10],buff[10],W_10);\
-     W_from_buff1(w[12],buff[12],W_12);\
-     W_from_buff1(w[14],buff[14],W_14);
-
-static word64 mBYTE_FLIP_MASK[] =  { 0x0001020304050607, 0x08090a0b0c0d0e0f };
-
-#define W_I_15  xmm14
-#define W_I_7   xmm11
-#define W_I_2   xmm13
-#define W_I     xmm12
-#define G_TEMP  xmm0
-#define S_TEMP  xmm1
-#define XMM_TEMP0  xmm2
-
-#define W_0     xmm12
-#define W_2     xmm3
-#define W_4     xmm4
-#define W_6     xmm5
-#define W_8     xmm6
-#define W_10    xmm7
-#define W_12    xmm8
-#define W_14    xmm9
-
-#define s0_1(dest, src)      AVX1_S(dest, src, 1);
-#define s0_2(dest, src)      AVX1_S(G_TEMP, src, 8); XOR(dest, G_TEMP, dest);
-#define s0_3(dest, src)      AVX1_R(G_TEMP, src, 7);  XOR(dest, G_TEMP, dest);
-
-#define s1_1(dest, src)      AVX1_S(dest, src, 19);
-#define s1_2(dest, src)      AVX1_S(G_TEMP, src, 61); XOR(dest, G_TEMP, dest);
-#define s1_3(dest, src)      AVX1_R(G_TEMP, src, 6); XOR(dest, G_TEMP, dest);
-
-#define s0_(dest, src)       s0_1(dest, src); s0_2(dest, src); s0_3(dest, src)
-#define s1_(dest, src)       s1_1(dest, src); s1_2(dest, src); s1_3(dest, src)
-
-#define Block_xx_1(i) \
-    MOVE_to_REG(W_I_15, W_X[(i-15)&15]);\
-    MOVE_to_REG(W_I_7,  W_X[(i- 7)&15]);\
-
-#define Block_xx_2(i) \
-    MOVE_to_REG(W_I_2,  W_X[(i- 2)&15]);\
-    MOVE_to_REG(W_I,    W_X[(i)]);\
-
-#define Block_xx_3(i) \
-    s0_ (XMM_TEMP0, W_I_15);\
-
-#define Block_xx_4(i) \
-    ADD(W_I, W_I, XMM_TEMP0);\
-    ADD(W_I, W_I, W_I_7);\
-
-#define Block_xx_5(i) \
-    s1_ (XMM_TEMP0, W_I_2);\
-
-#define Block_xx_6(i) \
-    ADD(W_I, W_I, XMM_TEMP0);\
-    MOVE_to_MEM(W_X,i, W_I);\
-    if (i==0)\
-        MOVE_to_MEM(W_X,16, W_I);\
-
-#define Block_xx_7(i) \
-    MOVE_to_REG(W_I_15, W_X[(i-15)&15]);\
-    MOVE_to_REG(W_I_7,  W_X[(i- 7)&15]);\
-
-#define Block_xx_8(i) \
-    MOVE_to_REG(W_I_2,  W_X[(i- 2)&15]);\
-    MOVE_to_REG(W_I,    W_X[(i)]);\
-
-#define Block_xx_9(i) \
-    s0_ (XMM_TEMP0, W_I_15);\
-
-#define Block_xx_10(i) \
-    ADD(W_I, W_I, XMM_TEMP0);\
-    ADD(W_I, W_I, W_I_7);\
-
-#define Block_xx_11(i) \
-    s1_ (XMM_TEMP0, W_I_2);\
-
-#define Block_xx_12(i) \
-    ADD(W_I, W_I, XMM_TEMP0);\
-    MOVE_to_MEM(W_X,i, W_I);\
-    if ((i)==0)\
-        MOVE_to_MEM(W_X,16, W_I);\
-
-static INLINE void Block_0_1(word64 *W_X) { Block_xx_1(0); }
-static INLINE void Block_0_2(word64 *W_X) { Block_xx_2(0); }
-static INLINE void Block_0_3(void) { Block_xx_3(0); }
-static INLINE void Block_0_4(void) { Block_xx_4(0); }
-static INLINE void Block_0_5(void) { Block_xx_5(0); }
-static INLINE void Block_0_6(word64 *W_X) { Block_xx_6(0); }
-static INLINE void Block_0_7(word64 *W_X) { Block_xx_7(2); }
-static INLINE void Block_0_8(word64 *W_X) { Block_xx_8(2); }
-static INLINE void Block_0_9(void) { Block_xx_9(2); }
-static INLINE void Block_0_10(void){ Block_xx_10(2); }
-static INLINE void Block_0_11(void){ Block_xx_11(2); }
-static INLINE void Block_0_12(word64 *W_X){ Block_xx_12(2); }
-
-static INLINE void Block_4_1(word64 *W_X) { Block_xx_1(4); }
-static INLINE void Block_4_2(word64 *W_X) { Block_xx_2(4); }
-static INLINE void Block_4_3(void) { Block_xx_3(4); }
-static INLINE void Block_4_4(void) { Block_xx_4(4); }
-static INLINE void Block_4_5(void) { Block_xx_5(4); }
-static INLINE void Block_4_6(word64 *W_X) { Block_xx_6(4); }
-static INLINE void Block_4_7(word64 *W_X) { Block_xx_7(6); }
-static INLINE void Block_4_8(word64 *W_X) { Block_xx_8(6); }
-static INLINE void Block_4_9(void) { Block_xx_9(6); }
-static INLINE void Block_4_10(void){ Block_xx_10(6); }
-static INLINE void Block_4_11(void){ Block_xx_11(6); }
-static INLINE void Block_4_12(word64 *W_X){ Block_xx_12(6); }
-
-static INLINE void Block_8_1(word64 *W_X) { Block_xx_1(8); }
-static INLINE void Block_8_2(word64 *W_X) { Block_xx_2(8); }
-static INLINE void Block_8_3(void) { Block_xx_3(8); }
-static INLINE void Block_8_4(void) { Block_xx_4(8); }
-static INLINE void Block_8_5(void) { Block_xx_5(8); }
-static INLINE void Block_8_6(word64 *W_X) { Block_xx_6(8); }
-static INLINE void Block_8_7(word64 *W_X) { Block_xx_7(10); }
-static INLINE void Block_8_8(word64 *W_X) { Block_xx_8(10); }
-static INLINE void Block_8_9(void) { Block_xx_9(10); }
-static INLINE void Block_8_10(void){ Block_xx_10(10); }
-static INLINE void Block_8_11(void){ Block_xx_11(10); }
-static INLINE void Block_8_12(word64 *W_X){ Block_xx_12(10); }
-
-static INLINE void Block_12_1(word64 *W_X) { Block_xx_1(12); }
-static INLINE void Block_12_2(word64 *W_X) { Block_xx_2(12); }
-static INLINE void Block_12_3(void) { Block_xx_3(12); }
-static INLINE void Block_12_4(void) { Block_xx_4(12); }
-static INLINE void Block_12_5(void) { Block_xx_5(12); }
-static INLINE void Block_12_6(word64 *W_X) { Block_xx_6(12); }
-static INLINE void Block_12_7(word64 *W_X) { Block_xx_7(14); }
-static INLINE void Block_12_8(word64 *W_X) { Block_xx_8(14); }
-static INLINE void Block_12_9(void) { Block_xx_9(14); }
-static INLINE void Block_12_10(void){ Block_xx_10(14); }
-static INLINE void Block_12_11(void){ Block_xx_11(14); }
-static INLINE void Block_12_12(word64 *W_X){ Block_xx_12(14); }
-
-#endif /* HAVE_INTEL_AVX1 */
-
-#if defined(HAVE_INTEL_AVX2)
-static const unsigned long mBYTE_FLIP_MASK_Y[] =
-   { 0x0001020304050607, 0x08090a0b0c0d0e0f, 0x0001020304050607, 0x08090a0b0c0d0e0f };
-
-#define W_from_buff_Y(buff)\
-    { /* X0..3(ymm9..12), W_X[0..15] = sha512->buffer[0.15];  */\
-     __asm__ volatile("vmovdqu %0, %%ymm8\n\t"::"m"(mBYTE_FLIP_MASK_Y[0]));\
-     __asm__ volatile("vmovdqu %0, %%ymm12\n\t"\
-                      "vmovdqu %1, %%ymm4\n\t"\
-                      "vpshufb %%ymm8, %%ymm12, %%ymm12\n\t"\
-                      "vpshufb %%ymm8, %%ymm4, %%ymm4\n\t"\
-                      :: "m"(buff[0]),  "m"(buff[4]));\
-     __asm__ volatile("vmovdqu %0, %%ymm5\n\t"\
-                      "vmovdqu %1, %%ymm6\n\t"\
-                      "vpshufb %%ymm8, %%ymm5, %%ymm5\n\t"\
-                      "vpshufb %%ymm8, %%ymm6, %%ymm6\n\t"\
-                      :: "m"(buff[8]),  "m"(buff[12]));\
-    }
-
-#if defined(DEBUG_YMM)
-    #define SAVE_REG_Y(i) __asm__ volatile("vmovdqu %%ymm"#i", %0 \n\t":"=m"(reg[i-4][0]):);
-    #define RECV_REG_Y(i) __asm__ volatile("vmovdqu %0, %%ymm"#i" \n\t"::"m"(reg[i-4][0]));
-
-    #define _DUMP_REG_Y(REG, name)\
-        { word64 buf[16];word64 reg[16][2];int k;\
-          SAVE_REG_Y(4);  SAVE_REG_Y(5);   SAVE_REG_Y(6); SAVE_REG_Y(7); \
-          SAVE_REG_Y(8); SAVE_REG_Y(9); SAVE_REG_Y(10); SAVE_REG_Y(11); SAVE_REG_Y(12);\
-          SAVE_REG_Y(13); SAVE_REG_Y(14); SAVE_REG_Y(15); \
-          __asm__ volatile("vmovdqu %%"#REG", %0 \n\t":"=m"(buf[0]):);\
-          printf(" "#name":\t"); for(k=0; k<4; k++) printf("%016lx.", (word64)buf[k]); printf("\n"); \
-          RECV_REG_Y(4);  RECV_REG_Y(5);   RECV_REG_Y(6); RECV_REG_Y(7); \
-          RECV_REG_Y(8); RECV_REG_Y(9); RECV_REG_Y(10); RECV_REG_Y(11); RECV_REG_Y(12); \
-          RECV_REG_Y(13); RECV_REG_Y(14); RECV_REG_Y(15);\
-        }
-
-    #define DUMP_REG_Y(REG) _DUMP_REG_Y(REG, #REG)
-    #define DUMP_REG2_Y(REG) _DUMP_REG_Y(REG, #REG)
-    #define PRINTF_Y(fmt, ...)
-#else
-    #define DUMP_REG_Y(REG)
-    #define DUMP_REG2_Y(REG)
-    #define PRINTF_Y(fmt, ...)
-#endif /* DEBUG_YMM */
-
-#define _MOVE_to_REGy(ymm, mem)         __asm__ volatile("vmovdqu %0, %%"#ymm" "\
-                                        :: "m"(mem));
-#define _MOVE_to_MEMy(mem,i, ymm)       __asm__ volatile("vmovdqu %%"#ymm", %0" \
-        : "=m"(mem[i]),"=m"(mem[i+1]),"=m"(mem[i+2]),"=m"(mem[i+3]):);
-#define _MOVE_128y(ymm0, ymm1, ymm2, map)  __asm__ volatile("vperm2i128  $"\
-        #map", %%"#ymm2", %%"#ymm1", %%"#ymm0" "::);
-#define _S_TEMPy(dest, src, bits, temp) \
-         __asm__ volatile("vpsrlq  $"#bits", %%"#src", %%"#dest"\n\tvpsllq  $64-"#bits\
-        ", %%"#src", %%"#temp"\n\tvpor %%"#temp",%%"#dest", %%"#dest" "::);
-#define _AVX2_R(dest, src, bits)        __asm__ volatile("vpsrlq  $"#bits", %%"\
-         #src", %%"#dest" "::);
-#define _XORy(dest, src1, src2)         __asm__ volatile("vpxor   %%"#src1", %%"\
-         #src2", %%"#dest" "::);
-#define _ADDy(dest, src1, src2)         __asm__ volatile("vpaddq   %%"#src1", %%"\
-         #src2", %%"#dest" "::);
-#define _BLENDy(map, dest, src1, src2)  __asm__ volatile("vpblendd    $"#map", %%"\
-         #src1",   %%"#src2", %%"#dest" "::);
-#define _BLENDQy(map, dest, src1, src2) __asm__ volatile("vblendpd   $"#map", %%"\
-         #src1",   %%"#src2", %%"#dest" "::);
-#define _PERMQy(map, dest, src)         __asm__ volatile("vpermq  $"#map", %%"\
-         #src", %%"#dest" "::);
-
-#define MOVE_to_REGy(ymm, mem)      _MOVE_to_REGy(ymm, mem)
-#define MOVE_to_MEMy(mem, i, ymm)   _MOVE_to_MEMy(mem, i, ymm)
-
-#define MOVE_128y(ymm0, ymm1, ymm2, map) _MOVE_128y(ymm0, ymm1, ymm2, map)
-#define XORy(dest, src1, src2)      _XORy(dest, src1, src2)
-#define ADDy(dest, src1, src2)      _ADDy(dest, src1, src2)
-#define BLENDy(map, dest, src1, src2) _BLENDy(map, dest, src1, src2)
-#define BLENDQy(map, dest, src1, src2) _BLENDQy(map, dest, src1, src2)
-#define PERMQy(map, dest, src)      _PERMQy(map, dest, src)
-
-
-#define S_TMPy(dest, src, bits, temp) _S_TEMPy(dest, src, bits, temp);
-#define AVX2_S(dest, src, bits)      S_TMPy(dest, src, bits, S_TEMPy)
-#define AVX2_R(dest, src, bits)      _AVX2_R(dest, src, bits)
-
-
-#define    FEEDBACK1_to_W_I_2(w_i_2, w_i)    MOVE_128y(YMM_TEMP0, w_i, w_i, 0x08);\
-                                       BLENDy(0xf0, w_i_2, YMM_TEMP0, w_i_2);
-
-#define    MOVE_W_to_W_I_15(w_i_15, w_0, w_4)  BLENDQy(0x1, w_i_15, w_4, w_0);\
-                                       PERMQy(0x39, w_i_15, w_i_15);
-#define    MOVE_W_to_W_I_7(w_i_7,  w_8, w_12)  BLENDQy(0x1, w_i_7, w_12, w_8);\
-                                       PERMQy(0x39, w_i_7, w_i_7);
-#define    MOVE_W_to_W_I_2(w_i_2,  w_12)       BLENDQy(0xc, w_i_2, w_12, w_i_2);\
-                                       PERMQy(0x0e, w_i_2, w_i_2);
-
-
-#define W_I_16y  ymm8
-#define W_I_15y  ymm9
-#define W_I_7y  ymm10
-#define W_I_2y  ymm11
-#define W_Iy    ymm12
-#define G_TEMPy     ymm13
-#define S_TEMPy     ymm14
-#define YMM_TEMP0  ymm15
-#define YMM_TEMP0x xmm15
-#define W_I_TEMPy   ymm7
-#define W_K_TEMPy   ymm15
-#define W_K_TEMPx  xmm15
-#define W_0y     ymm12
-#define W_4y     ymm4
-#define W_8y     ymm5
-#define W_12y    ymm6
-
-
-#define MOVE_15_to_16(w_i_16, w_i_15, w_i_7)\
-    __asm__ volatile("vperm2i128  $0x01, %%"#w_i_15", %%"#w_i_15", %%"#w_i_15" "::);\
-    __asm__ volatile("vpblendd    $0x08, %%"#w_i_15", %%"#w_i_7", %%"#w_i_16" "::);\
-    __asm__ volatile("vperm2i128 $0x01,  %%"#w_i_7",  %%"#w_i_7", %%"#w_i_15" "::);\
-    __asm__ volatile("vpblendd    $0x80, %%"#w_i_15", %%"#w_i_16", %%"#w_i_16" "::);\
-    __asm__ volatile("vpshufd    $0x93,  %%"#w_i_16", %%"#w_i_16" "::);\
-
-#define MOVE_7_to_15(w_i_15, w_i_7)\
-    __asm__ volatile("vmovdqu                 %%"#w_i_7",  %%"#w_i_15" "::);\
-
-#define MOVE_I_to_7(w_i_7, w_i)\
-    __asm__ volatile("vperm2i128 $0x01,       %%"#w_i",   %%"#w_i",   %%"#w_i_7" "::);\
-    __asm__ volatile("vpblendd    $0x01,       %%"#w_i_7",   %%"#w_i", %%"#w_i_7" "::);\
-    __asm__ volatile("vpshufd    $0x39, %%"#w_i_7", %%"#w_i_7" "::);\
-
-#define MOVE_I_to_2(w_i_2, w_i)\
-    __asm__ volatile("vperm2i128 $0x01,       %%"#w_i", %%"#w_i", %%"#w_i_2" "::);\
-    __asm__ volatile("vpshufd    $0x0e, %%"#w_i_2", %%"#w_i_2" "::);\
-
-#endif /* HAVE_INTEL_AVX2 */
 
 
 /***  Transform Body ***/
 #if defined(HAVE_INTEL_AVX1)
-static int Transform_AVX1(wc_Sha512* sha512)
+static int Transform_Sha512_AVX1(wc_Sha512* sha512)
 {
-    const word64* K = K512;
-    word64 W_X[16+4] = {0};
-    word32 j;
-    word64 T[8];
-
-    /* Copy digest to working vars */
-    XMEMCPY(T, sha512->digest, sizeof(T));
-
-    W_from_buff(W_X, sha512->buffer);
-    for (j = 0; j < 80; j += 16) {
-        Rx_1( 0); Block_0_1(W_X); Rx_2( 0); Block_0_2(W_X); Rx_3( 0); Block_0_3();
-        Rx_1( 1); Block_0_4(); Rx_2( 1); Block_0_5(); Rx_3( 1); Block_0_6(W_X);
-        Rx_1( 2); Block_0_7(W_X); Rx_2( 2); Block_0_8(W_X); Rx_3( 2); Block_0_9();
-        Rx_1( 3); Block_0_10();Rx_2( 3); Block_0_11();Rx_3( 3); Block_0_12(W_X);
-
-        Rx_1( 4); Block_4_1(W_X); Rx_2( 4); Block_4_2(W_X); Rx_3( 4); Block_4_3();
-        Rx_1( 5); Block_4_4(); Rx_2( 5); Block_4_5(); Rx_3( 5); Block_4_6(W_X);
-        Rx_1( 6); Block_4_7(W_X); Rx_2( 6); Block_4_8(W_X); Rx_3( 6); Block_4_9();
-        Rx_1( 7); Block_4_10();Rx_2( 7); Block_4_11();Rx_3( 7); Block_4_12(W_X);
-
-        Rx_1( 8); Block_8_1(W_X); Rx_2( 8); Block_8_2(W_X); Rx_3( 8); Block_8_3();
-        Rx_1( 9); Block_8_4(); Rx_2( 9); Block_8_5(); Rx_3( 9); Block_8_6(W_X);
-        Rx_1(10); Block_8_7(W_X); Rx_2(10); Block_8_8(W_X); Rx_3(10); Block_8_9();
-        Rx_1(11); Block_8_10();Rx_2(11); Block_8_11();Rx_3(11); Block_8_12(W_X);
-
-        Rx_1(12); Block_12_1(W_X); Rx_2(12); Block_12_2(W_X); Rx_3(12); Block_12_3();
-        Rx_1(13); Block_12_4(); Rx_2(13); Block_12_5(); Rx_3(13); Block_12_6(W_X);
-        Rx_1(14); Block_12_7(W_X); Rx_2(14); Block_12_8(W_X); Rx_3(14); Block_12_9();
-        Rx_1(15); Block_12_10();Rx_2(15); Block_12_11();Rx_3(15); Block_12_12(W_X);
-    }
-
-    /* Add the working vars back into digest */
-    sha512->digest[0] += a(0);
-    sha512->digest[1] += b(0);
-    sha512->digest[2] += c(0);
-    sha512->digest[3] += d(0);
-    sha512->digest[4] += e(0);
-    sha512->digest[5] += f(0);
-    sha512->digest[6] += g(0);
-    sha512->digest[7] += h(0);
-
-    /* Wipe variables */
-#if !defined(HAVE_INTEL_AVX1) && !defined(HAVE_INTEL_AVX2)
-    XMEMSET(W_X, 0, sizeof(word64) * 16);
-#endif
-    XMEMSET(T, 0, sizeof(T));
+    __asm__ __volatile__ (
+
+        /* 16 Ws plus loop counter. */
+        "subq	$136, %%rsp\n\t"
+        "leaq	64(%[sha512]), %%rax\n\t"
+
+    INIT_MASK(MASK)
+    LOAD_DIGEST()
+
+    LOAD_W(MASK, rax)
+
+        "movl	$4, 16*8(" WX ")\n\t"
+        "leaq	%[K512], %%rsi\n\t"
+        /* b */
+        "movq	%%r9, " L4 "\n\t"
+        /* e */
+        "movq	%%r12, " L1 "\n\t"
+        /* b ^ c */
+        "xorq	%%r10, " L4 "\n\t"
+
+        "# Start of 16 rounds\n"
+        "1:\n\t"
+
+    SET_W_X(rsi)
+
+        "addq	$128, %%rsi\n\t"
+
+    MsgSched2(W_0,W_2,W_4,W_6,W_8,W_10,W_12,W_14,RA,RB,RC,RD,RE,RF,RG,RH, 0)
+    MsgSched2(W_2,W_4,W_6,W_8,W_10,W_12,W_14,W_0,RG,RH,RA,RB,RC,RD,RE,RF, 2)
+    MsgSched2(W_4,W_6,W_8,W_10,W_12,W_14,W_0,W_2,RE,RF,RG,RH,RA,RB,RC,RD, 4)
+    MsgSched2(W_6,W_8,W_10,W_12,W_14,W_0,W_2,W_4,RC,RD,RE,RF,RG,RH,RA,RB, 6)
+    MsgSched2(W_8,W_10,W_12,W_14,W_0,W_2,W_4,W_6,RA,RB,RC,RD,RE,RF,RG,RH, 8)
+    MsgSched2(W_10,W_12,W_14,W_0,W_2,W_4,W_6,W_8,RG,RH,RA,RB,RC,RD,RE,RF,10)
+    MsgSched2(W_12,W_14,W_0,W_2,W_4,W_6,W_8,W_10,RE,RF,RG,RH,RA,RB,RC,RD,12)
+    MsgSched2(W_14,W_0,W_2,W_4,W_6,W_8,W_10,W_12,RC,RD,RE,RF,RG,RH,RA,RB,14)
+
+        "subl	$1, 16*8(" WX ")\n\t"
+        "jne	1b\n\t"
+
+    SET_W_X(rsi)
+
+    RND_ALL_2(RA,RB,RC,RD,RE,RF,RG,RH, 0)
+    RND_ALL_2(RG,RH,RA,RB,RC,RD,RE,RF, 2)
+    RND_ALL_2(RE,RF,RG,RH,RA,RB,RC,RD, 4)
+    RND_ALL_2(RC,RD,RE,RF,RG,RH,RA,RB, 6)
+
+    RND_ALL_2(RA,RB,RC,RD,RE,RF,RG,RH, 8)
+    RND_ALL_2(RG,RH,RA,RB,RC,RD,RE,RF,10)
+    RND_ALL_2(RE,RF,RG,RH,RA,RB,RC,RD,12)
+    RND_ALL_2(RC,RD,RE,RF,RG,RH,RA,RB,14)
+
+    STORE_ADD_DIGEST()
+
+        "addq	$136, %%rsp\n\t"
+
+        :
+        : [mask]   "m" (mBYTE_FLIP_MASK),
+          [sha512] "r" (sha512),
+          [K512]   "m" (K512)
+        : WORK_REGS, STATE_REGS, XMM_REGS, "memory", "rsi"
+    );
+
+    return 0;
+    }
+
+static int Transform_Sha512_AVX1_Len(wc_Sha512* sha512, word32 len)
+{
+    __asm__ __volatile__ (
+
+        "movq	224(%[sha512]), %%rsi\n\t"
+        "leaq	%[K512], %%rdx\n\t"
+
+    INIT_MASK(MASK)
+    LOAD_DIGEST()
+
+        "# Start of processing a block\n"
+        "2:\n\t"
+
+        /* 16 Ws plus loop counter and K512. len goes into -4(%rsp).
+         * Debug needs more stack space. */
+        "subq	$256, %%rsp\n\t"
+
+    LOAD_W(MASK, rsi)
+
+        "movl	$4, 16*8(" WX ")\n\t"
+        /* b */
+        "movq	%%r9, " L4 "\n\t"
+        /* e */
+        "movq	%%r12, " L1 "\n\t"
+        /* b ^ c */
+        "xorq	%%r10, " L4 "\n\t"
+
+    SET_W_X(rdx)
+
+        "# Start of 16 rounds\n"
+        "1:\n\t"
+
+        "addq	$128, %%rdx\n\t"
+        "movq	%%rdx, 17*8(%%rsp)\n\t"
+
+    MsgSched2(W_0,W_2,W_4,W_6,W_8,W_10,W_12,W_14,RA,RB,RC,RD,RE,RF,RG,RH, 0)
+    MsgSched2(W_2,W_4,W_6,W_8,W_10,W_12,W_14,W_0,RG,RH,RA,RB,RC,RD,RE,RF, 2)
+    MsgSched2(W_4,W_6,W_8,W_10,W_12,W_14,W_0,W_2,RE,RF,RG,RH,RA,RB,RC,RD, 4)
+    MsgSched2(W_6,W_8,W_10,W_12,W_14,W_0,W_2,W_4,RC,RD,RE,RF,RG,RH,RA,RB, 6)
+    MsgSched2(W_8,W_10,W_12,W_14,W_0,W_2,W_4,W_6,RA,RB,RC,RD,RE,RF,RG,RH, 8)
+    MsgSched2(W_10,W_12,W_14,W_0,W_2,W_4,W_6,W_8,RG,RH,RA,RB,RC,RD,RE,RF,10)
+    MsgSched2(W_12,W_14,W_0,W_2,W_4,W_6,W_8,W_10,RE,RF,RG,RH,RA,RB,RC,RD,12)
+    MsgSched2(W_14,W_0,W_2,W_4,W_6,W_8,W_10,W_12,RC,RD,RE,RF,RG,RH,RA,RB,14)
+
+        "movq	17*8(%%rsp), %%rdx\n\t"
+
+    SET_W_X(rdx)
+
+        "subl	$1, 16*8(" WX ")\n\t"
+        "jne	1b\n\t"
+
+    RND_ALL_2(RA,RB,RC,RD,RE,RF,RG,RH, 0)
+    RND_ALL_2(RG,RH,RA,RB,RC,RD,RE,RF, 2)
+    RND_ALL_2(RE,RF,RG,RH,RA,RB,RC,RD, 4)
+    RND_ALL_2(RC,RD,RE,RF,RG,RH,RA,RB, 6)
+
+    RND_ALL_2(RA,RB,RC,RD,RE,RF,RG,RH, 8)
+    RND_ALL_2(RG,RH,RA,RB,RC,RD,RE,RF,10)
+    RND_ALL_2(RE,RF,RG,RH,RA,RB,RC,RD,12)
+    RND_ALL_2(RC,RD,RE,RF,RG,RH,RA,RB,14)
+
+    ADD_DIGEST()
+
+        "addq	$256, %%rsp\n\t"
+        "leaq	%[K512], %%rdx\n\t"
+        "addq	$128, %%rsi\n\t"
+        "subl	$128, %[len]\n\t"
+
+    STORE_DIGEST()
+
+        "jnz	2b\n\t"
+
+        :
+        : [mask]   "m" (mBYTE_FLIP_MASK),
+          [len]    "m" (len),
+          [sha512] "r" (sha512),
+          [K512]   "m" (K512)
+        : WORK_REGS, STATE_REGS, XMM_REGS, "memory", "rsi"
+    );
 
     return 0;
@@ -1090,254 +1562,1050 @@
 #endif /* HAVE_INTEL_AVX1 */
 
-#if defined(HAVE_INTEL_AVX2) && defined(HAVE_INTEL_AVX1) && defined(HAVE_INTEL_RORX)
-static int Transform_AVX1_RORX(wc_Sha512* sha512)
+#if defined(HAVE_INTEL_AVX2) && defined(HAVE_INTEL_RORX)
+static int Transform_Sha512_AVX1_RORX(wc_Sha512* sha512)
 {
-    const word64* K = K512;
-    word64 W_X[16+4] = {0};
-    word32 j;
-    word64 T[8];
-
-    /* Copy digest to working vars */
-    XMEMCPY(T, sha512->digest, sizeof(T));
-
-    W_from_buff(W_X, sha512->buffer);
-    for (j = 0; j < 80; j += 16) {
-        Rx_RORX_1( 0); Block_0_1(W_X); Rx_RORX_2( 0); Block_0_2(W_X);
-                                    Rx_RORX_3( 0); Block_0_3();
-        Rx_RORX_1( 1); Block_0_4(); Rx_RORX_2( 1); Block_0_5();
-                                    Rx_RORX_3( 1); Block_0_6(W_X);
-        Rx_RORX_1( 2); Block_0_7(W_X); Rx_RORX_2( 2); Block_0_8(W_X);
-                                    Rx_RORX_3( 2); Block_0_9();
-        Rx_RORX_1( 3); Block_0_10();Rx_RORX_2( 3); Block_0_11();
-                                    Rx_RORX_3( 3); Block_0_12(W_X);
-
-        Rx_RORX_1( 4); Block_4_1(W_X); Rx_RORX_2( 4); Block_4_2(W_X);
-                                    Rx_RORX_3( 4); Block_4_3();
-        Rx_RORX_1( 5); Block_4_4(); Rx_RORX_2( 5); Block_4_5();
-                                    Rx_RORX_3( 5); Block_4_6(W_X);
-        Rx_RORX_1( 6); Block_4_7(W_X); Rx_RORX_2( 6); Block_4_8(W_X);
-                                    Rx_RORX_3( 6); Block_4_9();
-        Rx_RORX_1( 7); Block_4_10();Rx_RORX_2( 7); Block_4_11();
-                                    Rx_RORX_3( 7); Block_4_12(W_X);
-
-        Rx_RORX_1( 8); Block_8_1(W_X); Rx_RORX_2( 8); Block_8_2(W_X);
-                                    Rx_RORX_3( 8); Block_8_3();
-        Rx_RORX_1( 9); Block_8_4(); Rx_RORX_2( 9); Block_8_5();
-                                    Rx_RORX_3( 9); Block_8_6(W_X);
-        Rx_RORX_1(10); Block_8_7(W_X); Rx_RORX_2(10); Block_8_8(W_X);
-                                    Rx_RORX_3(10); Block_8_9();
-        Rx_RORX_1(11); Block_8_10();Rx_RORX_2(11); Block_8_11();
-                                    Rx_RORX_3(11); Block_8_12(W_X);
-
-        Rx_RORX_1(12); Block_12_1(W_X); Rx_RORX_2(12); Block_12_2(W_X);
-                                     Rx_RORX_3(12); Block_12_3();
-        Rx_RORX_1(13); Block_12_4(); Rx_RORX_2(13); Block_12_5();
-                                     Rx_RORX_3(13); Block_12_6(W_X);
-        Rx_RORX_1(14); Block_12_7(W_X); Rx_RORX_2(14); Block_12_8(W_X);
-                                     Rx_RORX_3(14); Block_12_9();
-        Rx_RORX_1(15); Block_12_10();Rx_RORX_2(15); Block_12_11();
-                                     Rx_RORX_3(15); Block_12_12(W_X);
-    }
-
-    /* Add the working vars back into digest */
-    sha512->digest[0] += a(0);
-    sha512->digest[1] += b(0);
-    sha512->digest[2] += c(0);
-    sha512->digest[3] += d(0);
-    sha512->digest[4] += e(0);
-    sha512->digest[5] += f(0);
-    sha512->digest[6] += g(0);
-    sha512->digest[7] += h(0);
-
-    /* Wipe variables */
-#if !defined(HAVE_INTEL_AVX1)&&!defined(HAVE_INTEL_AVX2)
-    XMEMSET(W_X, 0, sizeof(word64) * 16);
-#endif
-    XMEMSET(T, 0, sizeof(T));
+    __asm__ __volatile__ (
+
+        /* 16 Ws plus loop counter and K512. */
+        "subq	$144, %%rsp\n\t"
+        "leaq	64(%[sha512]), %%rax\n\t"
+
+    INIT_MASK(MASK)
+    LOAD_DIGEST()
+
+    LOAD_W(MASK, rax)
+
+        "movl	$4, 16*8(" WX ")\n\t"
+        "leaq	%[K512], %%rsi\n\t"
+        /* L4 = b */
+        "movq	%%r9, " L4 "\n\t"
+        /* L3 = 0 (add to prev h) */
+        "xorq	" L3 ", " L3 "\n\t"
+        /* L4 = b ^ c */
+        "xorq	%%r10, " L4 "\n\t"
+
+    SET_W_X(rsi)
+
+        "# Start of 16 rounds\n"
+        "1:\n\t"
+
+        "addq	$128, %%rsi\n\t"
+
+    MsgSched_RORX(W_0,W_2,W_4,W_6,W_8,W_10,W_12,W_14,RA,RB,RC,RD,RE,RF,RG,RH, 0)
+    MsgSched_RORX(W_2,W_4,W_6,W_8,W_10,W_12,W_14,W_0,RG,RH,RA,RB,RC,RD,RE,RF, 2)
+    MsgSched_RORX(W_4,W_6,W_8,W_10,W_12,W_14,W_0,W_2,RE,RF,RG,RH,RA,RB,RC,RD, 4)
+    MsgSched_RORX(W_6,W_8,W_10,W_12,W_14,W_0,W_2,W_4,RC,RD,RE,RF,RG,RH,RA,RB, 6)
+    MsgSched_RORX(W_8,W_10,W_12,W_14,W_0,W_2,W_4,W_6,RA,RB,RC,RD,RE,RF,RG,RH, 8)
+    MsgSched_RORX(W_10,W_12,W_14,W_0,W_2,W_4,W_6,W_8,RG,RH,RA,RB,RC,RD,RE,RF,10)
+    MsgSched_RORX(W_12,W_14,W_0,W_2,W_4,W_6,W_8,W_10,RE,RF,RG,RH,RA,RB,RC,RD,12)
+    MsgSched_RORX(W_14,W_0,W_2,W_4,W_6,W_8,W_10,W_12,RC,RD,RE,RF,RG,RH,RA,RB,14)
+
+    SET_W_X(rsi)
+
+        "subl	$1, 16*8(" WX ")\n\t"
+        "jne	1b\n\t"
+
+    RND_RORX_ALL_2(RA,RB,RC,RD,RE,RF,RG,RH, 0)
+    RND_RORX_ALL_2(RG,RH,RA,RB,RC,RD,RE,RF, 2)
+    RND_RORX_ALL_2(RE,RF,RG,RH,RA,RB,RC,RD, 4)
+    RND_RORX_ALL_2(RC,RD,RE,RF,RG,RH,RA,RB, 6)
+
+    RND_RORX_ALL_2(RA,RB,RC,RD,RE,RF,RG,RH, 8)
+    RND_RORX_ALL_2(RG,RH,RA,RB,RC,RD,RE,RF,10)
+    RND_RORX_ALL_2(RE,RF,RG,RH,RA,RB,RC,RD,12)
+    RND_RORX_ALL_2(RC,RD,RE,RF,RG,RH,RA,RB,14)
+
+        /* Prev RND: h += Maj(a,b,c) */
+        "addq	" L3 ", %%r8\n\t"
+        "addq	$144, %%rsp\n\t"
+
+    STORE_ADD_DIGEST()
+
+        :
+        : [mask]   "m" (mBYTE_FLIP_MASK),
+          [sha512] "r" (sha512),
+          [K512]   "m" (K512)
+        : WORK_REGS, STATE_REGS, XMM_REGS, "memory", "rsi"
+    );
+
+    return 0;
+    }
+
+static int Transform_Sha512_AVX1_RORX_Len(wc_Sha512* sha512, word32 len)
+{
+    __asm__ __volatile__ (
+
+        "movq	224(%[sha512]), %%rsi\n\t"
+        "leaq	%[K512], %%rcx\n\t"
+
+    INIT_MASK(MASK)
+    LOAD_DIGEST()
+
+        "# Start of processing a block\n"
+        "2:\n\t"
+
+        /* 16 Ws plus loop counter and K512. len goes into -4(%rsp).
+         * Debug needs more stack space. */
+        "subq	$256, %%rsp\n\t"
+
+    LOAD_W(MASK, rsi)
+
+        "movl	$4, 16*8(" WX ")\n\t"
+        /* L4 = b */
+        "movq	%%r9, " L4 "\n\t"
+        /* L3 = 0 (add to prev h) */
+        "xorq	" L3 ", " L3 "\n\t"
+        /* L4 = b ^ c */
+        "xorq	%%r10, " L4 "\n\t"
+
+    SET_W_X(rcx)
+
+        "# Start of 16 rounds\n"
+        "1:\n\t"
+
+        "addq	$128, %%rcx\n\t"
+        "movq	%%rcx, 17*8(%%rsp)\n\t"
+
+    MsgSched_RORX(W_0,W_2,W_4,W_6,W_8,W_10,W_12,W_14,RA,RB,RC,RD,RE,RF,RG,RH, 0)
+    MsgSched_RORX(W_2,W_4,W_6,W_8,W_10,W_12,W_14,W_0,RG,RH,RA,RB,RC,RD,RE,RF, 2)
+    MsgSched_RORX(W_4,W_6,W_8,W_10,W_12,W_14,W_0,W_2,RE,RF,RG,RH,RA,RB,RC,RD, 4)
+    MsgSched_RORX(W_6,W_8,W_10,W_12,W_14,W_0,W_2,W_4,RC,RD,RE,RF,RG,RH,RA,RB, 6)
+    MsgSched_RORX(W_8,W_10,W_12,W_14,W_0,W_2,W_4,W_6,RA,RB,RC,RD,RE,RF,RG,RH, 8)
+    MsgSched_RORX(W_10,W_12,W_14,W_0,W_2,W_4,W_6,W_8,RG,RH,RA,RB,RC,RD,RE,RF,10)
+    MsgSched_RORX(W_12,W_14,W_0,W_2,W_4,W_6,W_8,W_10,RE,RF,RG,RH,RA,RB,RC,RD,12)
+    MsgSched_RORX(W_14,W_0,W_2,W_4,W_6,W_8,W_10,W_12,RC,RD,RE,RF,RG,RH,RA,RB,14)
+
+        "movq	17*8(%%rsp), %%rcx\n\t"
+
+    SET_W_X(rcx)
+
+        "subl	$1, 16*8(" WX ")\n\t"
+        "jne	1b\n\t"
+
+    SET_W_X(rcx)
+
+    RND_RORX_ALL_2(RA,RB,RC,RD,RE,RF,RG,RH, 0)
+    RND_RORX_ALL_2(RG,RH,RA,RB,RC,RD,RE,RF, 2)
+    RND_RORX_ALL_2(RE,RF,RG,RH,RA,RB,RC,RD, 4)
+    RND_RORX_ALL_2(RC,RD,RE,RF,RG,RH,RA,RB, 6)
+
+    RND_RORX_ALL_2(RA,RB,RC,RD,RE,RF,RG,RH, 8)
+    RND_RORX_ALL_2(RG,RH,RA,RB,RC,RD,RE,RF,10)
+    RND_RORX_ALL_2(RE,RF,RG,RH,RA,RB,RC,RD,12)
+    RND_RORX_ALL_2(RC,RD,RE,RF,RG,RH,RA,RB,14)
+
+        /* Prev RND: h += Maj(a,b,c) */
+        "addq	" L3 ", %%r8\n\t"
+        "addq	$256, %%rsp\n\t"
+
+    ADD_DIGEST()
+
+        "leaq	%[K512], %%rcx\n\t"
+        "addq	$128, %%rsi\n\t"
+        "subl	$128, %[len]\n\t"
+
+    STORE_DIGEST()
+
+        "jnz	2b\n\t"
+
+        :
+        : [mask]   "m" (mBYTE_FLIP_MASK),
+          [len]    "m" (len),
+          [sha512] "r" (sha512),
+          [K512]   "m" (K512)
+        : WORK_REGS, STATE_REGS, XMM_REGS, "memory", "rsi"
+    );
 
     return 0;
 }
-#endif /* HAVE_INTEL_AVX2 && HAVE_INTEL_AVX1 && HAVE_INTEL_RORX */
+#endif /* HAVE_INTEL_AVX2 && HAVE_INTEL_RORX */
 
 #if defined(HAVE_INTEL_AVX2)
-
-#define s0_1y(dest, src)      AVX2_S(dest, src, 1);
-#define s0_2y(dest, src)      AVX2_S(G_TEMPy, src, 8); XORy(dest, G_TEMPy, dest);
-#define s0_3y(dest, src)      AVX2_R(G_TEMPy, src, 7);  XORy(dest, G_TEMPy, dest);
-
-#define s1_1y(dest, src)      AVX2_S(dest, src, 19);
-#define s1_2y(dest, src)      AVX2_S(G_TEMPy, src, 61); XORy(dest, G_TEMPy, dest);
-#define s1_3y(dest, src)      AVX2_R(G_TEMPy, src, 6); XORy(dest, G_TEMPy, dest);
-
-#define s0_y(dest, src)       s0_1y(dest, src); s0_2y(dest, src); s0_3y(dest, src)
-#define s1_y(dest, src)       s1_1y(dest, src); s1_2y(dest, src); s1_3y(dest, src)
-
-
-#define Block_Y_xx_1(i, w_0, w_4, w_8, w_12)\
-    MOVE_W_to_W_I_15(W_I_15y, w_0, w_4);\
-    MOVE_W_to_W_I_7 (W_I_7y,  w_8, w_12);\
-    MOVE_W_to_W_I_2 (W_I_2y,  w_12);\
-
-#define Block_Y_xx_2(i, w_0, w_4, w_8, w_12)\
-    s0_1y (YMM_TEMP0, W_I_15y);\
-
-#define Block_Y_xx_3(i, w_0, w_4, w_8, w_12)\
-    s0_2y (YMM_TEMP0, W_I_15y);\
-
-#define Block_Y_xx_4(i, w_0, w_4, w_8, w_12)\
-    s0_3y (YMM_TEMP0, W_I_15y);\
-
-#define Block_Y_xx_5(i, w_0, w_4, w_8, w_12)\
-    ADDy(W_I_TEMPy, w_0, YMM_TEMP0);\
-
-#define Block_Y_xx_6(i, w_0, w_4, w_8, w_12)\
-    ADDy(W_I_TEMPy, W_I_TEMPy, W_I_7y);\
-    s1_1y (YMM_TEMP0, W_I_2y);\
-
-#define Block_Y_xx_7(i, w_0, w_4, w_8, w_12)\
-    s1_2y (YMM_TEMP0, W_I_2y);\
-
-#define Block_Y_xx_8(i, w_0, w_4, w_8, w_12)\
-    s1_3y (YMM_TEMP0, W_I_2y);\
-    ADDy(w_0, W_I_TEMPy, YMM_TEMP0);\
-
-#define Block_Y_xx_9(i, w_0, w_4, w_8, w_12)\
-    FEEDBACK1_to_W_I_2(W_I_2y, w_0);\
-
-#define Block_Y_xx_10(i, w_0, w_4, w_8, w_12) \
-    s1_1y (YMM_TEMP0, W_I_2y);\
-
-#define Block_Y_xx_11(i, w_0, w_4, w_8, w_12) \
-    s1_2y (YMM_TEMP0, W_I_2y);\
-
-#define Block_Y_xx_12(i, w_0, w_4, w_8, w_12)\
-    s1_3y (YMM_TEMP0, W_I_2y);\
-    ADDy(w_0, W_I_TEMPy, YMM_TEMP0);\
-    MOVE_to_MEMy(w,0, w_4);\
-
-
-static INLINE void Block_Y_0_1(void) { Block_Y_xx_1(0, W_0y, W_4y, W_8y, W_12y); }
-static INLINE void Block_Y_0_2(void) { Block_Y_xx_2(0, W_0y, W_4y, W_8y, W_12y); }
-static INLINE void Block_Y_0_3(void) { Block_Y_xx_3(0, W_0y, W_4y, W_8y, W_12y); }
-static INLINE void Block_Y_0_4(void) { Block_Y_xx_4(0, W_0y, W_4y, W_8y, W_12y); }
-static INLINE void Block_Y_0_5(void) { Block_Y_xx_5(0, W_0y, W_4y, W_8y, W_12y); }
-static INLINE void Block_Y_0_6(void) { Block_Y_xx_6(0, W_0y, W_4y, W_8y, W_12y); }
-static INLINE void Block_Y_0_7(void) { Block_Y_xx_7(0, W_0y, W_4y, W_8y, W_12y); }
-static INLINE void Block_Y_0_8(void) { Block_Y_xx_8(0, W_0y, W_4y, W_8y, W_12y); }
-static INLINE void Block_Y_0_9(void) { Block_Y_xx_9(0, W_0y, W_4y, W_8y, W_12y); }
-static INLINE void Block_Y_0_10(void){ Block_Y_xx_10(0, W_0y, W_4y, W_8y, W_12y); }
-static INLINE void Block_Y_0_11(void){ Block_Y_xx_11(0, W_0y, W_4y, W_8y, W_12y); }
-static INLINE void Block_Y_0_12(word64 *w){ Block_Y_xx_12(0, W_0y, W_4y, W_8y, W_12y); }
-
-static INLINE void Block_Y_4_1(void) { Block_Y_xx_1(4, W_4y, W_8y, W_12y, W_0y); }
-static INLINE void Block_Y_4_2(void) { Block_Y_xx_2(4, W_4y, W_8y, W_12y, W_0y); }
-static INLINE void Block_Y_4_3(void) { Block_Y_xx_3(4, W_4y, W_8y, W_12y, W_0y); }
-static INLINE void Block_Y_4_4(void) { Block_Y_xx_4(4, W_4y, W_8y, W_12y, W_0y); }
-static INLINE void Block_Y_4_5(void) { Block_Y_xx_5(4, W_4y, W_8y, W_12y, W_0y); }
-static INLINE void Block_Y_4_6(void) { Block_Y_xx_6(4, W_4y, W_8y, W_12y, W_0y); }
-static INLINE void Block_Y_4_7(void) { Block_Y_xx_7(4, W_4y, W_8y, W_12y, W_0y); }
-static INLINE void Block_Y_4_8(void) { Block_Y_xx_8(4, W_4y, W_8y, W_12y, W_0y); }
-static INLINE void Block_Y_4_9(void) { Block_Y_xx_9(4, W_4y, W_8y, W_12y, W_0y); }
-static INLINE void Block_Y_4_10(void) { Block_Y_xx_10(4, W_4y, W_8y, W_12y, W_0y); }
-static INLINE void Block_Y_4_11(void) { Block_Y_xx_11(4, W_4y, W_8y, W_12y, W_0y); }
-static INLINE void Block_Y_4_12(word64 *w) { Block_Y_xx_12(4, W_4y, W_8y, W_12y, W_0y); }
-
-static INLINE void Block_Y_8_1(void) { Block_Y_xx_1(8, W_8y, W_12y, W_0y, W_4y); }
-static INLINE void Block_Y_8_2(void) { Block_Y_xx_2(8, W_8y, W_12y, W_0y, W_4y); }
-static INLINE void Block_Y_8_3(void) { Block_Y_xx_3(8, W_8y, W_12y, W_0y, W_4y); }
-static INLINE void Block_Y_8_4(void) { Block_Y_xx_4(8, W_8y, W_12y, W_0y, W_4y); }
-static INLINE void Block_Y_8_5(void) { Block_Y_xx_5(8, W_8y, W_12y, W_0y, W_4y); }
-static INLINE void Block_Y_8_6(void) { Block_Y_xx_6(8, W_8y, W_12y, W_0y, W_4y); }
-static INLINE void Block_Y_8_7(void) { Block_Y_xx_7(8, W_8y, W_12y, W_0y, W_4y); }
-static INLINE void Block_Y_8_8(void) { Block_Y_xx_8(8, W_8y, W_12y, W_0y, W_4y); }
-static INLINE void Block_Y_8_9(void) { Block_Y_xx_9(8, W_8y, W_12y, W_0y, W_4y); }
-static INLINE void Block_Y_8_10(void) { Block_Y_xx_10(8, W_8y, W_12y, W_0y, W_4y); }
-static INLINE void Block_Y_8_11(void) { Block_Y_xx_11(8, W_8y, W_12y, W_0y, W_4y); }
-static INLINE void Block_Y_8_12(word64 *w) { Block_Y_xx_12(8, W_8y, W_12y, W_0y, W_4y); }
-
-static INLINE void Block_Y_12_1(void) { Block_Y_xx_1(12, W_12y, W_0y, W_4y, W_8y); }
-static INLINE void Block_Y_12_2(void) { Block_Y_xx_2(12, W_12y, W_0y, W_4y, W_8y); }
-static INLINE void Block_Y_12_3(void) { Block_Y_xx_3(12, W_12y, W_0y, W_4y, W_8y); }
-static INLINE void Block_Y_12_4(void) { Block_Y_xx_4(12, W_12y, W_0y, W_4y, W_8y); }
-static INLINE void Block_Y_12_5(void) { Block_Y_xx_5(12, W_12y, W_0y, W_4y, W_8y); }
-static INLINE void Block_Y_12_6(void) { Block_Y_xx_6(12, W_12y, W_0y, W_4y, W_8y); }
-static INLINE void Block_Y_12_7(void) { Block_Y_xx_7(12, W_12y, W_0y, W_4y, W_8y); }
-static INLINE void Block_Y_12_8(void) { Block_Y_xx_8(12, W_12y, W_0y, W_4y, W_8y); }
-static INLINE void Block_Y_12_9(void) { Block_Y_xx_9(12, W_12y, W_0y, W_4y, W_8y); }
-static INLINE void Block_Y_12_10(void) { Block_Y_xx_10(12, W_12y, W_0y, W_4y, W_8y); }
-static INLINE void Block_Y_12_11(void) { Block_Y_xx_11(12, W_12y, W_0y, W_4y, W_8y); }
-static INLINE void Block_Y_12_12(word64 *w) { Block_Y_xx_12(12, W_12y, W_0y, W_4y, W_8y); }
-
-
-static int Transform_AVX2(wc_Sha512* sha512)
+static const unsigned long mBYTE_FLIP_MASK_Y[] =
+   { 0x0001020304050607, 0x08090a0b0c0d0e0f,
+     0x0001020304050607, 0x08090a0b0c0d0e0f };
+
+#define W_Y_0       ymm0
+#define W_Y_4       ymm1
+#define W_Y_8       ymm2
+#define W_Y_12      ymm3
+
+#define X0       xmm0
+#define X1       xmm1
+#define X2       xmm2
+#define X3       xmm3
+#define X4       xmm4
+#define X5       xmm5
+#define X6       xmm6
+#define X7       xmm7
+#define X8       xmm8
+#define X9       xmm9
+#define Y0       ymm0
+#define Y1       ymm1
+#define Y2       ymm2
+#define Y3       ymm3
+#define Y4       ymm4
+#define Y5       ymm5
+#define Y6       ymm6
+#define Y7       ymm7
+
+#define W_Y_M15     ymm12
+#define W_Y_M7      ymm13
+#define W_Y_M2      ymm14
+#define MASK_Y      ymm15
+
+#define YTMP1       ymm8
+#define YTMP2       ymm9
+#define YTMP3       ymm10
+#define YTMP4       ymm11
+
+#define YMM_REGS \
+    "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7",       \
+    "xmm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15"
+
+#define _VPERM2I128(dest, src1, src2, sel)                             \
+    "vperm2I128	$" #sel ", %%" #src2 ", %%" #src1 ", %%" #dest "\n\t"
+#define VPERM2I128(dest, src1, src2, sel) \
+       _VPERM2I128(dest, src1, src2, sel)
+
+#define _VPERMQ(dest, src, sel)                                        \
+    "vpermq	$" #sel ", %%" #src ", %%" #dest "\n\t"
+#define VPERMQ(dest, src, sel) \
+       _VPERMQ(dest, src, sel)
+
+#define _VPBLENDD(dest, src1, src2, sel)                               \
+    "vpblendd	$" #sel ", %%" #src2 ", %%" #src1 ", %%" #dest "\n\t"
+#define VPBLENDD(dest, src1, src2, sel) \
+       _VPBLENDD(dest, src1, src2, sel)
+
+#define _V_ADD_I(dest, src1, addr, i)                                  \
+    "vpaddq	 "#i"*8(%%" #addr "), %%" #src1 ", %%" #dest "\n\t"
+#define V_ADD_I(dest, src1, addr, i) \
+       _V_ADD_I(dest, src1, addr, i)
+
+#define _VMOVDQU_I(addr, i, src)                                       \
+    "vmovdqu	 %%" #src ", " #i "*8(%%" #addr ")\n\t"
+#define VMOVDQU_I(addr, i, src) \
+       _VMOVDQU_I(addr, i, src)
+
+#define MsgSched4_AVX2(W_Y_0,W_Y_4,W_Y_8,W_Y_12,a,b,c,d,e,f,g,h,i) \
+            RND_0_1(a,b,c,d,e,f,g,h,i)                             \
+    /* W[-13]..W[-15], W[-12] */                                   \
+    VPBLENDD(W_Y_M15, W_Y_0, W_Y_4, 0x03)                          \
+    /* W[-5]..W[-7], W[-4] */                                      \
+    VPBLENDD(W_Y_M7, W_Y_8, W_Y_12, 0x03)                          \
+            RND_0_2(a,b,c,d,e,f,g,h,i)                             \
+            RND_0_3(a,b,c,d,e,f,g,h,i)                             \
+    /* W_Y_M15 = W[-12]..W[-15] */                                 \
+    VPERMQ(W_Y_M15, W_Y_M15, 0x39)                                 \
+            RND_0_4(a,b,c,d,e,f,g,h,i)                             \
+    /* W_Y_M7 = W[-4]..W[-7] */                                    \
+    VPERMQ(W_Y_M7, W_Y_M7, 0x39)                                   \
+            RND_0_5(a,b,c,d,e,f,g,h,i)                             \
+            RND_0_6(a,b,c,d,e,f,g,h,i)                             \
+    /* W[-15] >>  1 */                                             \
+    V_SHIFT_R(YTMP1, W_Y_M15, 1)                                   \
+            RND_0_7(a,b,c,d,e,f,g,h,i)                             \
+    /* W[-15] << 63 */                                             \
+    V_SHIFT_L(YTMP2, W_Y_M15, 63)                                  \
+            RND_0_8(a,b,c,d,e,f,g,h,i)                             \
+    /* W[-15] >>  8 */                                             \
+    V_SHIFT_R(YTMP3, W_Y_M15, 8)                                   \
+            RND_0_9(a,b,c,d,e,f,g,h,i)                             \
+    /* W[-15] << 56 */                                             \
+    V_SHIFT_L(YTMP4, W_Y_M15, 56)                                  \
+            RND_0_10(a,b,c,d,e,f,g,h,i)                            \
+    /* W[-15] >>> 1 */                                             \
+    V_OR(YTMP1, YTMP2, YTMP1)                                      \
+            RND_0_11(a,b,c,d,e,f,g,h,i)                            \
+    /* W[-15] >>> 8 */                                             \
+    V_OR(YTMP3, YTMP4, YTMP3)                                      \
+            RND_0_12(a,b,c,d,e,f,g,h,i)                            \
+            RND_1_1(h,a,b,c,d,e,f,g,i+1)                           \
+    /* W[-15] >> 7 */                                              \
+    V_SHIFT_R(YTMP4, W_Y_M15, 7)                                   \
+            RND_1_2_A(h,a,b,c,d,e,f,g,i+1)                         \
+    /* (W[-15] >>> 1) ^ (W[-15] >>> 8) */                          \
+    V_XOR(YTMP1, YTMP3, YTMP1)                                     \
+            RND_1_2_B(h,a,b,c,d,e,f,g,i+1)                         \
+    /* (W[-15] >>> 1) ^ (W[-15] >>> 8) ^ (W[-15] >> 7) */          \
+    V_XOR(YTMP1, YTMP4, YTMP1)                                     \
+            RND_1_3(h,a,b,c,d,e,f,g,i+1)                           \
+    /* W[0] = W[-16] + W[-7] */                                    \
+    V_ADD(W_Y_0, W_Y_0, W_Y_M7)                                    \
+            RND_1_4(h,a,b,c,d,e,f,g,i+1)                           \
+    /* W[0] = W[-16] + W[-7] + s0(W[-15]) */                       \
+    V_ADD(W_Y_0, W_Y_0, YTMP1)                                     \
+            RND_1_5(h,a,b,c,d,e,f,g,i+1)                           \
+    /* 0, 0, W[-1], W[-2] */                                       \
+    VPERM2I128(W_Y_M2, W_Y_12, W_Y_12, 0x81)                       \
+            RND_1_6(h,a,b,c,d,e,f,g,i+1)                           \
+            RND_1_7(h,a,b,c,d,e,f,g,i+1)                           \
+            RND_1_8(h,a,b,c,d,e,f,g,i+1)                           \
+    /* W[-2] >> 19 */                                              \
+    V_SHIFT_R(YTMP1, W_Y_M2, 19)                                   \
+            RND_1_9(h,a,b,c,d,e,f,g,i+1)                           \
+    /* W[-2] << 45 */                                              \
+    V_SHIFT_L(YTMP2, W_Y_M2, 45)                                   \
+            RND_1_10(h,a,b,c,d,e,f,g,i+1)                          \
+    /* W[-2] >> 61 */                                              \
+    V_SHIFT_R(YTMP3, W_Y_M2, 61)                                   \
+            RND_1_11(h,a,b,c,d,e,f,g,i+1)                          \
+    /* W[-2] <<  3 */                                              \
+    V_SHIFT_L(YTMP4, W_Y_M2, 3)                                    \
+            RND_1_12(h,a,b,c,d,e,f,g,i+1)                          \
+            RND_0_1(g,h,a,b,c,d,e,f,i+2)                           \
+    /* W[-2] >>> 19 */                                             \
+    V_OR(YTMP1, YTMP2, YTMP1)                                      \
+            RND_0_2(g,h,a,b,c,d,e,f,i+2)                           \
+    /* W[-2] >>> 61 */                                             \
+    V_OR(YTMP3, YTMP4, YTMP3)                                      \
+            RND_0_3(g,h,a,b,c,d,e,f,i+2)                           \
+    /* (W[-2] >>> 19) ^ (W[-2] >>> 61) */                          \
+    V_XOR(YTMP1, YTMP3, YTMP1)                                     \
+            RND_0_4(g,h,a,b,c,d,e,f,i+2)                           \
+    /* W[-2] >>  6 */                                              \
+    V_SHIFT_R(YTMP4, W_Y_M2, 6)                                    \
+            RND_0_5(g,h,a,b,c,d,e,f,i+2)                           \
+    /* (W[-2] >>> 19) ^ (W[-2] >>> 61) ^ (W[-2] >> 6) */           \
+    V_XOR(YTMP1, YTMP4, YTMP1)                                     \
+            RND_0_6(g,h,a,b,c,d,e,f,i+2)                           \
+    /* W[0] = W[-16] + W[-7] + s0(W[-15]) + s1(W[-2]) */           \
+    V_ADD(W_Y_0, W_Y_0, YTMP1)                                     \
+            RND_0_7(g,h,a,b,c,d,e,f,i+2)                           \
+            RND_0_8(g,h,a,b,c,d,e,f,i+2)                           \
+    /* W[1], W[0], 0, 0 */                                         \
+    VPERM2I128(W_Y_M2, W_Y_0, W_Y_0, 0x08)                         \
+            RND_0_9(g,h,a,b,c,d,e,f,i+2)                           \
+            RND_0_10(g,h,a,b,c,d,e,f,i+2)                          \
+    /* W[-2] >> 19 */                                              \
+    V_SHIFT_R(YTMP1, W_Y_M2, 19)                                   \
+            RND_0_11(g,h,a,b,c,d,e,f,i+2)                          \
+    /* W[-2] << 45 */                                              \
+    V_SHIFT_L(YTMP2, W_Y_M2, 45)                                   \
+            RND_0_12(g,h,a,b,c,d,e,f,i+2)                          \
+            RND_1_1(f,g,h,a,b,c,d,e,i+3)                           \
+    /* W[-2] >> 61 */                                              \
+    V_SHIFT_R(YTMP3, W_Y_M2, 61)                                   \
+            RND_1_2(f,g,h,a,b,c,d,e,i+3)                           \
+    /* W[-2] <<  3 */                                              \
+    V_SHIFT_L(YTMP4, W_Y_M2, 3)                                    \
+            RND_1_3(f,g,h,a,b,c,d,e,i+3)                           \
+    /* W[-2] >>> 19 */                                             \
+    V_OR(YTMP1, YTMP2, YTMP1)                                      \
+            RND_1_4(f,g,h,a,b,c,d,e,i+3)                           \
+    /* W[-2] >>> 61 */                                             \
+    V_OR(YTMP3, YTMP4, YTMP3)                                      \
+            RND_1_5(f,g,h,a,b,c,d,e,i+3)                           \
+    /* (W[-2] >>> 19) ^ (W[-2] >>> 61) */                          \
+    V_XOR(YTMP1, YTMP3, YTMP1)                                     \
+            RND_1_6(f,g,h,a,b,c,d,e,i+3)                           \
+    /* W[-2] >>  6 */                                              \
+    V_SHIFT_R(YTMP4, W_Y_M2, 6)                                    \
+            RND_1_7(f,g,h,a,b,c,d,e,i+3)                           \
+    /* (W[-2] >>> 19) ^ (W[-2] >>> 61) ^ (W[-2] >> 6) */           \
+    V_XOR(YTMP1, YTMP4, YTMP1)                                     \
+            RND_1_8(f,g,h,a,b,c,d,e,i+3)                           \
+    /* W[0] = W[-16] + W[-7] + s0(W[-15]) + s1(W[-2]) */           \
+    V_ADD(W_Y_0, W_Y_0, YTMP1)                                     \
+            RND_1_9(f,g,h,a,b,c,d,e,i+3)                           \
+            RND_1_10(f,g,h,a,b,c,d,e,i+3)                          \
+            RND_1_11(f,g,h,a,b,c,d,e,i+3)                          \
+            RND_1_12(f,g,h,a,b,c,d,e,i+3)                          \
+
+#define MsgSched2_AVX2(W_0,W_2,W_4,W_6,W_8,W_10,W_12,W_14,a,b,c,d,e,f,g,h,i) \
+            RND_0_1(a,b,c,d,e,f,g,h,i)                                       \
+    VPALIGNR(W_Y_M15, W_2, W_0, 8)                                           \
+    VPALIGNR(W_Y_M7, W_10, W_8, 8)                                           \
+            RND_0_2(a,b,c,d,e,f,g,h,i)                                       \
+    V_SHIFT_R(YTMP1, W_Y_M15, 1)                                             \
+    V_SHIFT_L(YTMP2, W_Y_M15, 63)                                            \
+            RND_0_3(a,b,c,d,e,f,g,h,i)                                       \
+            RND_0_4(a,b,c,d,e,f,g,h,i)                                       \
+    V_SHIFT_R(YTMP3, W_Y_M15, 8)                                             \
+    V_SHIFT_L(YTMP4, W_Y_M15, 56)                                            \
+            RND_0_5(a,b,c,d,e,f,g,h,i)                                       \
+            RND_0_6(a,b,c,d,e,f,g,h,i)                                       \
+    V_OR(YTMP1, YTMP2, YTMP1)                                                \
+    V_OR(YTMP3, YTMP4, YTMP3)                                                \
+            RND_0_7(a,b,c,d,e,f,g,h,i)                                       \
+            RND_0_8(a,b,c,d,e,f,g,h,i)                                       \
+    V_SHIFT_R(YTMP4, W_Y_M15, 7)                                             \
+    V_XOR(YTMP1, YTMP3, YTMP1)                                               \
+            RND_0_9(a,b,c,d,e,f,g,h,i)                                       \
+            RND_0_10(a,b,c,d,e,f,g,h,i)                                      \
+    V_XOR(YTMP1, YTMP4, YTMP1)                                               \
+    V_ADD(W_0, W_0, W_Y_M7)                                                  \
+            RND_0_11(a,b,c,d,e,f,g,h,i)                                      \
+            RND_0_12(a,b,c,d,e,f,g,h,i)                                      \
+            RND_1_1(h,a,b,c,d,e,f,g,i+1)                                     \
+    V_ADD(W_0, W_0, YTMP1)                                                   \
+            RND_1_2(h,a,b,c,d,e,f,g,i+1)                                     \
+    V_SHIFT_R(YTMP1, W_14, 19)                                               \
+    V_SHIFT_L(YTMP2, W_14, 45)                                               \
+            RND_1_3(h,a,b,c,d,e,f,g,i+1)                                     \
+            RND_1_4(h,a,b,c,d,e,f,g,i+1)                                     \
+    V_SHIFT_R(YTMP3, W_14, 61)                                               \
+    V_SHIFT_L(YTMP4, W_14, 3)                                                \
+            RND_1_5(h,a,b,c,d,e,f,g,i+1)                                     \
+            RND_1_6(h,a,b,c,d,e,f,g,i+1)                                     \
+            RND_1_7(h,a,b,c,d,e,f,g,i+1)                                     \
+    V_OR(YTMP1, YTMP2, YTMP1)                                                \
+    V_OR(YTMP3, YTMP4, YTMP3)                                                \
+            RND_1_8(h,a,b,c,d,e,f,g,i+1)                                     \
+            RND_1_9(h,a,b,c,d,e,f,g,i+1)                                     \
+    V_XOR(YTMP1, YTMP3, YTMP1)                                               \
+    V_SHIFT_R(YTMP4, W_14, 6)                                                \
+            RND_1_10(h,a,b,c,d,e,f,g,i+1)                                    \
+            RND_1_11(h,a,b,c,d,e,f,g,i+1)                                    \
+    V_XOR(YTMP1, YTMP4, YTMP1)                                               \
+            RND_1_12(h,a,b,c,d,e,f,g,i+1)                                    \
+    V_ADD(W_0, W_0, YTMP1)                                                   \
+
+#define MsgSched4_AVX2_RORX_SET(W_Y_0,W_Y_4,W_Y_8,W_Y_12,a,b,c,d,e,f,g,h,i) \
+            RND_RORX_0_1(a,b,c,d,e,f,g,h,i)                                 \
+    /* W[-13]..W[-15], W[-12] */                                            \
+    VPBLENDD(W_Y_M15, W_Y_0, W_Y_4, 0x03)                                   \
+    /* W[-5]..W[-7], W[-4] */                                               \
+    VPBLENDD(W_Y_M7, W_Y_8, W_Y_12, 0x03)                                   \
+            RND_RORX_0_2(a,b,c,d,e,f,g,h,i)                                 \
+    /* W_Y_M15 = W[-12]..W[-15] */                                          \
+    VPERMQ(W_Y_M15, W_Y_M15, 0x39)                                          \
+            RND_RORX_0_3(a,b,c,d,e,f,g,h,i)                                 \
+    /* W_Y_M7 = W[-4]..W[-7] */                                             \
+    VPERMQ(W_Y_M7, W_Y_M7, 0x39)                                            \
+            RND_RORX_0_4(a,b,c,d,e,f,g,h,i)                                 \
+    /* W[-15] >>  1 */                                                      \
+    V_SHIFT_R(YTMP1, W_Y_M15, 1)                                            \
+    /* W[-15] << 63 */                                                      \
+    V_SHIFT_L(YTMP2, W_Y_M15, 63)                                           \
+            RND_RORX_0_5(a,b,c,d,e,f,g,h,i)                                 \
+    /* W[-15] >>  8 */                                                      \
+    V_SHIFT_R(YTMP3, W_Y_M15, 8)                                            \
+    /* W[-15] << 56 */                                                      \
+    V_SHIFT_L(YTMP4, W_Y_M15, 56)                                           \
+    /* W[-15] >>> 1 */                                                      \
+    V_OR(YTMP1, YTMP2, YTMP1)                                               \
+    /* W[-15] >>> 8 */                                                      \
+    V_OR(YTMP3, YTMP4, YTMP3)                                               \
+            RND_RORX_0_6(a,b,c,d,e,f,g,h,i)                                 \
+    /* W[-15] >> 7 */                                                       \
+    V_SHIFT_R(YTMP4, W_Y_M15, 7)                                            \
+            RND_RORX_0_7(a,b,c,d,e,f,g,h,i)                                 \
+    /* 0, 0, W[-1], W[-2] */                                                \
+    VPERM2I128(W_Y_M2, W_Y_12, W_Y_12, 0x81)                                \
+            RND_RORX_0_8(a,b,c,d,e,f,g,h,i)                                 \
+            RND_RORX_1_1(h,a,b,c,d,e,f,g,i+1)                               \
+    /* (W[-15] >>> 1) ^ (W[-15] >>> 8) */                                   \
+    V_XOR(YTMP1, YTMP3, YTMP1)                                              \
+            RND_RORX_1_2(h,a,b,c,d,e,f,g,i+1)                               \
+    /* (W[-15] >>> 1) ^ (W[-15] >>> 8) ^ (W[-15] >> 7) */                   \
+    V_XOR(YTMP1, YTMP4, YTMP1)                                              \
+            RND_RORX_1_3(h,a,b,c,d,e,f,g,i+1)                               \
+    /* W[0] = W[-16] + W[-7] */                                             \
+    V_ADD(W_Y_0, W_Y_0, W_Y_M7)                                             \
+    /* W[0] = W[-16] + W[-7] + s0(W[-15]) */                                \
+    V_ADD(W_Y_0, W_Y_0, YTMP1)                                              \
+            RND_RORX_1_4(h,a,b,c,d,e,f,g,i+1)                               \
+    /* W[-2] >> 19 */                                                       \
+    V_SHIFT_R(YTMP1, W_Y_M2, 19)                                            \
+    /* W[-2] << 45 */                                                       \
+    V_SHIFT_L(YTMP2, W_Y_M2, 45)                                            \
+            RND_RORX_1_5(h,a,b,c,d,e,f,g,i+1)                               \
+    /* W[-2] >> 61 */                                                       \
+    V_SHIFT_R(YTMP3, W_Y_M2, 61)                                            \
+    /* W[-2] <<  3 */                                                       \
+    V_SHIFT_L(YTMP4, W_Y_M2, 3)                                             \
+    /* W[-2] >>> 19 */                                                      \
+    V_OR(YTMP1, YTMP2, YTMP1)                                               \
+            RND_RORX_1_6(h,a,b,c,d,e,f,g,i+1)                               \
+    /* W[-2] >>> 61 */                                                      \
+    V_OR(YTMP3, YTMP4, YTMP3)                                               \
+            RND_RORX_1_7(h,a,b,c,d,e,f,g,i+1)                               \
+    /* (W[-2] >>> 19) ^ (W[-2] >>> 61) */                                   \
+    V_XOR(YTMP1, YTMP3, YTMP1)                                              \
+            RND_RORX_1_8(h,a,b,c,d,e,f,g,i+1)                               \
+    /* W[-2] >>  6 */                                                       \
+    V_SHIFT_R(YTMP4, W_Y_M2, 6)                                             \
+            RND_RORX_0_1(g,h,a,b,c,d,e,f,i+2)                               \
+    /* (W[-2] >>> 19) ^ (W[-2] >>> 61) ^ (W[-2] >> 6) */                    \
+    V_XOR(YTMP1, YTMP4, YTMP1)                                              \
+            RND_RORX_0_2(g,h,a,b,c,d,e,f,i+2)                               \
+    /* W[0] = W[-16] + W[-7] + s0(W[-15]) + s1(W[-2]) */                    \
+    V_ADD(W_Y_0, W_Y_0, YTMP1)                                              \
+            RND_RORX_0_3(g,h,a,b,c,d,e,f,i+2)                               \
+    /* W[1], W[0], 0, 0 */                                                  \
+    VPERM2I128(W_Y_M2, W_Y_0, W_Y_0, 0x08)                                  \
+            RND_RORX_0_4(g,h,a,b,c,d,e,f,i+2)                               \
+            RND_RORX_0_5(g,h,a,b,c,d,e,f,i+2)                               \
+    /* W[-2] >> 19 */                                                       \
+    V_SHIFT_R(YTMP1, W_Y_M2, 19)                                            \
+    /* W[-2] << 45 */                                                       \
+    V_SHIFT_L(YTMP2, W_Y_M2, 45)                                            \
+            RND_RORX_0_6(g,h,a,b,c,d,e,f,i+2)                               \
+    /* W[-2] >> 61 */                                                       \
+    V_SHIFT_R(YTMP3, W_Y_M2, 61)                                            \
+    /* W[-2] <<  3 */                                                       \
+    V_SHIFT_L(YTMP4, W_Y_M2, 3)                                             \
+    /* W[-2] >>> 19 */                                                      \
+    V_OR(YTMP1, YTMP2, YTMP1)                                               \
+            RND_RORX_0_7(g,h,a,b,c,d,e,f,i+2)                               \
+    /* W[-2] >>> 61 */                                                      \
+    V_OR(YTMP3, YTMP4, YTMP3)                                               \
+            RND_RORX_0_8(g,h,a,b,c,d,e,f,i+2)                               \
+    /* (W[-2] >>> 19) ^ (W[-2] >>> 61) */                                   \
+    V_XOR(YTMP1, YTMP3, YTMP1)                                              \
+            RND_RORX_1_1(f,g,h,a,b,c,d,e,i+3)                               \
+    /* W[-2] >>  6 */                                                       \
+    V_SHIFT_R(YTMP4, W_Y_M2, 6)                                             \
+            RND_RORX_1_2(f,g,h,a,b,c,d,e,i+3)                               \
+            RND_RORX_1_3(f,g,h,a,b,c,d,e,i+3)                               \
+    /* (W[-2] >>> 19) ^ (W[-2] >>> 61) ^ (W[-2] >> 6) */                    \
+    V_XOR(YTMP1, YTMP4, YTMP1)                                              \
+            RND_RORX_1_4(f,g,h,a,b,c,d,e,i+3)                               \
+            RND_RORX_1_5(f,g,h,a,b,c,d,e,i+3)                               \
+    /* W[0] = W[-16] + W[-7] + s0(W[-15]) + s1(W[-2]) */                    \
+    V_ADD(W_Y_0, W_Y_0, YTMP1)                                              \
+            RND_RORX_1_6(f,g,h,a,b,c,d,e,i+3)                               \
+    V_ADD_I(YTMP1, W_Y_0, rsi, i)                                           \
+            RND_RORX_1_7(f,g,h,a,b,c,d,e,i+3)                               \
+            RND_RORX_1_8(f,g,h,a,b,c,d,e,i+3)                               \
+    VMOVDQU_I(rsp, i, YTMP1)                                                \
+
+#define MsgSched2_AVX2_RORX(W_0,W_2,W_4,W_6,W_8,W_10,W_12,W_14,a,b,c,d,e,  \
+                            f,g,h,i)                                       \
+            RND_RORX_0_1(a,b,c,d,e,f,g,h,i)                                \
+    VPALIGNR(W_Y_M15, W_2, W_0, 8)                                         \
+    VPALIGNR(W_Y_M7, W_10, W_8, 8)                                         \
+            RND_RORX_0_2(a,b,c,d,e,f,g,h,i)                                \
+    V_SHIFT_R(YTMP1, W_Y_M15, 1)                                           \
+    V_SHIFT_L(YTMP2, W_Y_M15, 63)                                          \
+            RND_RORX_0_3(a,b,c,d,e,f,g,h,i)                                \
+    V_SHIFT_R(YTMP3, W_Y_M15, 8)                                           \
+    V_SHIFT_L(YTMP4, W_Y_M15, 56)                                          \
+            RND_RORX_0_4(a,b,c,d,e,f,g,h,i)                                \
+    V_OR(YTMP1, YTMP2, YTMP1)                                              \
+    V_OR(YTMP3, YTMP4, YTMP3)                                              \
+            RND_RORX_0_5(a,b,c,d,e,f,g,h,i)                                \
+    V_SHIFT_R(YTMP4, W_Y_M15, 7)                                           \
+    V_XOR(YTMP1, YTMP3, YTMP1)                                             \
+            RND_RORX_0_6(a,b,c,d,e,f,g,h,i)                                \
+    V_XOR(YTMP1, YTMP4, YTMP1)                                             \
+    V_ADD(W_0, W_0, W_Y_M7)                                                \
+            RND_RORX_0_7(a,b,c,d,e,f,g,h,i)                                \
+            RND_RORX_0_8(a,b,c,d,e,f,g,h,i)                                \
+    V_ADD(W_0, W_0, YTMP1)                                                 \
+            RND_RORX_1_1(h,a,b,c,d,e,f,g,i+1)                              \
+    V_SHIFT_R(YTMP1, W_14, 19)                                             \
+    V_SHIFT_L(YTMP2, W_14, 45)                                             \
+            RND_RORX_1_2(h,a,b,c,d,e,f,g,i+1)                              \
+    V_SHIFT_R(YTMP3, W_14, 61)                                             \
+    V_SHIFT_L(YTMP4, W_14, 3)                                              \
+            RND_RORX_1_3(h,a,b,c,d,e,f,g,i+1)                              \
+    V_OR(YTMP1, YTMP2, YTMP1)                                              \
+    V_OR(YTMP3, YTMP4, YTMP3)                                              \
+            RND_RORX_1_4(h,a,b,c,d,e,f,g,i+1)                              \
+            RND_RORX_1_5(h,a,b,c,d,e,f,g,i+1)                              \
+    V_XOR(YTMP1, YTMP3, YTMP1)                                             \
+    V_SHIFT_R(YTMP4, W_14, 6)                                              \
+            RND_RORX_1_6(h,a,b,c,d,e,f,g,i+1)                              \
+            RND_RORX_1_7(h,a,b,c,d,e,f,g,i+1)                              \
+    V_XOR(YTMP1, YTMP4, YTMP1)                                             \
+            RND_RORX_1_8(h,a,b,c,d,e,f,g,i+1)                              \
+    V_ADD(W_0, W_0, YTMP1)                                                 \
+
+
+#define _INIT_MASK_Y(mask)            \
+    "vmovdqu %[mask], %%"#mask"\n\t"
+#define INIT_MASK_Y(mask) \
+       _INIT_MASK_Y(mask)
+
+/* Load into YMM registers and swap endian. */
+#define _LOAD_BLOCK_W_Y_2(mask, ymm0, ymm1, reg, i)           \
+    /* buffer[0..15] => ymm0..ymm3;  */                       \
+    "vmovdqu	" #i "+ 0(%%" #reg "), %%" #ymm0 "\n\t"       \
+    "vmovdqu	" #i "+32(%%" #reg "), %%" #ymm1 "\n\t"       \
+    "vpshufb	%%" #mask ", %%" #ymm0 ", %%" #ymm0 "\n\t"    \
+    "vpshufb	%%" #mask ", %%" #ymm1 ", %%" #ymm1 "\n\t"
+
+#define LOAD_BLOCK_W_Y_2(mask, ymm1, ymm2, reg, i) \
+       _LOAD_BLOCK_W_Y_2(mask, ymm1, ymm2, reg, i)
+
+#define LOAD_BLOCK_W_Y(mask, reg)                  \
+    LOAD_BLOCK_W_Y_2(mask, W_Y_0, W_Y_4 , reg,  0) \
+    LOAD_BLOCK_W_Y_2(mask, W_Y_8, W_Y_12, reg, 64)
+
+#define _SET_W_Y_2(ymm0, ymm1, ymm2, ymm3, reg, i)                    \
+    "vpaddq	" #i "+ 0(%%" #reg "), %%" #ymm0 ", %%" #ymm2 "\n\t"  \
+    "vpaddq	" #i "+32(%%" #reg "), %%" #ymm1 ", %%" #ymm3 "\n\t"  \
+    "vmovdqu	%%" #ymm2 ", " #i "+ 0(" WX ")\n\t"                   \
+    "vmovdqu	%%" #ymm3 ", " #i "+32(" WX ")\n\t"
+
+#define SET_W_Y_2(ymm0, ymm1, ymm2, ymm3, reg, i) \
+       _SET_W_Y_2(ymm0, ymm1, ymm2, ymm3, reg, i)
+
+#define SET_BLOCK_W_Y(reg)                          \
+    SET_W_Y_2(W_Y_0, W_Y_4 , YTMP1, YTMP2, reg,  0) \
+    SET_W_Y_2(W_Y_8, W_Y_12, YTMP1, YTMP2, reg, 64)
+
+/* Load into YMM registers and swap endian. */
+#define _LOAD_BLOCK2_W_Y_2(mask, Y0, Y1, X0, X1, X8, X9, reg, i)   \
+    "vmovdqu	" #i "+  0(%%" #reg "), %%" #X0 "\n\t"                   \
+    "vmovdqu	" #i "+ 16(%%" #reg "), %%" #X1 "\n\t"                   \
+    "vmovdqu	" #i "+128(%%" #reg "), %%" #X8 "\n\t"                   \
+    "vmovdqu	" #i "+144(%%" #reg "), %%" #X9 "\n\t"                   \
+    "vinserti128	$1, %%" #X8 ", %%" #Y0 ", %%" #Y0 "\n\t"         \
+    "vinserti128	$1, %%" #X9 ", %%" #Y1 ", %%" #Y1 "\n\t"         \
+    "vpshufb	%%" #mask ", %%" #Y0 ", %%" #Y0 "\n\t"                   \
+    "vpshufb	%%" #mask ", %%" #Y1 ", %%" #Y1 "\n\t"
+
+#define LOAD_BLOCK2_W_Y_2(mask, Y0, Y1, X0, X1, X8, X9, reg, i) \
+       _LOAD_BLOCK2_W_Y_2(mask, Y0, Y1, X0, X1, X8, X9, reg, i)
+
+#define LOAD_BLOCK2_W_Y(mask, reg)                           \
+    LOAD_BLOCK2_W_Y_2(mask, Y0, Y1, X0, X1, X8, X9, reg,  0) \
+    LOAD_BLOCK2_W_Y_2(mask, Y2, Y3, X2, X3, X8, X9, reg, 32) \
+    LOAD_BLOCK2_W_Y_2(mask, Y4, Y5, X4, X5, X8, X9, reg, 64) \
+    LOAD_BLOCK2_W_Y_2(mask, Y6, Y7, X6, X7, X8, X9, reg, 96) \
+
+#define SET_BLOCK2_W_Y(reg)                   \
+    SET_W_Y_2(Y0, Y1, YTMP1, YTMP2, reg,   0) \
+    SET_W_Y_2(Y2, Y3, YTMP1, YTMP2, reg,  64) \
+    SET_W_Y_2(Y4, Y5, YTMP1, YTMP2, reg, 128) \
+    SET_W_Y_2(Y6, Y7, YTMP1, YTMP2, reg, 192)
+
+static const word64 K512_AVX2[160] = {
+    W64LIT(0x428a2f98d728ae22), W64LIT(0x7137449123ef65cd),
+    W64LIT(0x428a2f98d728ae22), W64LIT(0x7137449123ef65cd),
+    W64LIT(0xb5c0fbcfec4d3b2f), W64LIT(0xe9b5dba58189dbbc),
+    W64LIT(0xb5c0fbcfec4d3b2f), W64LIT(0xe9b5dba58189dbbc),
+    W64LIT(0x3956c25bf348b538), W64LIT(0x59f111f1b605d019),
+    W64LIT(0x3956c25bf348b538), W64LIT(0x59f111f1b605d019),
+    W64LIT(0x923f82a4af194f9b), W64LIT(0xab1c5ed5da6d8118),
+    W64LIT(0x923f82a4af194f9b), W64LIT(0xab1c5ed5da6d8118),
+    W64LIT(0xd807aa98a3030242), W64LIT(0x12835b0145706fbe),
+    W64LIT(0xd807aa98a3030242), W64LIT(0x12835b0145706fbe),
+    W64LIT(0x243185be4ee4b28c), W64LIT(0x550c7dc3d5ffb4e2),
+    W64LIT(0x243185be4ee4b28c), W64LIT(0x550c7dc3d5ffb4e2),
+    W64LIT(0x72be5d74f27b896f), W64LIT(0x80deb1fe3b1696b1),
+    W64LIT(0x72be5d74f27b896f), W64LIT(0x80deb1fe3b1696b1),
+    W64LIT(0x9bdc06a725c71235), W64LIT(0xc19bf174cf692694),
+    W64LIT(0x9bdc06a725c71235), W64LIT(0xc19bf174cf692694),
+    W64LIT(0xe49b69c19ef14ad2), W64LIT(0xefbe4786384f25e3),
+    W64LIT(0xe49b69c19ef14ad2), W64LIT(0xefbe4786384f25e3),
+    W64LIT(0x0fc19dc68b8cd5b5), W64LIT(0x240ca1cc77ac9c65),
+    W64LIT(0x0fc19dc68b8cd5b5), W64LIT(0x240ca1cc77ac9c65),
+    W64LIT(0x2de92c6f592b0275), W64LIT(0x4a7484aa6ea6e483),
+    W64LIT(0x2de92c6f592b0275), W64LIT(0x4a7484aa6ea6e483),
+    W64LIT(0x5cb0a9dcbd41fbd4), W64LIT(0x76f988da831153b5),
+    W64LIT(0x5cb0a9dcbd41fbd4), W64LIT(0x76f988da831153b5),
+    W64LIT(0x983e5152ee66dfab), W64LIT(0xa831c66d2db43210),
+    W64LIT(0x983e5152ee66dfab), W64LIT(0xa831c66d2db43210),
+    W64LIT(0xb00327c898fb213f), W64LIT(0xbf597fc7beef0ee4),
+    W64LIT(0xb00327c898fb213f), W64LIT(0xbf597fc7beef0ee4),
+    W64LIT(0xc6e00bf33da88fc2), W64LIT(0xd5a79147930aa725),
+    W64LIT(0xc6e00bf33da88fc2), W64LIT(0xd5a79147930aa725),
+    W64LIT(0x06ca6351e003826f), W64LIT(0x142929670a0e6e70),
+    W64LIT(0x06ca6351e003826f), W64LIT(0x142929670a0e6e70),
+    W64LIT(0x27b70a8546d22ffc), W64LIT(0x2e1b21385c26c926),
+    W64LIT(0x27b70a8546d22ffc), W64LIT(0x2e1b21385c26c926),
+    W64LIT(0x4d2c6dfc5ac42aed), W64LIT(0x53380d139d95b3df),
+    W64LIT(0x4d2c6dfc5ac42aed), W64LIT(0x53380d139d95b3df),
+    W64LIT(0x650a73548baf63de), W64LIT(0x766a0abb3c77b2a8),
+    W64LIT(0x650a73548baf63de), W64LIT(0x766a0abb3c77b2a8),
+    W64LIT(0x81c2c92e47edaee6), W64LIT(0x92722c851482353b),
+    W64LIT(0x81c2c92e47edaee6), W64LIT(0x92722c851482353b),
+    W64LIT(0xa2bfe8a14cf10364), W64LIT(0xa81a664bbc423001),
+    W64LIT(0xa2bfe8a14cf10364), W64LIT(0xa81a664bbc423001),
+    W64LIT(0xc24b8b70d0f89791), W64LIT(0xc76c51a30654be30),
+    W64LIT(0xc24b8b70d0f89791), W64LIT(0xc76c51a30654be30),
+    W64LIT(0xd192e819d6ef5218), W64LIT(0xd69906245565a910),
+    W64LIT(0xd192e819d6ef5218), W64LIT(0xd69906245565a910),
+    W64LIT(0xf40e35855771202a), W64LIT(0x106aa07032bbd1b8),
+    W64LIT(0xf40e35855771202a), W64LIT(0x106aa07032bbd1b8),
+    W64LIT(0x19a4c116b8d2d0c8), W64LIT(0x1e376c085141ab53),
+    W64LIT(0x19a4c116b8d2d0c8), W64LIT(0x1e376c085141ab53),
+    W64LIT(0x2748774cdf8eeb99), W64LIT(0x34b0bcb5e19b48a8),
+    W64LIT(0x2748774cdf8eeb99), W64LIT(0x34b0bcb5e19b48a8),
+    W64LIT(0x391c0cb3c5c95a63), W64LIT(0x4ed8aa4ae3418acb),
+    W64LIT(0x391c0cb3c5c95a63), W64LIT(0x4ed8aa4ae3418acb),
+    W64LIT(0x5b9cca4f7763e373), W64LIT(0x682e6ff3d6b2b8a3),
+    W64LIT(0x5b9cca4f7763e373), W64LIT(0x682e6ff3d6b2b8a3),
+    W64LIT(0x748f82ee5defb2fc), W64LIT(0x78a5636f43172f60),
+    W64LIT(0x748f82ee5defb2fc), W64LIT(0x78a5636f43172f60),
+    W64LIT(0x84c87814a1f0ab72), W64LIT(0x8cc702081a6439ec),
+    W64LIT(0x84c87814a1f0ab72), W64LIT(0x8cc702081a6439ec),
+    W64LIT(0x90befffa23631e28), W64LIT(0xa4506cebde82bde9),
+    W64LIT(0x90befffa23631e28), W64LIT(0xa4506cebde82bde9),
+    W64LIT(0xbef9a3f7b2c67915), W64LIT(0xc67178f2e372532b),
+    W64LIT(0xbef9a3f7b2c67915), W64LIT(0xc67178f2e372532b),
+    W64LIT(0xca273eceea26619c), W64LIT(0xd186b8c721c0c207),
+    W64LIT(0xca273eceea26619c), W64LIT(0xd186b8c721c0c207),
+    W64LIT(0xeada7dd6cde0eb1e), W64LIT(0xf57d4f7fee6ed178),
+    W64LIT(0xeada7dd6cde0eb1e), W64LIT(0xf57d4f7fee6ed178),
+    W64LIT(0x06f067aa72176fba), W64LIT(0x0a637dc5a2c898a6),
+    W64LIT(0x06f067aa72176fba), W64LIT(0x0a637dc5a2c898a6),
+    W64LIT(0x113f9804bef90dae), W64LIT(0x1b710b35131c471b),
+    W64LIT(0x113f9804bef90dae), W64LIT(0x1b710b35131c471b),
+    W64LIT(0x28db77f523047d84), W64LIT(0x32caab7b40c72493),
+    W64LIT(0x28db77f523047d84), W64LIT(0x32caab7b40c72493),
+    W64LIT(0x3c9ebe0a15c9bebc), W64LIT(0x431d67c49c100d4c),
+    W64LIT(0x3c9ebe0a15c9bebc), W64LIT(0x431d67c49c100d4c),
+    W64LIT(0x4cc5d4becb3e42b6), W64LIT(0x597f299cfc657e2a),
+    W64LIT(0x4cc5d4becb3e42b6), W64LIT(0x597f299cfc657e2a),
+    W64LIT(0x5fcb6fab3ad6faec), W64LIT(0x6c44198c4a475817),
+    W64LIT(0x5fcb6fab3ad6faec), W64LIT(0x6c44198c4a475817)
+};
+static const word64* K512_AVX2_END = &K512_AVX2[128];
+
+static int Transform_Sha512_AVX2(wc_Sha512* sha512)
 {
-    const word64* K = K512;
-    word64 w[4];
-    word32 j;
-    word64 T[8];
-
-    /* Copy digest to working vars */
-    XMEMCPY(T, sha512->digest, sizeof(T));
-
-    W_from_buff_Y(sha512->buffer);
-    MOVE_to_MEMy(w,0, W_0y);
-    for (j = 0; j < 80; j += 16) {
-        Ry_1( 0, w[0]); Block_Y_0_1(); Ry_2( 0, w[0]); Block_Y_0_2();
-                                       Ry_3( 0, w[0]); Block_Y_0_3();
-        Ry_1( 1, w[1]); Block_Y_0_4(); Ry_2( 1, w[1]); Block_Y_0_5();
-                                       Ry_3( 1, w[1]); Block_Y_0_6();
-        Ry_1( 2, w[2]); Block_Y_0_7(); Ry_2( 2, w[2]); Block_Y_0_8();
-                                       Ry_3( 2, w[2]); Block_Y_0_9();
-        Ry_1( 3, w[3]); Block_Y_0_10();Ry_2( 3, w[3]); Block_Y_0_11();
-                                       Ry_3( 3, w[3]); Block_Y_0_12(w);
-
-        Ry_1( 4, w[0]); Block_Y_4_1(); Ry_2( 4, w[0]); Block_Y_4_2();
-                                       Ry_3( 4, w[0]); Block_Y_4_3();
-        Ry_1( 5, w[1]); Block_Y_4_4(); Ry_2( 5, w[1]); Block_Y_4_5();
-                                       Ry_3( 5, w[1]); Block_Y_4_6();
-        Ry_1( 6, w[2]); Block_Y_4_7(); Ry_2( 6, w[2]); Block_Y_4_8();
-                                       Ry_3( 6, w[2]); Block_Y_4_9();
-        Ry_1( 7, w[3]); Block_Y_4_10(); Ry_2( 7, w[3]);Block_Y_4_11();
-                                        Ry_3( 7, w[3]);Block_Y_4_12(w);
-
-        Ry_1( 8, w[0]); Block_Y_8_1(); Ry_2( 8, w[0]); Block_Y_8_2();
-                                       Ry_3( 8, w[0]); Block_Y_8_3();
-        Ry_1( 9, w[1]); Block_Y_8_4(); Ry_2( 9, w[1]); Block_Y_8_5();
-                                       Ry_3( 9, w[1]); Block_Y_8_6();
-        Ry_1(10, w[2]); Block_Y_8_7(); Ry_2(10, w[2]); Block_Y_8_8();
-                                       Ry_3(10, w[2]); Block_Y_8_9();
-        Ry_1(11, w[3]); Block_Y_8_10();Ry_2(11, w[3]); Block_Y_8_11();
-                                       Ry_3(11, w[3]); Block_Y_8_12(w);
-
-        Ry_1(12, w[0]); Block_Y_12_1(); Ry_2(12, w[0]); Block_Y_12_2();
-                                        Ry_3(12, w[0]); Block_Y_12_3();
-        Ry_1(13, w[1]); Block_Y_12_4(); Ry_2(13, w[1]); Block_Y_12_5();
-                                        Ry_3(13, w[1]); Block_Y_12_6();
-        Ry_1(14, w[2]); Block_Y_12_7(); Ry_2(14, w[2]); Block_Y_12_8();
-                                        Ry_3(14, w[2]); Block_Y_12_9();
-        Ry_1(15, w[3]); Block_Y_12_10();Ry_2(15, w[3]); Block_Y_12_11();
-                                        Ry_3(15, w[3]);Block_Y_12_12(w);
-    }
-
-    /* Add the working vars back into digest */
-    sha512->digest[0] += a(0);
-    sha512->digest[1] += b(0);
-    sha512->digest[2] += c(0);
-    sha512->digest[3] += d(0);
-    sha512->digest[4] += e(0);
-    sha512->digest[5] += f(0);
-    sha512->digest[6] += g(0);
-    sha512->digest[7] += h(0);
-
-    /* Wipe variables */
-#if !defined(HAVE_INTEL_AVX1) && !defined(HAVE_INTEL_AVX2)
-    XMEMSET(W, 0, sizeof(word64) * 16);
-#endif
-    XMEMSET(T, 0, sizeof(T));
+    __asm__ __volatile__ (
+
+        /* 16 Ws plus loop counter and K512. */
+        "subq	$136, %%rsp\n\t"
+        "leaq	64(%[sha512]), %%rax\n\t"
+
+    INIT_MASK(MASK_Y)
+    LOAD_DIGEST()
+
+    LOAD_BLOCK_W_Y(MASK_Y, rax)
+
+        "movl	$4, 16*8(" WX ")\n\t"
+        "leaq	%[K512], %%rsi\n\t"
+        /* b */
+        "movq	%%r9, " L4 "\n\t"
+        /* e */
+        "movq	%%r12, " L1 "\n\t"
+        /* b ^ c */
+        "xorq	%%r10, " L4 "\n\t"
+
+    SET_BLOCK_W_Y(rsi)
+
+        "# Start of 16 rounds\n"
+        "1:\n\t"
+
+        "addq	$128, %%rsi\n\t"
+
+    MsgSched4_AVX2(W_Y_0,W_Y_4,W_Y_8,W_Y_12,RA,RB,RC,RD,RE,RF,RG,RH, 0)
+    MsgSched4_AVX2(W_Y_4,W_Y_8,W_Y_12,W_Y_0,RE,RF,RG,RH,RA,RB,RC,RD, 4)
+    MsgSched4_AVX2(W_Y_8,W_Y_12,W_Y_0,W_Y_4,RA,RB,RC,RD,RE,RF,RG,RH, 8)
+    MsgSched4_AVX2(W_Y_12,W_Y_0,W_Y_4,W_Y_8,RE,RF,RG,RH,RA,RB,RC,RD,12)
+
+    SET_BLOCK_W_Y(rsi)
+
+        "subl	$1, 16*8(" WX ")\n\t"
+        "jne	1b\n\t"
+
+    RND_ALL_2(RA,RB,RC,RD,RE,RF,RG,RH, 0)
+    RND_ALL_2(RG,RH,RA,RB,RC,RD,RE,RF, 2)
+    RND_ALL_2(RE,RF,RG,RH,RA,RB,RC,RD, 4)
+    RND_ALL_2(RC,RD,RE,RF,RG,RH,RA,RB, 6)
+
+    RND_ALL_2(RA,RB,RC,RD,RE,RF,RG,RH, 8)
+    RND_ALL_2(RG,RH,RA,RB,RC,RD,RE,RF,10)
+    RND_ALL_2(RE,RF,RG,RH,RA,RB,RC,RD,12)
+    RND_ALL_2(RC,RD,RE,RF,RG,RH,RA,RB,14)
+
+    STORE_ADD_DIGEST()
+
+        "addq	$136, %%rsp\n\t"
+
+        :
+        : [mask]   "m" (mBYTE_FLIP_MASK_Y),
+          [sha512] "r" (sha512),
+          [K512]   "m" (K512)
+        : WORK_REGS, STATE_REGS, YMM_REGS, "memory", "rsi"
+    );
+
+    return 0;
+    }
+
+static int Transform_Sha512_AVX2_Len(wc_Sha512* sha512, word32 len)
+{
+    if ((len & WC_SHA512_BLOCK_SIZE) != 0) {
+        XMEMCPY(sha512->buffer, sha512->data, WC_SHA512_BLOCK_SIZE);
+        Transform_Sha512_AVX2(sha512);
+        sha512->data += WC_SHA512_BLOCK_SIZE;
+        len -= WC_SHA512_BLOCK_SIZE;
+        if (len == 0)
+            return 0;
+    }
+
+    __asm__ __volatile__ (
+
+        "movq	224(%[sha512]), %%rcx\n\t"
+
+    INIT_MASK(MASK_Y)
+    LOAD_DIGEST()
+
+        "# Start of processing two blocks\n"
+        "2:\n\t"
+
+        "subq	$1344, %%rsp\n\t"
+        "leaq	%[K512], %%rsi\n\t"
+
+        /* L4 = b */
+        "movq	%%r9, " L4 "\n\t"
+        /* e */
+        "movq	%%r12, " L1 "\n\t"
+
+    LOAD_BLOCK2_W_Y(MASK_Y, rcx)
+
+        /* L4 = b ^ c */
+        "xorq	%%r10, " L4 "\n\t"
+        "\n"
+        "1:\n\t"
+    SET_BLOCK2_W_Y(rsi)
+    MsgSched2_AVX2(Y0,Y1,Y2,Y3,Y4,Y5,Y6,Y7,RA,RB,RC,RD,RE,RF,RG,RH, 0)
+    MsgSched2_AVX2(Y1,Y2,Y3,Y4,Y5,Y6,Y7,Y0,RG,RH,RA,RB,RC,RD,RE,RF, 4)
+    MsgSched2_AVX2(Y2,Y3,Y4,Y5,Y6,Y7,Y0,Y1,RE,RF,RG,RH,RA,RB,RC,RD, 8)
+    MsgSched2_AVX2(Y3,Y4,Y5,Y6,Y7,Y0,Y1,Y2,RC,RD,RE,RF,RG,RH,RA,RB,12)
+    MsgSched2_AVX2(Y4,Y5,Y6,Y7,Y0,Y1,Y2,Y3,RA,RB,RC,RD,RE,RF,RG,RH,16)
+    MsgSched2_AVX2(Y5,Y6,Y7,Y0,Y1,Y2,Y3,Y4,RG,RH,RA,RB,RC,RD,RE,RF,20)
+    MsgSched2_AVX2(Y6,Y7,Y0,Y1,Y2,Y3,Y4,Y5,RE,RF,RG,RH,RA,RB,RC,RD,24)
+    MsgSched2_AVX2(Y7,Y0,Y1,Y2,Y3,Y4,Y5,Y6,RC,RD,RE,RF,RG,RH,RA,RB,28)
+        "addq	$256, %%rsi\n\t"
+        "addq	$256, %%rsp\n\t"
+        "cmpq	%[K512_END], %%rsi\n\t"
+        "jne	1b\n\t"
+
+    SET_BLOCK2_W_Y(rsi)
+    RND_ALL_2(RA,RB,RC,RD,RE,RF,RG,RH, 0)
+    RND_ALL_2(RG,RH,RA,RB,RC,RD,RE,RF, 4)
+    RND_ALL_2(RE,RF,RG,RH,RA,RB,RC,RD, 8)
+    RND_ALL_2(RC,RD,RE,RF,RG,RH,RA,RB,12)
+
+    RND_ALL_2(RA,RB,RC,RD,RE,RF,RG,RH,16)
+    RND_ALL_2(RG,RH,RA,RB,RC,RD,RE,RF,20)
+    RND_ALL_2(RE,RF,RG,RH,RA,RB,RC,RD,24)
+    RND_ALL_2(RC,RD,RE,RF,RG,RH,RA,RB,28)
+        "subq	$1024, %%rsp\n\t"
+
+    ADD_DIGEST()
+    STORE_DIGEST()
+
+        /* L4 = b */
+        "movq	%%r9, " L4 "\n\t"
+        /* e */
+        "movq	%%r12, " L1 "\n\t"
+        /* L4 = b ^ c */
+        "xorq	%%r10, " L4 "\n\t"
+
+        "movq	$5, %%rsi\n\t"
+        "\n"
+        "3:\n\t"
+    RND_ALL_2(RA,RB,RC,RD,RE,RF,RG,RH, 2)
+    RND_ALL_2(RG,RH,RA,RB,RC,RD,RE,RF, 6)
+    RND_ALL_2(RE,RF,RG,RH,RA,RB,RC,RD,10)
+    RND_ALL_2(RC,RD,RE,RF,RG,RH,RA,RB,14)
+
+    RND_ALL_2(RA,RB,RC,RD,RE,RF,RG,RH,18)
+    RND_ALL_2(RG,RH,RA,RB,RC,RD,RE,RF,22)
+    RND_ALL_2(RE,RF,RG,RH,RA,RB,RC,RD,26)
+    RND_ALL_2(RC,RD,RE,RF,RG,RH,RA,RB,30)
+        "addq	$256, %%rsp\n\t"
+        "subq	$1, %%rsi\n\t"
+        "jnz	3b\n\t"
+
+    ADD_DIGEST()
+
+        "movq	224(%[sha512]), %%rcx\n\t"
+        "addq	$64, %%rsp\n\t"
+        "addq	$256, %%rcx\n\t"
+        "subl	$256, %[len]\n\t"
+        "movq	%%rcx, 224(%[sha512])\n\t"
+
+    STORE_DIGEST()
+
+        "jnz	2b\n\t"
+
+        :
+        : [mask]   "m" (mBYTE_FLIP_MASK_Y),
+          [len]    "m" (len),
+          [sha512] "r" (sha512),
+          [K512]   "m" (K512_AVX2),
+          [K512_END]   "m" (K512_AVX2_END)
+        : WORK_REGS, STATE_REGS, YMM_REGS, "memory", "rsi"
+    );
 
     return 0;
 }
+
+#ifdef HAVE_INTEL_RORX
+static int Transform_Sha512_AVX2_RORX(wc_Sha512* sha512)
+{
+    __asm__ __volatile__ (
+
+        /* 16 Ws plus loop counter. */
+        "subq	$136, %%rsp\n\t"
+        "leaq	64(%[sha512]), " L2 "\n\t"
+
+    INIT_MASK(MASK_Y)
+    LOAD_DIGEST()
+
+    LOAD_BLOCK_W_Y(MASK_Y, rcx)
+
+        "movl	$4, 16*8(" WX ")\n\t"
+        "leaq	%[K512], %%rsi\n\t"
+        /* b */
+        "movq	%%r9, " L4 "\n\t"
+        /* L3 = 0 (add to prev h) */
+        "xorq	" L3 ", " L3 "\n\t"
+        /* b ^ c */
+        "xorq	%%r10, " L4 "\n\t"
+
+    SET_BLOCK_W_Y(rsi)
+
+        "# Start of 16 rounds\n"
+        "1:\n\t"
+
+        "addq	$128, %%rsi\n\t"
+
+    MsgSched4_AVX2_RORX_SET(W_Y_0,W_Y_4,W_Y_8,W_Y_12,RA,RB,RC,RD,RE,RF,RG,RH, 0)
+    MsgSched4_AVX2_RORX_SET(W_Y_4,W_Y_8,W_Y_12,W_Y_0,RE,RF,RG,RH,RA,RB,RC,RD, 4)
+    MsgSched4_AVX2_RORX_SET(W_Y_8,W_Y_12,W_Y_0,W_Y_4,RA,RB,RC,RD,RE,RF,RG,RH, 8)
+    MsgSched4_AVX2_RORX_SET(W_Y_12,W_Y_0,W_Y_4,W_Y_8,RE,RF,RG,RH,RA,RB,RC,RD,12)
+
+        "subl	$1, 16*8(%%rsp)\n\t"
+        "jnz	1b\n\t"
+
+    RND_RORX_ALL_4(RA,RB,RC,RD,RE,RF,RG,RH, 0)
+    RND_RORX_ALL_4(RE,RF,RG,RH,RA,RB,RC,RD, 4)
+    RND_RORX_ALL_4(RA,RB,RC,RD,RE,RF,RG,RH, 8)
+    RND_RORX_ALL_4(RE,RF,RG,RH,RA,RB,RC,RD,12)
+        /* Prev RND: h += Maj(a,b,c) */
+        "addq	" L3 ", %%r8\n\t"
+        "addq	$136, %%rsp\n\t"
+
+    STORE_ADD_DIGEST()
+
+        :
+        : [mask]   "m" (mBYTE_FLIP_MASK_Y),
+          [sha512] "r" (sha512),
+          [K512]   "m" (K512)
+        : WORK_REGS, STATE_REGS, YMM_REGS, "memory", "rsi"
+    );
+
+    return 0;
+}
+
+static int Transform_Sha512_AVX2_RORX_Len(wc_Sha512* sha512, word32 len)
+{
+    if ((len & WC_SHA512_BLOCK_SIZE) != 0) {
+        XMEMCPY(sha512->buffer, sha512->data, WC_SHA512_BLOCK_SIZE);
+        Transform_Sha512_AVX2_RORX(sha512);
+        sha512->data += WC_SHA512_BLOCK_SIZE;
+        len -= WC_SHA512_BLOCK_SIZE;
+        if (len == 0)
+            return 0;
+    }
+
+    __asm__ __volatile__ (
+
+        "movq	224(%[sha512]), %%rax\n\t"
+
+    INIT_MASK(MASK_Y)
+    LOAD_DIGEST()
+
+        "# Start of processing two blocks\n"
+        "2:\n\t"
+
+        "subq	$1344, %%rsp\n\t"
+        "leaq	%[K512], %%rsi\n\t"
+
+        /* L4 = b */
+        "movq	%%r9, " L4 "\n\t"
+        /* L3 = 0 (add to prev h) */
+        "xorq	" L3 ", " L3 "\n\t"
+
+    LOAD_BLOCK2_W_Y(MASK_Y, rax)
+
+        /* L4 = b ^ c */
+        "xorq	%%r10, " L4 "\n\t"
+        "\n"
+        "1:\n\t"
+    SET_BLOCK2_W_Y(rsi)
+    MsgSched2_AVX2_RORX(Y0,Y1,Y2,Y3,Y4,Y5,Y6,Y7,RA,RB,RC,RD,RE,RF,RG,RH, 0)
+    MsgSched2_AVX2_RORX(Y1,Y2,Y3,Y4,Y5,Y6,Y7,Y0,RG,RH,RA,RB,RC,RD,RE,RF, 4)
+    MsgSched2_AVX2_RORX(Y2,Y3,Y4,Y5,Y6,Y7,Y0,Y1,RE,RF,RG,RH,RA,RB,RC,RD, 8)
+    MsgSched2_AVX2_RORX(Y3,Y4,Y5,Y6,Y7,Y0,Y1,Y2,RC,RD,RE,RF,RG,RH,RA,RB,12)
+    MsgSched2_AVX2_RORX(Y4,Y5,Y6,Y7,Y0,Y1,Y2,Y3,RA,RB,RC,RD,RE,RF,RG,RH,16)
+    MsgSched2_AVX2_RORX(Y5,Y6,Y7,Y0,Y1,Y2,Y3,Y4,RG,RH,RA,RB,RC,RD,RE,RF,20)
+    MsgSched2_AVX2_RORX(Y6,Y7,Y0,Y1,Y2,Y3,Y4,Y5,RE,RF,RG,RH,RA,RB,RC,RD,24)
+    MsgSched2_AVX2_RORX(Y7,Y0,Y1,Y2,Y3,Y4,Y5,Y6,RC,RD,RE,RF,RG,RH,RA,RB,28)
+        "addq	$256, %%rsi\n\t"
+        "addq	$256, %%rsp\n\t"
+        "cmpq	%[K512_END], %%rsi\n\t"
+        "jne	1b\n\t"
+
+    SET_BLOCK2_W_Y(rsi)
+    RND_RORX_ALL_2(RA,RB,RC,RD,RE,RF,RG,RH, 0)
+    RND_RORX_ALL_2(RG,RH,RA,RB,RC,RD,RE,RF, 4)
+    RND_RORX_ALL_2(RE,RF,RG,RH,RA,RB,RC,RD, 8)
+    RND_RORX_ALL_2(RC,RD,RE,RF,RG,RH,RA,RB,12)
+
+    RND_RORX_ALL_2(RA,RB,RC,RD,RE,RF,RG,RH,16)
+    RND_RORX_ALL_2(RG,RH,RA,RB,RC,RD,RE,RF,20)
+    RND_RORX_ALL_2(RE,RF,RG,RH,RA,RB,RC,RD,24)
+    RND_RORX_ALL_2(RC,RD,RE,RF,RG,RH,RA,RB,28)
+        "addq	" L3 ", %%r8\n\t"
+        "subq	$1024, %%rsp\n\t"
+
+    ADD_DIGEST()
+    STORE_DIGEST()
+
+        /* L4 = b */
+        "movq	%%r9, " L4 "\n\t"
+        /* L3 = 0 (add to prev h) */
+        "xorq	" L3 ", " L3 "\n\t"
+        /* L4 = b ^ c */
+        "xorq	%%r10, " L4 "\n\t"
+
+        "movq	$5, %%rsi\n\t"
+        "\n"
+        "3:\n\t"
+    RND_RORX_ALL_2(RA,RB,RC,RD,RE,RF,RG,RH, 2)
+    RND_RORX_ALL_2(RG,RH,RA,RB,RC,RD,RE,RF, 6)
+    RND_RORX_ALL_2(RE,RF,RG,RH,RA,RB,RC,RD,10)
+    RND_RORX_ALL_2(RC,RD,RE,RF,RG,RH,RA,RB,14)
+
+    RND_RORX_ALL_2(RA,RB,RC,RD,RE,RF,RG,RH,18)
+    RND_RORX_ALL_2(RG,RH,RA,RB,RC,RD,RE,RF,22)
+    RND_RORX_ALL_2(RE,RF,RG,RH,RA,RB,RC,RD,26)
+    RND_RORX_ALL_2(RC,RD,RE,RF,RG,RH,RA,RB,30)
+        "addq	$256, %%rsp\n\t"
+        "subq	$1, %%rsi\n\t"
+        "jnz	3b\n\t"
+
+        "addq	" L3 ", %%r8\n\t"
+
+    ADD_DIGEST()
+
+        "movq	224(%[sha512]), %%rax\n\t"
+        "addq	$64, %%rsp\n\t"
+        "addq	$256, %%rax\n\t"
+        "subl	$256, %[len]\n\t"
+        "movq	%%rax, 224(%[sha512])\n\t"
+
+    STORE_DIGEST()
+
+        "jnz	2b\n\t"
+
+        :
+        : [mask]   "m" (mBYTE_FLIP_MASK_Y),
+          [len]    "m" (len),
+          [sha512] "r" (sha512),
+          [K512]   "m" (K512_AVX2),
+          [K512_END]   "m" (K512_AVX2_END)
+        : WORK_REGS, STATE_REGS, YMM_REGS, "memory", "rsi"
+    );
+
+    return 0;
+}
+#endif /* HAVE_INTEL_RORX */
 #endif /* HAVE_INTEL_AVX2 */
 
+#endif /* WOLFSSL_SHA512 */
 
 
@@ -1346,4 +2614,9 @@
 /* -------------------------------------------------------------------------- */
 #ifdef WOLFSSL_SHA384
+
+#if defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_HASH)
+    /* functions defined in wolfcrypt/src/port/caam/caam_sha.c */
+#else
+
 static int InitSha384(wc_Sha384* sha384)
 {
@@ -1386,4 +2659,25 @@
 
 
+int wc_Sha384FinalRaw(wc_Sha384* sha384, byte* hash)
+{
+#ifdef LITTLE_ENDIAN_ORDER
+    word64 digest[WC_SHA384_DIGEST_SIZE / sizeof(word64)];
+#endif
+
+    if (sha384 == NULL || hash == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+#ifdef LITTLE_ENDIAN_ORDER
+    ByteReverseWords64((word64*)digest, (word64*)sha384->digest,
+                                                         WC_SHA384_DIGEST_SIZE);
+    XMEMCPY(hash, digest, WC_SHA384_DIGEST_SIZE);
+#else
+    XMEMCPY(hash, sha384->digest, WC_SHA384_DIGEST_SIZE);
+#endif
+
+    return 0;
+}
+
 int wc_Sha384Final(wc_Sha384* sha384, byte* hash)
 {
@@ -1412,19 +2706,4 @@
 }
 
-
-/* Hardware Acceleration */
-#if defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
-    int wc_InitSha384_ex(wc_Sha384* sha384, void* heap, int devId)
-    {
-        int ret = InitSha384(sha384);
-
-        (void)heap;
-        (void)devId;
-
-        Sha512_SetTransform();
-
-        return ret;
-    }
-#else
 int wc_InitSha384_ex(wc_Sha384* sha384, void* heap, int devId)
 {
@@ -1439,4 +2718,11 @@
     if (ret != 0)
         return ret;
+
+#if defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
+    Sha512_SetTransform();
+#endif
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+    sha384->W = NULL;
+#endif
 
 #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_SHA384)
@@ -1449,5 +2735,6 @@
     return ret;
 }
-#endif
+
+#endif /* WOLFSSL_IMX6_CAAM */
 
 int wc_InitSha384(wc_Sha384* sha384)
@@ -1461,4 +2748,11 @@
         return;
 
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+    if (sha384->W != NULL) {
+        XFREE(sha384->W, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        sha384->W = NULL;
+    }
+#endif
+
 #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_SHA384)
     wolfAsync_DevCtxFree(&sha384->asyncDev, WOLFSSL_ASYNC_MARKER_SHA384);
@@ -1470,4 +2764,5 @@
 #endif /* HAVE_FIPS */
 
+#ifdef WOLFSSL_SHA512
 
 int wc_Sha512GetHash(wc_Sha512* sha512, byte* hash)
@@ -1482,4 +2777,5 @@
     if (ret == 0) {
         ret = wc_Sha512Final(&tmpSha512, hash);
+        wc_Sha512Free(&tmpSha512);
     }
     return ret;
@@ -1494,4 +2790,7 @@
 
     XMEMCPY(dst, src, sizeof(wc_Sha512));
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+    dst->W = NULL;
+#endif
 
 #ifdef WOLFSSL_ASYNC_CRYPT
@@ -1502,5 +2801,8 @@
 }
 
+#endif /* WOLFSSL_SHA512 */
+
 #ifdef WOLFSSL_SHA384
+
 int wc_Sha384GetHash(wc_Sha384* sha384, byte* hash)
 {
@@ -1514,4 +2816,5 @@
     if (ret == 0) {
         ret = wc_Sha384Final(&tmpSha384, hash);
+        wc_Sha384Free(&tmpSha384);
     }
     return ret;
@@ -1525,4 +2828,7 @@
 
     XMEMCPY(dst, src, sizeof(wc_Sha384));
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+    dst->W = NULL;
+#endif
 
 #ifdef WOLFSSL_ASYNC_CRYPT
@@ -1532,5 +2838,6 @@
     return ret;
 }
+
 #endif /* WOLFSSL_SHA384 */
 
-#endif /* WOLFSSL_SHA512 */
+#endif /* WOLFSSL_SHA512 || WOLFSSL_SHA384 */
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/wc_encrypt.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/wc_encrypt.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/wc_encrypt.c	(revision 372)
@@ -28,7 +28,19 @@
 #include <wolfssl/wolfcrypt/aes.h>
 #include <wolfssl/wolfcrypt/des3.h>
+#include <wolfssl/wolfcrypt/hash.h>
+#include <wolfssl/wolfcrypt/arc4.h>
 #include <wolfssl/wolfcrypt/wc_encrypt.h>
 #include <wolfssl/wolfcrypt/error-crypt.h>
-
+#include <wolfssl/wolfcrypt/asn.h>
+#include <wolfssl/wolfcrypt/coding.h>
+#include <wolfssl/wolfcrypt/pwdbased.h>
+#include <wolfssl/wolfcrypt/logging.h>
+
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #define WOLFSSL_MISC_INCLUDED
+    #include <wolfcrypt/src/misc.c>
+#endif
 
 #if !defined(NO_AES) && defined(HAVE_AES_CBC)
@@ -225,2 +237,380 @@
 
 #endif /* !NO_DES3 */
+
+
+#ifdef WOLFSSL_ENCRYPTED_KEYS
+
+int wc_BufferKeyDecrypt(EncryptedInfo* info, byte* der, word32 derSz,
+    const byte* password, int passwordSz, int hashType)
+{
+    int ret = NOT_COMPILED_IN;
+#ifdef WOLFSSL_SMALL_STACK
+    byte* key      = NULL;
+#else
+    byte  key[WC_MAX_SYM_KEY_SIZE];
+#endif
+
+    (void)derSz;
+    (void)passwordSz;
+    (void)hashType;
+
+    if (der == NULL || password == NULL || info == NULL || info->keySz == 0) {
+        return BAD_FUNC_ARG;
+    }
+
+    /* use file's salt for key derivation, hex decode first */
+    if (Base16_Decode(info->iv, info->ivSz, info->iv, &info->ivSz) != 0) {
+        return BUFFER_E;
+    }
+    if (info->ivSz < PKCS5_SALT_SZ)
+        return BUFFER_E;
+
+#ifdef WOLFSSL_SMALL_STACK
+    key = (byte*)XMALLOC(WC_MAX_SYM_KEY_SIZE, NULL, DYNAMIC_TYPE_SYMMETRIC_KEY);
+    if (key == NULL) {
+        return MEMORY_E;
+    }
+#endif
+
+#ifndef NO_PWDBASED
+    if ((ret = wc_PBKDF1(key, password, passwordSz, info->iv, PKCS5_SALT_SZ, 1,
+                                        info->keySz, hashType)) != 0) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(key, NULL, DYNAMIC_TYPE_SYMMETRIC_KEY);
+#endif
+        return ret;
+    }
+#endif
+
+#ifndef NO_DES3
+    if (info->cipherType == WC_CIPHER_DES)
+        ret = wc_Des_CbcDecryptWithKey(der, der, derSz, key, info->iv);
+    if (info->cipherType == WC_CIPHER_DES3)
+        ret = wc_Des3_CbcDecryptWithKey(der, der, derSz, key, info->iv);
+#endif /* NO_DES3 */
+#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(HAVE_AES_DECRYPT)
+    if (info->cipherType == WC_CIPHER_AES_CBC)
+        ret = wc_AesCbcDecryptWithKey(der, der, derSz, key, info->keySz,
+            info->iv);
+#endif /* !NO_AES && HAVE_AES_CBC && HAVE_AES_DECRYPT */
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(key, NULL, DYNAMIC_TYPE_SYMMETRIC_KEY);
+#endif
+
+    return ret;
+}
+
+int wc_BufferKeyEncrypt(EncryptedInfo* info, byte* der, word32 derSz,
+    const byte* password, int passwordSz, int hashType)
+{
+    int ret = NOT_COMPILED_IN;
+#ifdef WOLFSSL_SMALL_STACK
+    byte* key      = NULL;
+#else
+    byte  key[WC_MAX_SYM_KEY_SIZE];
+#endif
+
+    (void)derSz;
+    (void)passwordSz;
+    (void)hashType;
+
+    if (der == NULL || password == NULL || info == NULL || info->keySz == 0 ||
+            info->ivSz < PKCS5_SALT_SZ) {
+        return BAD_FUNC_ARG;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    key = (byte*)XMALLOC(WC_MAX_SYM_KEY_SIZE, NULL, DYNAMIC_TYPE_SYMMETRIC_KEY);
+    if (key == NULL) {
+        return MEMORY_E;
+    }
+#endif /* WOLFSSL_SMALL_STACK */
+
+#ifndef NO_PWDBASED
+    if ((ret = wc_PBKDF1(key, password, passwordSz, info->iv, PKCS5_SALT_SZ, 1,
+                                        info->keySz, hashType)) != 0) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(key, NULL, DYNAMIC_TYPE_SYMMETRIC_KEY);
+#endif
+        return ret;
+    }
+#endif
+
+#ifndef NO_DES3
+    if (info->cipherType == WC_CIPHER_DES)
+        ret = wc_Des_CbcEncryptWithKey(der, der, derSz, key, info->iv);
+    if (info->cipherType == WC_CIPHER_DES3)
+        ret = wc_Des3_CbcEncryptWithKey(der, der, derSz, key, info->iv);
+#endif /* NO_DES3 */
+#if !defined(NO_AES) && defined(HAVE_AES_CBC)
+    if (info->cipherType == WC_CIPHER_AES_CBC)
+        ret = wc_AesCbcEncryptWithKey(der, der, derSz, key, info->keySz,
+            info->iv);
+#endif /* !NO_AES && HAVE_AES_CBC */
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(key, NULL, DYNAMIC_TYPE_SYMMETRIC_KEY);
+#endif
+
+    return ret;
+}
+
+#endif /* WOLFSSL_ENCRYPTED_KEYS */
+
+
+#ifndef NO_PWDBASED
+
+/* Decrypt/Encrypt input in place from parameters based on id
+ *
+ * returns a negative value on fail case
+ */
+int wc_CryptKey(const char* password, int passwordSz, byte* salt,
+                      int saltSz, int iterations, int id, byte* input,
+                      int length, int version, byte* cbcIv, int enc)
+{
+    int typeH;
+    int derivedLen;
+    int ret = 0;
+#ifdef WOLFSSL_SMALL_STACK
+    byte* key;
+#else
+    byte key[MAX_KEY_SIZE];
+#endif
+
+    (void)input;
+    (void)length;
+    (void)enc;
+
+    WOLFSSL_ENTER("wc_CryptKey");
+
+    switch (id) {
+    #ifndef NO_DES3
+        #ifndef NO_MD5
+        case PBE_MD5_DES:
+            typeH = WC_MD5;
+            derivedLen = 16;           /* may need iv for v1.5 */
+            break;
+        #endif
+        #ifndef NO_SHA
+        case PBE_SHA1_DES:
+            typeH = WC_SHA;
+            derivedLen = 16;           /* may need iv for v1.5 */
+            break;
+
+        case PBE_SHA1_DES3:
+            typeH = WC_SHA;
+            derivedLen = 32;           /* may need iv for v1.5 */
+            break;
+        #endif /* !NO_SHA */
+    #endif /* !NO_DES3 */
+    #if !defined(NO_SHA) && !defined(NO_RC4)
+        case PBE_SHA1_RC4_128:
+            typeH = WC_SHA;
+            derivedLen = 16;
+            break;
+    #endif
+    #ifdef WOLFSSL_AES_256
+        case PBE_AES256_CBC:
+            typeH = WC_SHA256;
+            derivedLen = 32;
+            break;
+    #endif
+        default:
+            WOLFSSL_MSG("Unknown/Unsupported encrypt/decrypt id");
+            return ALGO_ID_E;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    key = (byte*)XMALLOC(MAX_KEY_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (key == NULL)
+        return MEMORY_E;
+#endif
+
+    if (version == PKCS5v2)
+        ret = wc_PBKDF2(key, (byte*)password, passwordSz,
+                        salt, saltSz, iterations, derivedLen, typeH);
+#ifndef NO_SHA
+    else if (version == PKCS5)
+        ret = wc_PBKDF1(key, (byte*)password, passwordSz,
+                        salt, saltSz, iterations, derivedLen, typeH);
+#endif
+    else if (version == PKCS12v1) {
+        int  i, idx = 0;
+        byte unicodePasswd[MAX_UNICODE_SZ];
+
+        if ( (passwordSz * 2 + 2) > (int)sizeof(unicodePasswd)) {
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return UNICODE_SIZE_E;
+        }
+
+        for (i = 0; i < passwordSz; i++) {
+            unicodePasswd[idx++] = 0x00;
+            unicodePasswd[idx++] = (byte)password[i];
+        }
+        /* add trailing NULL */
+        unicodePasswd[idx++] = 0x00;
+        unicodePasswd[idx++] = 0x00;
+
+        ret =  wc_PKCS12_PBKDF(key, unicodePasswd, idx, salt, saltSz,
+                            iterations, derivedLen, typeH, 1);
+        if (id != PBE_SHA1_RC4_128)
+            ret += wc_PKCS12_PBKDF(cbcIv, unicodePasswd, idx, salt, saltSz,
+                                iterations, 8, typeH, 2);
+    }
+    else {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        WOLFSSL_MSG("Unknown/Unsupported PKCS version");
+        return ALGO_ID_E;
+    }
+
+    if (ret != 0) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ret;
+    }
+
+    switch (id) {
+#ifndef NO_DES3
+    #if !defined(NO_SHA) || !defined(NO_MD5)
+        case PBE_MD5_DES:
+        case PBE_SHA1_DES:
+        {
+            Des    des;
+            byte*  desIv = key + 8;
+
+            if (version == PKCS5v2 || version == PKCS12v1)
+                desIv = cbcIv;
+
+            if (enc) {
+                ret = wc_Des_SetKey(&des, key, desIv, DES_ENCRYPTION);
+            }
+            else {
+                ret = wc_Des_SetKey(&des, key, desIv, DES_DECRYPTION);
+            }
+            if (ret != 0) {
+#ifdef WOLFSSL_SMALL_STACK
+                XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+                return ret;
+            }
+
+            if (enc) {
+                wc_Des_CbcEncrypt(&des, input, input, length);
+            }
+            else {
+                wc_Des_CbcDecrypt(&des, input, input, length);
+            }
+            break;
+        }
+    #endif /* !NO_SHA || !NO_MD5 */
+
+    #ifndef NO_SHA
+        case PBE_SHA1_DES3:
+        {
+            Des3   des;
+            byte*  desIv = key + 24;
+
+            if (version == PKCS5v2 || version == PKCS12v1)
+                desIv = cbcIv;
+
+            ret = wc_Des3Init(&des, NULL, INVALID_DEVID);
+            if (ret != 0) {
+#ifdef WOLFSSL_SMALL_STACK
+                XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+                return ret;
+            }
+            if (enc) {
+                ret = wc_Des3_SetKey(&des, key, desIv, DES_ENCRYPTION);
+            }
+            else {
+                ret = wc_Des3_SetKey(&des, key, desIv, DES_DECRYPTION);
+            }
+            if (ret != 0) {
+#ifdef WOLFSSL_SMALL_STACK
+                XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+                return ret;
+            }
+            if (enc) {
+                ret = wc_Des3_CbcEncrypt(&des, input, input, length);
+            }
+            else {
+                ret = wc_Des3_CbcDecrypt(&des, input, input, length);
+            }
+            if (ret != 0) {
+#ifdef WOLFSSL_SMALL_STACK
+                XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+                return ret;
+            }
+            break;
+        }
+    #endif /* !NO_SHA */
+#endif
+#if !defined(NO_RC4) && !defined(NO_SHA)
+        case PBE_SHA1_RC4_128:
+        {
+            Arc4    dec;
+
+            wc_Arc4SetKey(&dec, key, derivedLen);
+            wc_Arc4Process(&dec, input, input, length);
+            break;
+        }
+#endif
+#if !defined(NO_AES) && defined(HAVE_AES_CBC)
+    #ifdef WOLFSSL_AES_256
+        case PBE_AES256_CBC:
+        {
+            Aes aes;
+            ret = wc_AesInit(&aes, NULL, INVALID_DEVID);
+            if (ret == 0) {
+                if (enc) {
+                    ret = wc_AesSetKey(&aes, key, derivedLen, cbcIv,
+                                                                AES_ENCRYPTION);
+                }
+                else {
+                    ret = wc_AesSetKey(&aes, key, derivedLen, cbcIv,
+                                                                AES_DECRYPTION);
+                }
+            }
+            if (ret == 0) {
+                if (enc)
+                    ret = wc_AesCbcEncrypt(&aes, input, input, length);
+                else
+                    ret = wc_AesCbcDecrypt(&aes, input, input, length);
+            }
+            if (ret != 0) {
+#ifdef WOLFSSL_SMALL_STACK
+                XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+                return ret;
+            }
+            ForceZero(&aes, sizeof(Aes));
+            break;
+        }
+    #endif /* WOLFSSL_AES_256 */
+#endif /* !NO_AES && HAVE_AES_CBC */
+
+        default:
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            WOLFSSL_MSG("Unknown/Unsupported encrypt/decryption algorithm");
+            return ALGO_ID_E;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+#endif /* !NO_PWDBASED */
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/wc_port.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/wc_port.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/wc_port.c	(revision 372)
@@ -43,10 +43,14 @@
 #endif
 
-#if defined(FREESCALE_LTC_TFM)
+#ifdef FREESCALE_LTC_TFM
     #include <wolfssl/wolfcrypt/port/nxp/ksdk_port.h>
 #endif
 
-#ifdef WOLFSSL_ATMEL
+#if defined(WOLFSSL_ATMEL) || defined(WOLFSSL_ATECC508A)
     #include <wolfssl/wolfcrypt/port/atmel/atmel.h>
+#endif
+
+#if defined(WOLFSSL_STSAFEA100)
+    #include <wolfssl/wolfcrypt/port/st/stsafe.h>
 #endif
 
@@ -58,4 +62,13 @@
     #include <wolfssl/wolfcrypt/memory.h>
     #include <wolfssl/wolfcrypt/mem_track.h>
+#endif
+
+#if defined(WOLFSSL_IMX6_CAAM) || defined(WOLFSSL_IMX6_CAAM_RNG) || \
+    defined(WOLFSSL_IMX6_CAAM_BLOB)
+    #include <wolfssl/wolfcrypt/port/caam/wolfcaam.h>
+#endif
+
+#ifdef WOLF_CRYPTO_DEV
+    #include <wolfssl/wolfcrypt/cryptodev.h>
 #endif
 
@@ -77,4 +90,19 @@
     if (initRefCount == 0) {
         WOLFSSL_ENTER("wolfCrypt_Init");
+
+    #ifdef WOLFSSL_FORCE_MALLOC_FAIL_TEST
+        {
+            word32 rngMallocFail;
+            time_t seed = time(NULL);
+            srand((word32)seed);
+            rngMallocFail = rand() % 2000; /* max 2000 */
+            printf("\n--- RNG MALLOC FAIL AT %d---\n", rngMallocFail);
+            wolfSSL_SetMemFailCount(rngMallocFail);
+        }
+    #endif
+
+    #ifdef WOLF_CRYPTO_DEV
+        wc_CryptoDev_Init();
+    #endif
 
     #ifdef WOLFSSL_ASYNC_CRYPT
@@ -125,10 +153,22 @@
     #endif
 
-    #ifdef WOLFSSL_ATMEL
-        atmel_init();
+    #if defined(WOLFSSL_ATMEL) || defined(WOLFSSL_ATECC508A)
+        ret = atmel_init();
+        if (ret != 0) {
+            WOLFSSL_MSG("CryptoAuthLib init failed");
+            return ret;
+        }
+    #endif
+
+    #if defined(WOLFSSL_STSAFEA100)
+        stsafe_interface_init();
     #endif
 
     #ifdef WOLFSSL_ARMASM
         WOLFSSL_MSG("Using ARM hardware acceleration");
+    #endif
+
+    #ifdef WOLFSSL_AFALG
+	WOLFSSL_MSG("Using AF_ALG for crypto acceleration");
     #endif
 
@@ -154,4 +194,11 @@
 #endif
 
+#if defined(WOLFSSL_IMX6_CAAM) || defined(WOLFSSL_IMX6_CAAM_RNG) || \
+    defined(WOLFSSL_IMX6_CAAM_BLOB)
+        if ((ret = wc_caamInit()) != 0) {
+            return ret;
+        }
+#endif
+
         initRefCount = 1;
     }
@@ -190,4 +237,9 @@
     #endif
 
+    #if defined(WOLFSSL_IMX6_CAAM) || defined(WOLFSSL_IMX6_CAAM_RNG) || \
+        defined(WOLFSSL_IMX6_CAAM_BLOB)
+        wc_caamFree();
+    #endif
+
         initRefCount = 0; /* allow re-init */
     }
@@ -196,11 +248,14 @@
 }
 
-#if !defined(NO_FILESYSTEM) && !defined(NO_WOLFSSL_DIR)
+#if !defined(NO_FILESYSTEM) && !defined(NO_WOLFSSL_DIR) && \
+	!defined(WOLFSSL_NUCLEUS) && !defined(WOLFSSL_NUCLEUS_1_2)
 
 /* File Handling Helpers */
-/* returns 0 if file found, -1 if no files or negative error */
+/* returns 0 if file found, WC_READDIR_NOFILE if no files or negative error */
 int wc_ReadDirFirst(ReadDirCtx* ctx, const char* path, char** name)
 {
-    int ret = -1; /* default to no files found */
+    int ret = WC_READDIR_NOFILE; /* default to no files found */
+    int pathLen = 0;
+    int dnameLen = 0;
 
     if (name)
@@ -212,8 +267,12 @@
 
     XMEMSET(ctx->name, 0, MAX_FILENAME_SZ);
+    pathLen = (int)XSTRLEN(path);
 
 #ifdef USE_WINDOWS_API
-    XSTRNCPY(ctx->name, path, MAX_FILENAME_SZ - 4);
-    XSTRNCAT(ctx->name, "\\*", 3);
+    if (pathLen > MAX_FILENAME_SZ - 3)
+        return BAD_PATH_ERROR;
+
+    XSTRNCPY(ctx->name, path, MAX_FILENAME_SZ - 3);
+    XSTRNCPY(ctx->name + pathLen, "\\*", MAX_FILENAME_SZ - pathLen);
 
     ctx->hFind = FindFirstFileA(ctx->name, &ctx->FindFileData);
@@ -225,7 +284,14 @@
     do {
         if (ctx->FindFileData.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY) {
-            XSTRNCPY(ctx->name, path, MAX_FILENAME_SZ/2 - 3);
-            XSTRNCAT(ctx->name, "\\", 2);
-            XSTRNCAT(ctx->name, ctx->FindFileData.cFileName, MAX_FILENAME_SZ/2);
+            dnameLen = (int)XSTRLEN(ctx->FindFileData.cFileName);
+
+            if (pathLen + dnameLen + 2 > MAX_FILENAME_SZ) {
+                return BAD_PATH_ERROR;
+            }
+            XSTRNCPY(ctx->name, path, pathLen + 1);
+            ctx->name[pathLen] = '\\';
+            XSTRNCPY(ctx->name + pathLen + 1,
+                     ctx->FindFileData.cFileName,
+                     MAX_FILENAME_SZ - pathLen - 1);
             if (name)
                 *name = ctx->name;
@@ -241,7 +307,14 @@
 
     while ((ctx->entry = readdir(ctx->dir)) != NULL) {
-        XSTRNCPY(ctx->name, path, MAX_FILENAME_SZ/2 - 2);
-        XSTRNCAT(ctx->name, "/", 1);
-        XSTRNCAT(ctx->name, ctx->entry->d_name, MAX_FILENAME_SZ/2);
+        dnameLen = (int)XSTRLEN(ctx->entry->d_name);
+
+        if (pathLen + dnameLen + 2 > MAX_FILENAME_SZ) {
+            ret = BAD_PATH_ERROR;
+            break;
+        }
+        XSTRNCPY(ctx->name, path, pathLen + 1);
+        ctx->name[pathLen] = '/';
+        XSTRNCPY(ctx->name + pathLen + 1,
+                 ctx->entry->d_name, MAX_FILENAME_SZ - pathLen - 1);
 
         if (stat(ctx->name, &ctx->s) != 0) {
@@ -249,5 +322,5 @@
             ret = BAD_PATH_ERROR;
             break;
-        } else if (ctx->s.st_mode & S_IFREG) {
+        } else if (S_ISREG(ctx->s.st_mode)) {
             if (name)
                 *name = ctx->name;
@@ -261,8 +334,10 @@
 }
 
-/* returns 0 if file found, -1 if no more files */
+/* returns 0 if file found, WC_READDIR_NOFILE if no more files */
 int wc_ReadDirNext(ReadDirCtx* ctx, const char* path, char** name)
 {
-    int ret = -1; /* default to no file found */
+    int ret = WC_READDIR_NOFILE; /* default to no file found */
+    int pathLen = 0;
+    int dnameLen = 0;
 
     if (name)
@@ -274,11 +349,19 @@
 
     XMEMSET(ctx->name, 0, MAX_FILENAME_SZ);
+    pathLen = (int)XSTRLEN(path);
 
 #ifdef USE_WINDOWS_API
     while (FindNextFileA(ctx->hFind, &ctx->FindFileData)) {
         if (ctx->FindFileData.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY) {
-            XSTRNCPY(ctx->name, path, MAX_FILENAME_SZ/2 - 3);
-            XSTRNCAT(ctx->name, "\\", 2);
-            XSTRNCAT(ctx->name, ctx->FindFileData.cFileName, MAX_FILENAME_SZ/2);
+            dnameLen = (int)XSTRLEN(ctx->FindFileData.cFileName);
+
+            if (pathLen + dnameLen + 2 > MAX_FILENAME_SZ) {
+                return BAD_PATH_ERROR;
+            }
+            XSTRNCPY(ctx->name, path, pathLen + 1);
+            ctx->name[pathLen] = '\\';
+            XSTRNCPY(ctx->name + pathLen + 1,
+                     ctx->FindFileData.cFileName,
+                     MAX_FILENAME_SZ - pathLen - 1);
             if (name)
                 *name = ctx->name;
@@ -288,7 +371,14 @@
 #else
     while ((ctx->entry = readdir(ctx->dir)) != NULL) {
-        XSTRNCPY(ctx->name, path, MAX_FILENAME_SZ/2 - 2);
-        XSTRNCAT(ctx->name, "/", 1);
-        XSTRNCAT(ctx->name, ctx->entry->d_name, MAX_FILENAME_SZ/2);
+        dnameLen = (int)XSTRLEN(ctx->entry->d_name);
+
+        if (pathLen + dnameLen + 2 > MAX_FILENAME_SZ) {
+            ret = BAD_PATH_ERROR;
+            break;
+        }
+        XSTRNCPY(ctx->name, path, pathLen + 1);
+        ctx->name[pathLen] = '/';
+        XSTRNCPY(ctx->name + pathLen + 1,
+                 ctx->entry->d_name, MAX_FILENAME_SZ - pathLen - 1);
 
         if (stat(ctx->name, &ctx->s) != 0) {
@@ -296,5 +386,5 @@
             ret = BAD_PATH_ERROR;
             break;
-        } else if (ctx->s.st_mode & S_IFREG) {
+        } else if (S_ISREG(ctx->s.st_mode)) {
             if (name)
                 *name = ctx->name;
@@ -403,4 +493,31 @@
 #endif /* USE_WOLF_STRTOK */
 
+#ifdef USE_WOLF_STRSEP
+char* wc_strsep(char **stringp, const char *delim)
+{
+    char *s, *tok;
+    const char *spanp;
+
+    /* null check */
+    if (stringp == NULL || *stringp == NULL)
+        return NULL;
+
+    s = *stringp;
+    for (tok = s; *tok; ++tok) {
+        for (spanp = delim; *spanp; ++spanp) {
+            /* found delimiter */
+            if (*tok == *spanp) {
+                *tok = '\0'; /* replace delim with null term */
+                *stringp = tok + 1; /* return past delim */
+                return s;
+            }
+        }
+    }
+
+    *stringp = NULL;
+    return s;
+}
+#endif /* USE_WOLF_STRSEP */
+
 #if WOLFSSL_CRYPT_HW_MUTEX
 /* Mutex for protection of cryptography hardware */
@@ -445,4 +562,37 @@
 /* Mutex Ports */
 /* ---------------------------------------------------------------------------*/
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+    static mutex_cb*     compat_mutex_cb = NULL;
+
+    /* Function that locks or unlocks a mutex based on the flag passed in.
+     *
+     * flag lock or unlock i.e. CRYPTO_LOCK
+     * type the type of lock to unlock or lock
+     * file name of the file calling
+     * line the line number from file calling
+     */
+    int wc_LockMutex_ex(int flag, int type, const char* file, int line)
+    {
+        if (compat_mutex_cb != NULL) {
+            compat_mutex_cb(flag, type, file, line);
+            return 0;
+        }
+        else {
+            WOLFSSL_MSG("Mutex call back function not set. Call wc_SetMutexCb");
+            return BAD_STATE_E;
+        }
+    }
+
+
+    /* Set the callback function to use for locking/unlocking mutex
+     *
+     * cb callback function to use
+     */
+    int wc_SetMutexCb(mutex_cb* cb)
+    {
+        compat_mutex_cb = cb;
+        return 0;
+    }
+#endif /* defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) */
 #ifdef SINGLE_THREADED
 
@@ -602,4 +752,45 @@
         else
             return BAD_MUTEX_E;
+    }
+
+#elif defined(WOLFSSL_VXWORKS)
+
+    int wc_InitMutex(wolfSSL_Mutex* m)
+    {
+        if (m) {
+            if ((*m = semMCreate(0)) != SEM_ID_NULL)
+                return 0;
+        }
+        return BAD_MUTEX_E;
+    }
+
+
+    int wc_FreeMutex(wolfSSL_Mutex* m)
+    {
+        if (m) {
+            if (semDelete(*m) == OK)
+                return 0;
+        }
+        return BAD_MUTEX_E;
+    }
+
+
+    int wc_LockMutex(wolfSSL_Mutex* m)
+    {
+        if (m) {
+            if (semTake(*m, WAIT_FOREVER) == OK)
+                return 0;
+        }
+        return BAD_MUTEX_E;
+    }
+
+
+    int wc_UnLockMutex(wolfSSL_Mutex* m)
+    {
+        if (m) {
+            if (semGive(*m) == OK)
+                return 0;
+        }
+        return BAD_MUTEX_E;
     }
 
@@ -1170,4 +1361,42 @@
     }
 
+#elif defined(WOLFSSL_NUCLEUS_1_2)
+
+    int wc_InitMutex(wolfSSL_Mutex* m)
+    {
+        /* Call the Nucleus function to create the semaphore */
+        if (NU_Create_Semaphore(m, "WOLFSSL_MTX", 1,
+                                NU_PRIORITY) == NU_SUCCESS) {
+            return 0;
+        }
+
+        return BAD_MUTEX_E;
+    }
+
+    int wc_FreeMutex(wolfSSL_Mutex* m)
+    {
+        if (NU_Delete_Semaphore(m) == NU_SUCCESS)
+            return 0;
+
+        return BAD_MUTEX_E;
+    }
+
+    int wc_LockMutex(wolfSSL_Mutex* m)
+    {
+        /* passing suspend task option */
+        if (NU_Obtain_Semaphore(m, NU_SUSPEND) == NU_SUCCESS)
+            return 0;
+
+        return BAD_MUTEX_E;
+    }
+
+    int wc_UnLockMutex(wolfSSL_Mutex* m)
+    {
+        if (NU_Release_Semaphore(m) == NU_SUCCESS)
+            return 0;
+
+        return BAD_MUTEX_E;
+    }
+
 #else
     #warning No mutex handling defined
@@ -1175,4 +1404,309 @@
 #endif
 
+#ifndef NO_ASN_TIME
+#if defined(_WIN32_WCE)
+time_t windows_time(time_t* timer)
+{
+    SYSTEMTIME     sysTime;
+    FILETIME       fTime;
+    ULARGE_INTEGER intTime;
+    time_t         localTime;
+
+    if (timer == NULL)
+        timer = &localTime;
+
+    GetSystemTime(&sysTime);
+    SystemTimeToFileTime(&sysTime, &fTime);
+
+    XMEMCPY(&intTime, &fTime, sizeof(FILETIME));
+    /* subtract EPOCH */
+    intTime.QuadPart -= 0x19db1ded53e8000;
+    /* to secs */
+    intTime.QuadPart /= 10000000;
+    *timer = (time_t)intTime.QuadPart;
+
+    return *timer;
+}
+#endif /*  _WIN32_WCE */
+
+#if defined(WOLFSSL_APACHE_MYNEWT)
+#include "os/os_time.h"
+
+time_t mynewt_time(time_t* timer)
+{
+    time_t now;
+    struct os_timeval tv;
+    os_gettimeofday(&tv, NULL);
+    now = (time_t)tv.tv_sec;
+    if(timer != NULL) {
+        *timer = now;
+    }
+    return now;
+}
+#endif /* WOLFSSL_APACHE_MYNEWT */
+
+#if defined(WOLFSSL_GMTIME)
+struct tm* gmtime(const time_t* timer)
+{
+    #define YEAR0          1900
+    #define EPOCH_YEAR     1970
+    #define SECS_DAY       (24L * 60L * 60L)
+    #define LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) %400)))
+    #define YEARSIZE(year) (LEAPYEAR(year) ? 366 : 365)
+
+    static const int _ytab[2][12] =
+    {
+        {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+        {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+    };
+
+    static struct tm st_time;
+    struct tm* ret = &st_time;
+    time_t secs = *timer;
+    unsigned long dayclock, dayno;
+    int year = EPOCH_YEAR;
+
+    dayclock = (unsigned long)secs % SECS_DAY;
+    dayno    = (unsigned long)secs / SECS_DAY;
+
+    ret->tm_sec  = (int) dayclock % 60;
+    ret->tm_min  = (int)(dayclock % 3600) / 60;
+    ret->tm_hour = (int) dayclock / 3600;
+    ret->tm_wday = (int) (dayno + 4) % 7;        /* day 0 a Thursday */
+
+    while(dayno >= (unsigned long)YEARSIZE(year)) {
+        dayno -= YEARSIZE(year);
+        year++;
+    }
+
+    ret->tm_year = year - YEAR0;
+    ret->tm_yday = (int)dayno;
+    ret->tm_mon  = 0;
+
+    while(dayno >= (unsigned long)_ytab[LEAPYEAR(year)][ret->tm_mon]) {
+        dayno -= _ytab[LEAPYEAR(year)][ret->tm_mon];
+        ret->tm_mon++;
+    }
+
+    ret->tm_mday  = (int)++dayno;
+    ret->tm_isdst = 0;
+
+    return ret;
+}
+#endif /* WOLFSSL_GMTIME */
+
+
+#if defined(HAVE_RTP_SYS)
+#define YEAR0          1900
+
+struct tm* rtpsys_gmtime(const time_t* timer)       /* has a gmtime() but hangs */
+{
+    static struct tm st_time;
+    struct tm* ret = &st_time;
+
+    DC_RTC_CALENDAR cal;
+    dc_rtc_time_get(&cal, TRUE);
+
+    ret->tm_year  = cal.year - YEAR0;       /* gm starts at 1900 */
+    ret->tm_mon   = cal.month - 1;          /* gm starts at 0 */
+    ret->tm_mday  = cal.day;
+    ret->tm_hour  = cal.hour;
+    ret->tm_min   = cal.minute;
+    ret->tm_sec   = cal.second;
+
+    return ret;
+}
+
+#endif /* HAVE_RTP_SYS */
+
+
+#if defined(MICROCHIP_TCPIP_V5) || defined(MICROCHIP_TCPIP)
+
+/*
+ * time() is just a stub in Microchip libraries. We need our own
+ * implementation. Use SNTP client to get seconds since epoch.
+ */
+time_t pic32_time(time_t* timer)
+{
+#ifdef MICROCHIP_TCPIP_V5
+    DWORD sec = 0;
+#else
+    uint32_t sec = 0;
+#endif
+    time_t localTime;
+
+    if (timer == NULL)
+        timer = &localTime;
+
+#ifdef MICROCHIP_MPLAB_HARMONY
+    sec = TCPIP_SNTP_UTCSecondsGet();
+#else
+    sec = SNTPGetUTCSeconds();
+#endif
+    *timer = (time_t) sec;
+
+    return *timer;
+}
+
+#endif /* MICROCHIP_TCPIP || MICROCHIP_TCPIP_V5 */
+
+#if defined(MICRIUM)
+
+time_t micrium_time(time_t* timer)
+{
+    CLK_TS_SEC sec;
+
+    Clk_GetTS_Unix(&sec);
+
+    if (timer != NULL)
+        *timer = sec;
+
+    return (time_t) sec;
+}
+
+#endif /* MICRIUM */
+
+#if defined(FREESCALE_MQX) || defined(FREESCALE_KSDK_MQX)
+
+time_t mqx_time(time_t* timer)
+{
+    time_t localTime;
+    TIME_STRUCT time_s;
+
+    if (timer == NULL)
+        timer = &localTime;
+
+    _time_get(&time_s);
+    *timer = (time_t) time_s.SECONDS;
+
+    return *timer;
+}
+
+#endif /* FREESCALE_MQX || FREESCALE_KSDK_MQX */
+
+
+#if defined(WOLFSSL_TIRTOS)
+
+time_t XTIME(time_t * timer)
+{
+    time_t sec = 0;
+
+    sec = (time_t) Seconds_get();
+
+    if (timer != NULL)
+        *timer = sec;
+
+    return sec;
+}
+
+#endif /* WOLFSSL_TIRTOS */
+
+#if defined(WOLFSSL_XILINX)
+#include "xrtcpsu.h"
+
+time_t XTIME(time_t * timer)
+{
+    time_t sec = 0;
+    XRtcPsu_Config* con;
+    XRtcPsu         rtc;
+
+    con = XRtcPsu_LookupConfig(XPAR_XRTCPSU_0_DEVICE_ID);
+    if (con != NULL) {
+        if (XRtcPsu_CfgInitialize(&rtc, con, con->BaseAddr) == XST_SUCCESS) {
+            sec = (time_t)XRtcPsu_GetCurrentTime(&rtc);
+        }
+        else {
+            WOLFSSL_MSG("Unable to initialize RTC");
+        }
+    }
+
+    if (timer != NULL)
+        *timer = sec;
+
+    return sec;
+}
+
+#endif /* WOLFSSL_XILINX */
+#endif /* !NO_ASN_TIME */
+
+#ifndef WOLFSSL_LEANPSK
+char* mystrnstr(const char* s1, const char* s2, unsigned int n)
+{
+    unsigned int s2_len = (unsigned int)XSTRLEN(s2);
+
+    if (s2_len == 0)
+        return (char*)s1;
+
+    while (n >= s2_len && s1[0]) {
+        if (s1[0] == s2[0])
+            if (XMEMCMP(s1, s2, s2_len) == 0)
+                return (char*)s1;
+        s1++;
+        n--;
+    }
+
+    return NULL;
+}
+#endif
+
+/* custom memory wrappers */
+#ifdef WOLFSSL_NUCLEUS_1_2
+
+    /* system memory pool */
+    extern NU_MEMORY_POOL System_Memory;
+
+    void* nucleus_malloc(unsigned long size, void* heap, int type)
+    {
+        STATUS status;
+        void*  stack_ptr;
+
+        status = NU_Allocate_Memory(&System_Memory, &stack_ptr, size,
+                                    NU_NO_SUSPEND);
+        if (status == NU_SUCCESS) {
+            return 0;
+        } else {
+            return stack_ptr;
+        }
+    }
+
+    void* nucleus_realloc(void* ptr, unsigned long size, void* heap, int type)
+    {
+        STATUS     status;
+        DM_HEADER* old_header;
+        word32     old_size, copy_size;
+        void*      new_mem;
+
+        /* if ptr is NULL, behave like malloc */
+        new_mem = nucleus_malloc(size, NULL, 0);
+        if (new_mem == 0 || ptr == 0) {
+            return new_mem;
+        }
+
+        /* calculate old memory block size */
+        /* mem pointers stored in block headers (ref dm_defs.h) */
+        old_header = (DM_HEADER*) ((byte*)ptr - DM_OVERHEAD);
+        old_size   = (byte*)old_header->dm_next_memory - (byte*)ptr;
+
+        /* copy old to new */
+        if (old_size < size) {
+            copy_size = old_size;
+        } else {
+            copy_size = size;
+        }
+        XMEMCPY(new_mem, ptr, copy_size);
+
+        /* free old */
+        nucleus_free(ptr, NULL, 0);
+
+        return new_mem;
+    }
+
+    void nucleus_free(void* ptr, void* heap, int type)
+    {
+        if (ptr != NULL)
+            NU_Deallocate_Memory(ptr);
+    }
+
+#endif /* WOLFSSL_NUCLEUS_1_2 */
 
 #if defined(WOLFSSL_TI_CRYPT) || defined(WOLFSSL_TI_HASH)
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/wolfmath.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/wolfmath.c	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/wolfmath.c	(revision 372)
@@ -30,9 +30,5 @@
 #include <wolfssl/wolfcrypt/settings.h>
 
-#ifdef USE_FAST_MATH
-    #include <wolfssl/wolfcrypt/tfm.h>
-#else
     #include <wolfssl/wolfcrypt/integer.h>
-#endif
 
 #include <wolfssl/wolfcrypt/error-crypt.h>
@@ -92,4 +88,5 @@
 }
 
+#ifndef WC_NO_RNG
 int get_rand_digit(WC_RNG* rng, mp_digit* d)
 {
@@ -100,45 +97,89 @@
 int mp_rand(mp_int* a, int digits, WC_RNG* rng)
 {
-    int ret;
-    mp_digit d;
-
-    if (rng == NULL)
-        return MISSING_RNG_E;
-
-    if (a == NULL)
-        return BAD_FUNC_ARG;
+    int ret = 0;
+    DECLARE_VAR(d, mp_digit, 1, rng ? rng->heap : NULL);
+
+    if (rng == NULL) {
+        ret = MISSING_RNG_E; goto exit;
+    }
+
+    if (a == NULL
+    #ifdef WOLFSSL_ASYNC_CRYPT
+        || d == NULL
+    #endif
+    ) {
+        ret = BAD_FUNC_ARG; goto exit;
+    }
 
     mp_zero(a);
     if (digits <= 0) {
-        return MP_OKAY;
+        ret = MP_OKAY; goto exit;
     }
 
     /* first place a random non-zero digit */
     do {
-        ret = get_rand_digit(rng, &d);
+        ret = get_rand_digit(rng, d);
         if (ret != 0) {
-            return ret;
-        }
-    } while (d == 0);
-
-    if ((ret = mp_add_d(a, d, a)) != MP_OKAY) {
-        return ret;
+            goto exit;
+        }
+    } while (*d == 0);
+
+    if ((ret = mp_add_d(a, *d, a)) != MP_OKAY) {
+        goto exit;
     }
 
     while (--digits > 0) {
         if ((ret = mp_lshd(a, 1)) != MP_OKAY) {
-            return ret;
-        }
-        if ((ret = get_rand_digit(rng, &d)) != 0) {
-            return ret;
-        }
-        if ((ret = mp_add_d(a, d, a)) != MP_OKAY) {
-            return ret;
-        }
-    }
+            goto exit;
+        }
+        if ((ret = get_rand_digit(rng, d)) != 0) {
+            goto exit;
+        }
+        if ((ret = mp_add_d(a, *d, a)) != MP_OKAY) {
+            goto exit;
+        }
+    }
+
+exit:
+    FREE_VAR(d, rng ? rng->heap : NULL);
 
     return ret;
 }
 #endif /* WC_RSA_BLINDING */
+#endif
+
+/* export an mp_int as unsigned char or hex string
+ * encType is WC_TYPE_UNSIGNED_BIN or WC_TYPE_HEX_STR
+ * return MP_OKAY on success */
+int wc_export_int(mp_int* mp, byte* buf, word32* len, word32 keySz,
+    int encType)
+{
+    int err;
+
+    if (mp == NULL)
+        return BAD_FUNC_ARG;
+
+    /* check buffer size */
+    if (*len < keySz) {
+        *len = keySz;
+        return BUFFER_E;
+    }
+
+    *len = keySz;
+    XMEMSET(buf, 0, *len);
+
+    if (encType == WC_TYPE_HEX_STR) {
+    #ifdef WC_MP_TO_RADIX
+        err = mp_tohex(mp, (char*)buf);
+    #else
+        err = NOT_COMPILED_IN;
+    #endif
+    }
+    else {
+        err = mp_to_unsigned_bin(mp, buf + (keySz - mp_unsigned_bin_size(mp)));
+    }
+
+    return err;
+}
 
 
@@ -236,18 +277,42 @@
 }
 
+/* sz: make sure the buffer is at least that size and zero padded.
+ *     A `sz == 0` will use the size of `src`.
+ *     The calulcates sz is stored into dst->len in `wc_bigint_alloc`.
+ */
+int wc_mp_to_bigint_sz(mp_int* src, WC_BIGINT* dst, word32 sz)
+{
+    int err;
+    word32 x, y;
+
+    if (src == NULL || dst == NULL)
+        return BAD_FUNC_ARG;
+
+    /* get size of source */
+    x = mp_unsigned_bin_size(src);
+    if (sz < x)
+        sz = x;
+
+    /* make sure destination is allocated and large enough */
+    err = wc_bigint_alloc(dst, sz);
+    if (err == MP_OKAY) {
+
+        /* leading zero pad */
+        y = sz - x;
+        XMEMSET(dst->buf, 0, y);
+
+        /* export src as unsigned bin to destination buf */
+        err = mp_to_unsigned_bin(src, dst->buf + y);
+    }
+
+    return err;
+}
+
 int wc_mp_to_bigint(mp_int* src, WC_BIGINT* dst)
 {
-    int err;
-    word32 sz;
-
     if (src == NULL || dst == NULL)
         return BAD_FUNC_ARG;
 
-    sz = mp_unsigned_bin_size(src);
-    err = wc_bigint_alloc(dst, sz);
-    if (err == MP_OKAY)
-        err = mp_to_unsigned_bin(src, dst->buf);
-
-    return err;
+    return wc_mp_to_bigint_sz(src, dst, 0);
 }
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/error-ssl.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/error-ssl.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/error-ssl.h	(revision 372)
@@ -58,5 +58,5 @@
     WANT_READ                    = -323,   /* want read, call again    */
     NOT_READY_ERROR              = -324,   /* handshake layer not ready */
-    PMS_VERSION_ERROR            = -325,   /* pre m secret version error */
+
     VERSION_ERROR                = -326,   /* record layer version error */
     WANT_WRITE                   = -327,   /* want write, call again   */
@@ -67,7 +67,4 @@
     SERVER_HINT_ERROR            = -332,   /* psk server hint error  */
     PSK_KEY_ERROR                = -333,   /* psk key error  */
-    ZLIB_INIT_ERROR              = -334,   /* zlib init error  */
-    ZLIB_COMPRESS_ERROR          = -335,   /* zlib compression error  */
-    ZLIB_DECOMPRESS_ERROR        = -336,   /* zlib decompression error  */
 
     GETTIME_ERROR                = -337,   /* gettimeofday failed ??? */
@@ -105,5 +102,5 @@
     SEQUENCE_ERROR               = -370,   /* dtls sequence error */
     SUITES_ERROR                 = -371,   /* suites pointer error */
-    SSL_NO_PEM_HEADER            = -372,   /* no PEM header found */
+
     OUT_OF_ORDER_E               = -373,   /* out of order message */
     BAD_KEA_TYPE_E               = -374,   /* bad KEA type found */
@@ -143,5 +140,5 @@
     BAD_CERTIFICATE_STATUS_ERROR = -406,   /* Bad certificate status message */
     OCSP_INVALID_STATUS          = -407,   /* Invalid OCSP Status */
-
+    OCSP_WANT_READ               = -408,   /* OCSP callback response WOLFSSL_CBIO_ERR_WANT_READ */
     RSA_KEY_SIZE_E               = -409,   /* RSA key too small */
     ECC_KEY_SIZE_E               = -410,   /* ECC key too small */
@@ -165,4 +162,5 @@
     ALERT_COUNT_E                = -427,   /* Alert Count exceeded err */
     EXT_MISSING                  = -428,   /* Required extension not found */
+    UNSUPPORTED_EXTENSION        = -429,   /* TLSX not requested by client */
     /* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */
 
@@ -181,5 +179,5 @@
 
 
-#ifdef WOLFSSL_CALLBACKS
+#if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
     enum {
         MIN_PARAM_ERR = UNSUPPORTED_SUITE,
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/internal.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/internal.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/internal.h	(revision 372)
@@ -70,7 +70,34 @@
     #include <wolfssl/wolfcrypt/arc4.h>
 #endif
+#ifndef NO_SHA256
+    #include <wolfssl/wolfcrypt/sha256.h>
+#endif
+#ifdef HAVE_OCSP
+    #include <wolfssl/ocsp.h>
+#endif
+#ifdef WOLFSSL_SHA384
+    #include <wolfssl/wolfcrypt/sha512.h>
+#endif
+#ifdef WOLFSSL_SHA512
+    #include <wolfssl/wolfcrypt/sha512.h>
+#endif
+#ifdef HAVE_AESGCM
+    #include <wolfssl/wolfcrypt/sha512.h>
+#endif
+#ifdef WOLFSSL_RIPEMD
+    #include <wolfssl/wolfcrypt/ripemd.h>
+#endif
+#ifdef HAVE_IDEA
+    #include <wolfssl/wolfcrypt/idea.h>
+#endif
+#ifndef NO_RSA
+    #include <wolfssl/wolfcrypt/rsa.h>
+#endif
 #ifdef HAVE_ECC
     #include <wolfssl/wolfcrypt/ecc.h>
 #endif
+#ifndef NO_DH
+    #include <wolfssl/wolfcrypt/dh.h>
+#endif
 #ifdef HAVE_ED25519
     #include <wolfssl/wolfcrypt/ed25519.h>
@@ -79,36 +106,12 @@
     #include <wolfssl/wolfcrypt/curve25519.h>
 #endif
-#ifndef NO_SHA256
-    #include <wolfssl/wolfcrypt/sha256.h>
-#endif
-#ifdef HAVE_OCSP
-    #include <wolfssl/ocsp.h>
-#endif
-#ifdef WOLFSSL_SHA512
-    #include <wolfssl/wolfcrypt/sha512.h>
-#endif
-#ifdef HAVE_AESGCM
-    #include <wolfssl/wolfcrypt/sha512.h>
-#endif
-#ifdef WOLFSSL_RIPEMD
-    #include <wolfssl/wolfcrypt/ripemd.h>
-#endif
-#ifdef HAVE_IDEA
-    #include <wolfssl/wolfcrypt/idea.h>
-#endif
-#ifndef NO_RSA
-    #include <wolfssl/wolfcrypt/rsa.h>
-#endif
-#ifdef HAVE_ECC
-    #include <wolfssl/wolfcrypt/ecc.h>
-#endif
-#ifndef NO_DH
-    #include <wolfssl/wolfcrypt/dh.h>
-#endif
-
+
+#include <wolfssl/wolfcrypt/wc_encrypt.h>
 #include <wolfssl/wolfcrypt/hash.h>
 
+#if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
+    #include <wolfssl/callbacks.h>
+#endif
 #ifdef WOLFSSL_CALLBACKS
-    #include <wolfssl/callbacks.h>
     #include <signal.h>
 #endif
@@ -142,4 +145,6 @@
 #elif defined(WOLFSSL_uTKERNEL2)
         /* do nothing */
+#elif defined(WOLFSSL_CMSIS_RTOS)
+    #include "cmsis_os.h"
 #elif defined(WOLFSSL_MDK_ARM)
     #if defined(WOLFSSL_MDK5)
@@ -155,4 +160,11 @@
 #elif defined(INTIME_RTOS)
     #include <rt.h>
+#elif defined(WOLFSSL_NUCLEUS_1_2)
+    /* do nothing */
+#elif defined(WOLFSSL_APACHE_MYNEWT)
+    #if !defined(WOLFSSL_LWIP)
+        void mynewt_ctx_clear(void *ctx);
+        void* mynewt_ctx_new();
+    #endif
 #else
     #ifndef SINGLE_THREADED
@@ -160,5 +172,5 @@
         #include <pthread.h>
     #endif
-    #if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS)
+    #ifdef OPENSSL_EXTRA
         #include <unistd.h>      /* for close of BIO */
     #endif
@@ -177,4 +189,10 @@
 #ifdef WOLFSSL_ASYNC_CRYPT
     #include <wolfssl/wolfcrypt/async.h>
+#endif
+
+#ifdef OPENSSL_EXTRA
+    #ifdef WOLFCRYPT_HAVE_SRP
+        #include <wolfssl/wolfcrypt/srp.h>
+    #endif
 #endif
 
@@ -232,4 +250,10 @@
 #ifndef WOLFSSL_MAX_STRENGTH
 
+#ifdef WOLFSSL_AEAD_ONLY
+    /* AES CBC ciphers are not allowed in AEAD only mode */
+    #undef HAVE_AES_CBC
+#endif
+
+#ifndef WOLFSSL_AEAD_ONLY
     #if !defined(NO_RSA) && !defined(NO_RC4)
         #if defined(WOLFSSL_STATIC_RSA)
@@ -264,39 +288,62 @@
         #endif
     #endif
+#endif /* !WOLFSSL_AEAD_ONLY */
 
     #if !defined(NO_RSA) && !defined(NO_AES) && !defined(NO_TLS)
-        #if !defined(NO_SHA)
+        #if !defined(NO_SHA) && defined(HAVE_AES_CBC)
             #if defined(WOLFSSL_STATIC_RSA)
+                #ifdef WOLFSSL_AES_128
                 #define BUILD_TLS_RSA_WITH_AES_128_CBC_SHA
+                #endif
+                #ifdef WOLFSSL_AES_256
                 #define BUILD_TLS_RSA_WITH_AES_256_CBC_SHA
             #endif
+            #endif
             #if defined(HAVE_NTRU) && defined(WOLFSSL_STATIC_RSA)
+                #ifdef WOLFSSL_AES_128
                     #define BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
+                #endif
+                #ifdef WOLFSSL_AES_256
                     #define BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
             #endif
         #endif
+        #endif
         #if defined(WOLFSSL_STATIC_RSA)
-            #if !defined (NO_SHA256)
+            #if !defined (NO_SHA256) && defined(HAVE_AES_CBC)
+                #ifdef WOLFSSL_AES_128
                 #define BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256
+                #endif
+                #ifdef WOLFSSL_AES_256
                 #define BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256
             #endif
+            #endif
             #if defined (HAVE_AESGCM)
+                #ifdef WOLFSSL_AES_128
                 #define BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256
-                #if defined (WOLFSSL_SHA384)
+                #endif
+                #if defined (WOLFSSL_SHA384) && defined(WOLFSSL_AES_256)
                     #define BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384
                 #endif
             #endif
             #if defined (HAVE_AESCCM)
+                #ifdef WOLFSSL_AES_128
                 #define BUILD_TLS_RSA_WITH_AES_128_CCM_8
+                #endif
+                #ifdef WOLFSSL_AES_256
                 #define BUILD_TLS_RSA_WITH_AES_256_CCM_8
             #endif
-            #if defined(HAVE_BLAKE2)
+            #endif
+            #if defined(HAVE_BLAKE2) && defined(HAVE_AES_CBC)
+                #ifdef WOLFSSL_AES_128
                 #define BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256
+                #endif
+                #ifdef WOLFSSL_AES_256
                 #define BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256
             #endif
         #endif
     #endif
-
-    #if defined(HAVE_CAMELLIA) && !defined(NO_TLS)
+    #endif
+
+    #if defined(HAVE_CAMELLIA) && !defined(NO_TLS) && !defined(NO_CAMELLIA_CBC)
         #ifndef NO_RSA
           #if defined(WOLFSSL_STATIC_RSA)
@@ -326,21 +373,35 @@
     #if !defined(NO_PSK) && !defined(NO_AES) && !defined(NO_TLS)
         #if !defined(NO_SHA)
+            #ifdef WOLFSSL_AES_128
             #define BUILD_TLS_PSK_WITH_AES_128_CBC_SHA
+            #endif
+            #ifdef WOLFSSL_AES_256
             #define BUILD_TLS_PSK_WITH_AES_256_CBC_SHA
         #endif
+        #endif
         #ifndef NO_SHA256
+            #ifdef WOLFSSL_AES_128
+                #ifdef HAVE_AES_CBC
             #define BUILD_TLS_PSK_WITH_AES_128_CBC_SHA256
+                #endif
             #ifdef HAVE_AESGCM
                 #define BUILD_TLS_PSK_WITH_AES_128_GCM_SHA256
             #endif
+            #endif /* WOLFSSL_AES_128 */
             #ifdef HAVE_AESCCM
+                #ifdef WOLFSSL_AES_128
                 #define BUILD_TLS_PSK_WITH_AES_128_CCM_8
-                #define BUILD_TLS_PSK_WITH_AES_256_CCM_8
                 #define BUILD_TLS_PSK_WITH_AES_128_CCM
+                #endif
+                #ifdef WOLFSSL_AES_256
+                    #define BUILD_TLS_PSK_WITH_AES_256_CCM_8
                 #define BUILD_TLS_PSK_WITH_AES_256_CCM
             #endif
         #endif
-        #ifdef WOLFSSL_SHA384
+        #endif
+        #if defined(WOLFSSL_SHA384) && defined(WOLFSSL_AES_256)
+            #ifdef HAVE_AES_CBC
             #define BUILD_TLS_PSK_WITH_AES_256_CBC_SHA384
+            #endif
             #ifdef HAVE_AESGCM
                 #define BUILD_TLS_PSK_WITH_AES_256_GCM_SHA384
@@ -398,24 +459,39 @@
 
         #if !defined(NO_SHA)
+            #if defined(WOLFSSL_AES_128) && defined(HAVE_AES_CBC)
             #define BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+            #endif
+            #if defined(WOLFSSL_AES_256) && defined(HAVE_AES_CBC)
             #define BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+            #endif
             #if !defined(NO_DES3)
                 #define BUILD_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
             #endif
         #endif
-        #if !defined(NO_SHA256)
+        #if !defined(NO_SHA256) && defined(HAVE_AES_CBC)
+            #ifdef WOLFSSL_AES_128
             #define BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
+            #endif
+            #ifdef WOLFSSL_AES_256
             #define BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
         #endif
     #endif
+    #endif
 
     #if defined(HAVE_ANON) && !defined(NO_TLS) && !defined(NO_DH) && \
-        !defined(NO_AES) && !defined(NO_SHA)
+        !defined(NO_AES) && !defined(NO_SHA) && defined(WOLFSSL_AES_128)
+        #ifdef HAVE_AES_CBC
         #define BUILD_TLS_DH_anon_WITH_AES_128_CBC_SHA
+    #endif
+
+        #if defined(WOLFSSL_SHA384) && defined(HAVE_AESGCM)
+            #define BUILD_TLS_DH_anon_WITH_AES_256_GCM_SHA384
+        #endif
     #endif
 
     #if !defined(NO_DH) && !defined(NO_PSK) && !defined(NO_TLS)
         #ifndef NO_SHA256
-            #ifndef NO_AES
+            #if !defined(NO_AES) && defined(WOLFSSL_AES_128) && \
+                                                           defined(HAVE_AES_CBC)
                 #define BUILD_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256
             #endif
@@ -425,5 +501,6 @@
         #endif
         #ifdef WOLFSSL_SHA384
-            #ifndef NO_AES
+            #if !defined(NO_AES) && defined(WOLFSSL_AES_256) && \
+                                                           defined(HAVE_AES_CBC)
                 #define BUILD_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384
             #endif
@@ -434,46 +511,73 @@
     #endif
 
-    #if defined(HAVE_ECC) && !defined(NO_TLS)
+    #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && !defined(NO_TLS)
         #if !defined(NO_AES)
-            #if !defined(NO_SHA)
+            #if !defined(NO_SHA) && defined(HAVE_AES_CBC)
                 #if !defined(NO_RSA)
+                    #ifdef WOLFSSL_AES_128
                     #define BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+                    #endif
+                    #ifdef WOLFSSL_AES_256
                     #define BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
-                    #if defined(WOLFSSL_STATIC_DH)
+                    #endif
+                    #if defined(WOLFSSL_STATIC_DH) && defined(HAVE_ECC)
+                        #ifdef WOLFSSL_AES_128
                         #define BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
+                        #endif
+                        #ifdef WOLFSSL_AES_256
                         #define BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
                     #endif
                 #endif
-
+                #endif
+
+                #if defined(HAVE_ECC) || (defined(HAVE_CURVE25519) && \
+                                                          defined(HAVE_ED25519))
+                    #ifdef WOLFSSL_AES_128
                 #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+                    #endif
+                    #ifdef WOLFSSL_AES_256
                 #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
-
-                #if defined(WOLFSSL_STATIC_DH)
+                    #endif
+                #endif
+
+                #if defined(WOLFSSL_STATIC_DH) && defined(HAVE_ECC)
+                    #ifdef WOLFSSL_AES_128
                     #define BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
+                    #endif
+                    #ifdef WOLFSSL_AES_256
                     #define BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
                 #endif
+                #endif
             #endif /* NO_SHA */
-            #ifndef NO_SHA256
+            #if !defined(NO_SHA256) && defined(WOLFSSL_AES_128) && \
+                                                           defined(HAVE_AES_CBC)
                 #if !defined(NO_RSA)
                     #define BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
-                    #if defined(WOLFSSL_STATIC_DH)
+                    #if defined(WOLFSSL_STATIC_DH) && defined(HAVE_ECC)
                         #define BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
                     #endif
                 #endif
+                #if defined(HAVE_ECC) || (defined(HAVE_CURVE25519) && \
+                                                          defined(HAVE_ED25519))
                 #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
-                #if defined(WOLFSSL_STATIC_DH)
+                #endif
+                #if defined(WOLFSSL_STATIC_DH) && defined(HAVE_ECC)
                     #define BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
                 #endif
             #endif
 
-            #ifdef WOLFSSL_SHA384
+            #if defined(WOLFSSL_SHA384) && defined(WOLFSSL_AES_256) && \
+                                                           defined(HAVE_AES_CBC)
                 #if !defined(NO_RSA)
                     #define BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
-                    #if defined(WOLFSSL_STATIC_DH)
+                    #if defined(WOLFSSL_STATIC_DH) && defined(HAVE_ECC)
                         #define BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
                     #endif
                 #endif
+                #if defined(HAVE_ECC) || (defined(HAVE_CURVE25519) && \
+                                                          defined(HAVE_ED25519))
                 #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
-                #if defined(WOLFSSL_STATIC_DH)
+                #endif
+                #if defined(WOLFSSL_STATIC_DH) && defined(HAVE_ECC)
                     #define BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
                 #endif
@@ -482,20 +586,26 @@
             #if defined (HAVE_AESGCM)
                 #if !defined(NO_RSA)
-                    #if defined(WOLFSSL_STATIC_DH)
+                    #if defined(WOLFSSL_STATIC_DH) && defined(HAVE_ECC)
+                        #ifdef WOLFSSL_AES_128
                         #define BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
                     #endif
+                    #endif
                     #if defined(WOLFSSL_SHA384)
-                        #if defined(WOLFSSL_STATIC_DH)
+                        #if defined(WOLFSSL_STATIC_DH) && defined(HAVE_ECC)
+                            #ifdef WOLFSSL_AES_256
                             #define BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
                         #endif
                     #endif
                 #endif
-
-                #if defined(WOLFSSL_STATIC_DH)
+                #endif
+
+                #if defined(WOLFSSL_STATIC_DH) && defined(WOLFSSL_AES_128) && \
+                                                               defined(HAVE_ECC)
                     #define BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
                 #endif
 
                 #if defined(WOLFSSL_SHA384)
-                    #if defined(WOLFSSL_STATIC_DH)
+                    #if defined(WOLFSSL_STATIC_DH) && \
+                                   defined(WOLFSSL_AES_256) && defined(HAVE_ECC)
                         #define BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
                     #endif
@@ -507,11 +617,14 @@
                 #if !defined(NO_RSA)
                     #define BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA
-                    #if defined(WOLFSSL_STATIC_DH)
+                    #if defined(WOLFSSL_STATIC_DH) && defined(HAVE_ECC)
                         #define BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA
                     #endif
                 #endif
 
+                #if defined(HAVE_ECC) || (defined(HAVE_CURVE25519) && \
+                                                          defined(HAVE_ED25519))
                 #define BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
-                #if defined(WOLFSSL_STATIC_DH)
+                #endif
+                #if defined(WOLFSSL_STATIC_DH) && defined(HAVE_ECC)
                     #define BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA
                 #endif
@@ -522,11 +635,14 @@
                 #if !defined(NO_RSA)
                     #define BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
-                    #if defined(WOLFSSL_STATIC_DH)
+                    #if defined(WOLFSSL_STATIC_DH) && defined(HAVE_ECC)
                         #define BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
                     #endif
                 #endif
 
+                #if defined(HAVE_ECC) || (defined(HAVE_CURVE25519) && \
+                                                          defined(HAVE_ED25519))
                 #define BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
-                #if defined(WOLFSSL_STATIC_DH)
+                #endif
+                #if defined(WOLFSSL_STATIC_DH) && defined(HAVE_ECC)
                     #define BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
                 #endif
@@ -535,5 +651,8 @@
         #if defined(HAVE_NULL_CIPHER)
             #if !defined(NO_SHA)
+                #if defined(HAVE_ECC) || (defined(HAVE_CURVE25519) && \
+                                                          defined(HAVE_ED25519))
                 #define BUILD_TLS_ECDHE_ECDSA_WITH_NULL_SHA
+            #endif
             #endif
             #if !defined(NO_PSK) && !defined(NO_SHA256)
@@ -541,5 +660,6 @@
             #endif
         #endif
-        #if !defined(NO_PSK) && !defined(NO_SHA256) && !defined(NO_AES)
+        #if !defined(NO_PSK) && !defined(NO_SHA256) && !defined(NO_AES) && \
+            defined(WOLFSSL_AES_128) && defined(HAVE_AES_CBC)
             #define BUILD_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256
         #endif
@@ -547,9 +667,10 @@
     #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) && !defined(NO_SHA256)
         #if !defined(NO_OLD_POLY1305)
-        #ifdef HAVE_ECC
+        #if defined(HAVE_ECC) || (defined(HAVE_CURVE25519) && \
+                                                          defined(HAVE_ED25519))
             #define BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256
-            #ifndef NO_RSA
-                #define BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256
-            #endif
+            #endif
+        #if !defined(NO_RSA) && defined(HAVE_ECC)
+            #define BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256
         #endif
         #if !defined(NO_DH) && !defined(NO_RSA)
@@ -559,5 +680,5 @@
         #if !defined(NO_PSK)
             #define BUILD_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256
-            #ifdef HAVE_ECC
+            #if defined(HAVE_ECC) || defined(HAVE_ED25519)
                 #define BUILD_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256
             #endif
@@ -573,9 +694,9 @@
     !defined(NO_RSA) && defined(HAVE_AESGCM)
 
-    #ifndef NO_SHA256
+    #if !defined(NO_SHA256) && defined(WOLFSSL_AES_128)
         #define BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
     #endif
 
-    #ifdef WOLFSSL_SHA384
+    #if defined(WOLFSSL_SHA384) && defined(WOLFSSL_AES_256)
         #define BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
     #endif
@@ -584,27 +705,39 @@
 #if !defined(NO_DH) && !defined(NO_PSK) && !defined(NO_TLS)
     #ifndef NO_SHA256
-        #ifdef HAVE_AESGCM
+        #if defined(HAVE_AESGCM) && defined(WOLFSSL_AES_128)
             #define BUILD_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256
         #endif
         #ifdef HAVE_AESCCM
+            #ifdef WOLFSSL_AES_128
             #define BUILD_TLS_DHE_PSK_WITH_AES_128_CCM
+            #endif
+            #ifdef WOLFSSL_AES_256
             #define BUILD_TLS_DHE_PSK_WITH_AES_256_CCM
         #endif
     #endif
-    #if defined(WOLFSSL_SHA384) && defined(HAVE_AESGCM)
+    #endif
+    #if defined(WOLFSSL_SHA384) && defined(HAVE_AESGCM) && \
+        defined(WOLFSSL_AES_256)
         #define BUILD_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384
     #endif
 #endif
 
-#if defined(HAVE_ECC) && !defined(NO_TLS) && !defined(NO_AES)
+#if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && !defined(NO_TLS) && \
+                                                                !defined(NO_AES)
     #ifdef HAVE_AESGCM
-        #ifndef NO_SHA256
+        #if !defined(NO_SHA256) && defined(WOLFSSL_AES_128)
+            #if defined(HAVE_ECC) || (defined(HAVE_CURVE25519) && \
+                                                          defined(HAVE_ED25519))
             #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+            #endif
             #ifndef NO_RSA
                 #define BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
             #endif
         #endif
-        #ifdef WOLFSSL_SHA384
+        #if defined(WOLFSSL_SHA384) && defined(WOLFSSL_AES_256)
+            #if defined(HAVE_ECC) || (defined(HAVE_CURVE25519) && \
+                                                          defined(HAVE_ED25519))
             #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+            #endif
             #ifndef NO_RSA
                 #define BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
@@ -613,13 +746,23 @@
     #endif
     #if defined(HAVE_AESCCM) && !defined(NO_SHA256)
+        #if defined(HAVE_ECC) || (defined(HAVE_CURVE25519) && \
+                                                          defined(HAVE_ED25519))
+            #ifdef WOLFSSL_AES_128
         #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM
         #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
+            #endif
+            #ifdef WOLFSSL_AES_256
         #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
     #endif
 #endif
+    #endif
+#endif
 
 #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) && !defined(NO_SHA256)
-    #ifdef HAVE_ECC
+    #if defined(HAVE_ECC) || defined(HAVE_CURVE25519)
+        #if defined(HAVE_ECC) || (defined(HAVE_CURVE25519) && \
+                                                          defined(HAVE_ED25519))
         #define BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
+        #endif
         #ifndef NO_RSA
             #define BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
@@ -633,13 +776,13 @@
 #if defined(WOLFSSL_TLS13)
     #ifdef HAVE_AESGCM
-        #ifndef NO_SHA256
+        #if !defined(NO_SHA256) && defined(WOLFSSL_AES_128)
             #define BUILD_TLS_AES_128_GCM_SHA256
         #endif
-        #ifdef WOLFSSL_SHA384
+        #if defined(WOLFSSL_SHA384) && defined(WOLFSSL_AES_256)
             #define BUILD_TLS_AES_256_GCM_SHA384
         #endif
     #endif
 
-    #ifdef HAVE_CHACHA
+    #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
         #ifndef NO_SHA256
             #define BUILD_TLS_CHACHA20_POLY1305_SHA256
@@ -648,5 +791,5 @@
 
     #ifdef HAVE_AESCCM
-        #ifndef NO_SHA256
+        #if !defined(NO_SHA256) && defined(WOLFSSL_AES_128)
             #define BUILD_TLS_AES_128_CCM_SHA256
             #define BUILD_TLS_AES_128_CCM_8_SHA256
@@ -689,4 +832,23 @@
     defined(BUILD_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384)
     #define BUILD_AESGCM
+#else
+    /* No AES-GCM cipher suites available with build */
+    #define NO_AESGCM_AEAD
+#endif
+
+#if defined(BUILD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256) || \
+    defined(BUILD_TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256) || \
+    defined(BUILD_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256) || \
+    defined(BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256) || \
+    defined(BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256) || \
+    defined(BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256) || \
+    defined(BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256) || \
+    defined(BUILD_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256) || \
+    defined(BUILD_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256) || \
+    defined(BUILD_TLS_CHACHA20_POLY1305_SHA256)
+    /* Have an available ChaCha Poly cipher suite */
+#else
+    /* No ChaCha Poly cipher suites available with build */
+    #define NO_CHAPOL_AEAD
 #endif
 
@@ -726,6 +888,7 @@
 
 #if defined(WOLFSSL_MAX_STRENGTH) || \
-    defined(HAVE_AESGCM) || defined(HAVE_AESCCM) || \
-    (defined(HAVE_CHACHA) && defined(HAVE_POLY1305))
+    (defined(HAVE_AESGCM) && !defined(NO_AESGCM_AEAD)) || \
+     defined(HAVE_AESCCM) || \
+    (defined(HAVE_CHACHA) && defined(HAVE_POLY1305) && !defined(NO_CHAPOL_AEAD))
 
     #define HAVE_AEAD
@@ -833,4 +996,5 @@
     TLS_DHE_RSA_WITH_AES_128_GCM_SHA256      = 0x9e,
     TLS_DHE_RSA_WITH_AES_256_GCM_SHA384      = 0x9f,
+    TLS_DH_anon_WITH_AES_256_GCM_SHA384      = 0xa7,
     TLS_PSK_WITH_AES_128_GCM_SHA256          = 0xa8,
     TLS_PSK_WITH_AES_256_GCM_SHA384          = 0xa9,
@@ -927,6 +1091,35 @@
 
 
+/* set minimum DH key size allowed */
+#ifndef WOLFSSL_MIN_DHKEY_BITS
+    #ifdef WOLFSSL_MAX_STRENGTH
+        #define WOLFSSL_MIN_DHKEY_BITS 2048
+    #else
+        #define WOLFSSL_MIN_DHKEY_BITS 1024
+    #endif
+#endif
+#if (WOLFSSL_MIN_DHKEY_BITS % 8)
+    #error DH minimum bit size must be multiple of 8
+#endif
+#if (WOLFSSL_MIN_DHKEY_BITS > 16000)
+    #error DH minimum bit size must not be greater than 16000
+#endif
+#define MIN_DHKEY_SZ (WOLFSSL_MIN_DHKEY_BITS / 8)
+/* set maximum DH key size allowed */
+#ifndef WOLFSSL_MAX_DHKEY_BITS
+    #define WOLFSSL_MAX_DHKEY_BITS 4096
+#endif
+#if (WOLFSSL_MAX_DHKEY_BITS % 8)
+    #error DH maximum bit size must be multiple of 8
+#endif
+#if (WOLFSSL_MAX_DHKEY_BITS > 16000)
+    #error DH maximum bit size must not be greater than 16000
+#endif
+#define MAX_DHKEY_SZ (WOLFSSL_MAX_DHKEY_BITS / 8)
+
+
 
 enum Misc {
+    CIPHER_BYTE = 0x00,            /* Default ciphers */
     ECC_BYTE    = 0xC0,            /* ECC first cipher suite byte */
     QSH_BYTE    = 0xD0,            /* Quantum-safe Handshake cipher suite */
@@ -946,9 +1139,17 @@
     TLSv1_2_MINOR   = 3,        /* TLSv1_2 minor version number */
     TLSv1_3_MINOR   = 4,        /* TLSv1_3 minor version number */
+#ifdef WOLFSSL_TLS13_DRAFT
     TLS_DRAFT_MAJOR = 0x7f,     /* Draft TLS major version number */
 #ifdef WOLFSSL_TLS13_DRAFT_18
     TLS_DRAFT_MINOR = 0x12,     /* Minor version number of TLS draft */
+#elif defined(WOLFSSL_TLS13_DRAFT_22)
+    TLS_DRAFT_MINOR = 0x16,     /* Minor version number of TLS draft */
+#elif defined(WOLFSSL_TLS13_DRAFT_23)
+    TLS_DRAFT_MINOR = 0x17,     /* Minor version number of TLS draft */
+#elif defined(WOLFSSL_TLS13_DRAFT_26)
+    TLS_DRAFT_MINOR = 0x1a,     /* Minor version number of TLS draft */
 #else
-    TLS_DRAFT_MINOR = 0x14,     /* Minor version number of TLS draft */
+    TLS_DRAFT_MINOR = 0x1c,     /* Minor version number of TLS draft */
+#endif
 #endif
     OLD_HELLO_ID    = 0x01,     /* SSLv2 Client Hello Indicator */
@@ -968,5 +1169,5 @@
     FINISHED_SZ     = 36,       /* WC_MD5_DIGEST_SIZE + WC_SHA_DIGEST_SIZE */
     MAX_RECORD_SIZE = 16384,    /* 2^14, max size by standard */
-    MAX_MSG_EXTRA   = 38 + MAX_DIGEST_SIZE,
+    MAX_MSG_EXTRA   = 38 + WC_MAX_DIGEST_SIZE,
                                 /* max added to msg, mac + pad  from */
                                 /* RECORD_HEADER_SZ + BLOCK_SZ (pad) + Max
@@ -975,5 +1176,6 @@
     MAX_MTU         = WOLFSSL_MAX_MTU,     /* max expected MTU */
     MAX_UDP_SIZE    = 8192 - 100, /* was MAX_MTU - 100 */
-    MAX_DH_SZ       = 1036,     /* 4096 p, pub, g + 2 byte size for each */
+    MAX_DH_SZ       = (MAX_DHKEY_SZ * 3) + 12, /* DH_P, DH_G and DH_Pub */
+                                /* 4096 p, pub, g + 2 byte size for each */
     MAX_STR_VERSION = 8,        /* string rep of protocol version */
 
@@ -981,10 +1183,5 @@
     PAD_SHA        = 40,       /* pad length for finished */
     MAX_PAD_SIZE   = 256,      /* maximum length of padding */
-    COMPRESS_DUMMY_SIZE = 64,  /* compression dummy round size */
-    COMPRESS_CONSTANT   = 13,  /* compression calc constant */
-    COMPRESS_UPPER      = 55,  /* compression calc numerator */
-    COMPRESS_LOWER      = 64,  /* compression calc denominator */
-
-    PEM_LINE_LEN   = 80,       /* PEM line max + fudge */
+
     LENGTH_SZ      =  2,       /* length field for HMAC, data only */
     VERSION_SZ     =  2,       /* length of proctocol version */
@@ -994,8 +1191,12 @@
     EXTS_SZ        =  2,       /* always use 2 bytes      */
     EXT_ID_SZ      =  2,       /* always use 2 bytes      */
-    MAX_DH_SIZE    = 513,      /* 4096 bit plus possible leading 0 */
+    MAX_DH_SIZE    = MAX_DHKEY_SZ+1,
+                               /* Max size plus possible leading 0 */
     NAMED_DH_MASK  = 0x100,    /* Named group mask for DH parameters  */
     SESSION_HINT_SZ = 4,       /* session timeout hint */
     SESSION_ADD_SZ = 4,        /* session age add */
+    TICKET_NONCE_LEN_SZ = 1,   /* Ticket nonce length size */
+    DEF_TICKET_NONCE_SZ = 1,   /* Default ticket nonce size */
+    MAX_TICKET_NONCE_SZ = 8,   /* maximum ticket nonce size */
     MAX_LIFETIME   = 604800,   /* maximum ticket lifetime */
     MAX_EARLY_DATA_SZ = 4096,  /* maximum early data size */
@@ -1029,5 +1230,4 @@
     HELLO_EXT_SZ_SZ       = 2,  /* length of a hello extension size */
     HELLO_EXT_SIGALGO_SZ  = 2,  /* length of number of items in sigalgo list */
-    HELLO_EXT_SIGALGO_MAX = 32, /* number of items in the signature algo list */
 
     DTLS_HANDSHAKE_HEADER_SZ = 12, /* normal + seq(2) + offset(3) + length(3) */
@@ -1040,7 +1240,7 @@
     DTLS_EXPORT_PRO          = 165,/* wolfSSL protocol for serialized session */
     DTLS_EXPORT_VERSION      = 4,  /* wolfSSL version for serialized session */
-    DTLS_EXPORT_OPT_SZ       = 58, /* amount of bytes used from Options */
+    DTLS_EXPORT_OPT_SZ       = 60, /* amount of bytes used from Options */
     DTLS_EXPORT_VERSION_3    = 3,  /* wolfSSL version before TLS 1.3 addition */
-    DTLS_EXPORT_OPT_SZ_3     = 57, /* amount of bytes used from Options */
+    DTLS_EXPORT_OPT_SZ_3     = 59, /* amount of bytes used from Options */
     DTLS_EXPORT_KEY_SZ       = 325 + (DTLS_SEQ_SZ * 2),
                                    /* max amount of bytes used from Keys */
@@ -1063,16 +1263,25 @@
     MAX_HKDF_LABEL_SZ   = OPAQUE16_LEN +
                           OPAQUE8_LEN + PROTOCOL_LABEL_SZ + MAX_LABEL_SZ +
-                          OPAQUE8_LEN + MAX_DIGEST_SIZE,
+                          OPAQUE8_LEN + WC_MAX_DIGEST_SIZE,
     MAX_REQUEST_SZ      = 256, /* Maximum cert req len (no auth yet */
     SESSION_FLUSH_COUNT = 256, /* Flush session cache unless user turns off */
-
-    RC4_KEY_SIZE        = 16,  /* always 128bit           */
-    DES_KEY_SIZE        =  8,  /* des                     */
-    DES3_KEY_SIZE       = 24,  /* 3 des ede               */
-    DES_IV_SIZE         = DES_BLOCK_SIZE,
-    AES_256_KEY_SIZE    = 32,  /* for 256 bit             */
-    AES_192_KEY_SIZE    = 24,  /* for 192 bit             */
-    AES_IV_SIZE         = 16,  /* always block size       */
-    AES_128_KEY_SIZE    = 16,  /* for 128 bit             */
+    TLS_MAX_PAD_SZ      = 255, /* Max padding in TLS */
+
+#if defined(HAVE_FIPS) && \
+    (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))
+    MAX_SYM_KEY_SIZE    = AES_256_KEY_SIZE,
+#else
+    MAX_SYM_KEY_SIZE    = WC_MAX_SYM_KEY_SIZE,
+#endif
+
+#ifdef HAVE_SELFTEST
+    #define WOLFSSL_AES_KEY_SIZE_ENUM
+    AES_IV_SIZE         = 16,
+    AES_128_KEY_SIZE    = 16,
+    AES_192_KEY_SIZE    = 24,
+    AES_256_KEY_SIZE    = 32,
+#endif
+
+    MAX_IV_SZ           = AES_BLOCK_SIZE,
 
     AEAD_SEQ_OFFSET     = 4,   /* Auth Data: Sequence number */
@@ -1117,5 +1326,7 @@
     EVP_SALT_SIZE       =  8,  /* evp salt size 64 bits   */
 
+#ifndef ECDHE_SIZE /* allow this to be overriden at compile-time */
     ECDHE_SIZE          = 32,  /* ECHDE server size defaults to 256 bit */
+#endif
     MAX_EXPORT_ECC_SZ   = 256, /* Export ANS X9.62 max future size */
     MAX_CURVE_NAME_SZ   = 16,  /* Maximum size of curve name string */
@@ -1130,11 +1341,13 @@
     MIN_RSA_SHA384_PSS_BITS = 384 * 2 + 8 * 8, /* Min key size */
 
-#ifdef HAVE_QSH
-    /* qsh handshake sends 600+ size keys over hello extensions */
-    MAX_HELLO_SZ       = 2048,  /* max client or server hello */
+#ifndef NO_RSA
+    MAX_CERT_VERIFY_SZ = 4096 / 8, /* max RSA - default 4096-bits */
+#elif defined(HAVE_ECC)
+    MAX_CERT_VERIFY_SZ = ECC_MAX_SIG_SIZE, /* max ECC  */
+#elif defined(HAVE_ED25519)
+    MAX_CERT_VERIFY_SZ = ED25519_SIG_SIZE, /* max Ed25519  */
 #else
-    MAX_HELLO_SZ       = 128,  /* max client or server hello */
-#endif
-    MAX_CERT_VERIFY_SZ = 1024, /* max   */
+    MAX_CERT_VERIFY_SZ = 1024, /* max default  */
+#endif
     CLIENT_HELLO_FIRST =  35,  /* Protocol + RAN_LEN + sizeof(id_len) */
     MAX_SUITE_NAME     =  48,  /* maximum length of cipher suite string */
@@ -1159,6 +1372,4 @@
     MAX_X509_SIZE      = 2048, /* max static x509 buffer size */
     CERT_MIN_SIZE      =  256, /* min PEM cert size with header/footer */
-    FILE_BUFFER_SIZE   = 1024, /* default static file buffer size for input,
-                                  will use dynamic buffer if not big enough */
 
     MAX_NTRU_PUB_KEY_SZ = 1027, /* NTRU max for now */
@@ -1177,7 +1388,17 @@
     PREV_ORDER         = -1,   /* Sequence number is in previous epoch. */
     PEER_ORDER         = 1,    /* Peer sequence number for verify. */
-    CUR_ORDER          = 0     /* Current sequence number. */
-};
-
+    CUR_ORDER          = 0,    /* Current sequence number. */
+    WRITE_PROTO        = 1,    /* writing a protocol message */
+    READ_PROTO         = 0     /* reading a protocol message */
+};
+
+/* minimum Downgrade Minor version */
+#ifndef WOLFSSL_MIN_DOWNGRADE
+    #ifndef NO_OLD_TLS
+        #define WOLFSSL_MIN_DOWNGRADE TLSv1_MINOR
+    #else
+        #define WOLFSSL_MIN_DOWNGRADE TLSv1_2_MINOR
+    #endif
+#endif
 
 /* Set max implicit IV size for AEAD cipher suites */
@@ -1192,4 +1413,10 @@
     /* 150 suites for now! */
 #endif
+
+/* number of items in the signature algo list */
+#ifndef WOLFSSL_MAX_SIGALGO
+    #define WOLFSSL_MAX_SIGALGO 32
+#endif
+
 
 /* set minimum ECC key size allowed */
@@ -1226,21 +1453,4 @@
 #define MIN_RSAKEY_SZ (WOLFSSL_MIN_RSA_BITS / 8)
 
-/* set minimum DH key size allowed */
-#ifndef WOLFSSL_MIN_DHKEY_BITS
-    #ifdef WOLFSSL_MAX_STRENGTH
-        #define WOLFSSL_MIN_DHKEY_BITS 2048
-    #else
-        #define WOLFSSL_MIN_DHKEY_BITS 1024
-    #endif
-#endif
-#if (WOLFSSL_MIN_DHKEY_BITS % 8)
-    #error DH minimum bit size must be multiple of 8
-#endif
-#if (WOLFSSL_MIN_DHKEY_BITS > 16000)
-    #error DH minimum bit size must not be greater than 16000
-#endif
-#define MIN_DHKEY_SZ (WOLFSSL_MIN_DHKEY_BITS / 8)
-
-
 #ifdef SESSION_INDEX
 /* Shift values for making a session index */
@@ -1290,4 +1500,5 @@
 
     SERVER_HELLOVERIFYREQUEST_COMPLETE,
+    SERVER_HELLO_RETRY_REQUEST_COMPLETE,
     SERVER_HELLO_COMPLETE,
     SERVER_ENCRYPTED_EXTENSIONS_COMPLETE,
@@ -1295,20 +1506,15 @@
     SERVER_KEYEXCHANGE_COMPLETE,
     SERVER_HELLODONE_COMPLETE,
+	SERVER_CHANGECIPHERSPEC_COMPLETE,
     SERVER_FINISHED_COMPLETE,
-    SERVER_HELLO_RETRY_REQUEST,
-
+
+    CLIENT_HELLO_RETRY,
     CLIENT_HELLO_COMPLETE,
     CLIENT_KEYEXCHANGE_COMPLETE,
+	CLIENT_CHANGECIPHERSPEC_COMPLETE,
     CLIENT_FINISHED_COMPLETE,
 
     HANDSHAKE_DONE
 };
-
-
-#if defined(__GNUC__)
-    #define WOLFSSL_PACK __attribute__ ((packed))
-#else
-    #define WOLFSSL_PACK
-#endif
 
 /* SSL Version */
@@ -1339,14 +1545,4 @@
 
 
-enum BIO_TYPE {
-    BIO_BUFFER = 1,
-    BIO_SOCKET = 2,
-    BIO_SSL    = 3,
-    BIO_MEMORY = 4,
-    BIO_BIO    = 5,
-    BIO_FILE   = 6
-};
-
-
 /* wolfSSL BIO_METHOD type */
 struct WOLFSSL_BIO_METHOD {
@@ -1357,4 +1553,5 @@
 /* wolfSSL BIO type */
 struct WOLFSSL_BIO {
+    WOLFSSL_BUF_MEM* mem_buf;
     WOLFSSL*     ssl;           /* possible associated ssl */
 #ifndef NO_FILESYSTEM
@@ -1373,4 +1570,5 @@
     int         fd;            /* possible file descriptor */
     int         eof;           /* eof flag */
+    int         flags;
     byte        type;          /* method type */
     byte        close;         /* close flag */
@@ -1388,7 +1586,12 @@
 typedef WOLFSSL_BUFFER_INFO buffer;
 
+typedef struct Suites Suites;
+
 
 /* defaults to client */
 WOLFSSL_LOCAL void InitSSL_Method(WOLFSSL_METHOD*, ProtocolVersion);
+
+WOLFSSL_LOCAL int InitSSL_Suites(WOLFSSL* ssl);
+WOLFSSL_LOCAL int InitSSL_Side(WOLFSSL* ssl, word16 side);
 
 /* for sniffer */
@@ -1397,4 +1600,6 @@
 WOLFSSL_LOCAL int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx);
 /* TLS v1.3 needs these */
+WOLFSSL_LOCAL int  HandleTlsResumption(WOLFSSL* ssl, int bogusID,
+                                       Suites* clSuites);
 WOLFSSL_LOCAL int  DoClientHello(WOLFSSL* ssl, const byte* input, word32*,
                                  word32);
@@ -1405,8 +1610,15 @@
 WOLFSSL_LOCAL int  DoServerHello(WOLFSSL* ssl, const byte* input, word32*,
                                  word32);
+WOLFSSL_LOCAL int  CompleteServerHello(WOLFSSL *ssl);
 WOLFSSL_LOCAL int  CheckVersion(WOLFSSL *ssl, ProtocolVersion pv);
 WOLFSSL_LOCAL void PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo,
                                    word32 hashSigAlgoSz);
 WOLFSSL_LOCAL int  DecodePrivateKey(WOLFSSL *ssl, word16* length);
+#ifdef HAVE_PK_CALLBACKS
+WOLFSSL_LOCAL int GetPrivateKeySigSize(WOLFSSL* ssl);
+#ifndef NO_ASN
+    WOLFSSL_LOCAL int  InitSigPkCb(WOLFSSL* ssl, SignatureCtx* sigCtx);
+#endif
+#endif
 WOLFSSL_LOCAL void FreeKeyExchange(WOLFSSL* ssl);
 WOLFSSL_LOCAL int  ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, word32 size);
@@ -1420,10 +1632,10 @@
                               int ivSz);
 WOLFSSL_LOCAL int  HashInput(WOLFSSL* ssl, const byte* input, int sz);
-#if defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || defined (WOLFSSL_HAPROXY)
+#if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
 WOLFSSL_LOCAL int SNI_Callback(WOLFSSL* ssl);
 #endif
 #ifdef WOLFSSL_TLS13
 WOLFSSL_LOCAL int  DecryptTls13(WOLFSSL* ssl, byte* output, const byte* input,
-                                word16 sz);
+                                word16 sz, const byte* aad, word16 aadSz);
 WOLFSSL_LOCAL int  DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input,
                                            word32* inOutIdx, byte type,
@@ -1432,17 +1644,9 @@
                                        word32* inOutIdx, word32 totalSz);
 WOLFSSL_LOCAL int DoTls13ServerHello(WOLFSSL* ssl, const byte* input,
-                                     word32* inOutIdx, word32 helloSz);
-#endif
-
-#ifndef NO_CERTS
-    /* wolfSSL DER buffer */
-    typedef struct DerBuffer {
-        byte*  buffer;
-        void* heap;
-        word32 length;
-        int type; /* enum CertType */
-        int dynType; /* DYNAMIC_TYPE_* */
-    } DerBuffer;
-#endif /* !NO_CERTS */
+                                     word32* inOutIdx, word32 helloSz,
+                                     byte* extMsgType);
+#endif
+int TimingPadVerify(WOLFSSL* ssl, const byte* input, int padLen, int t,
+                    int pLen, int content);
 
 
@@ -1524,13 +1728,13 @@
 
 /* Cipher Suites holder */
-typedef struct Suites {
+struct Suites {
     word16 suiteSz;                 /* suite length in bytes        */
     word16 hashSigAlgoSz;           /* SigAlgo extension length in bytes */
     byte   suites[WOLFSSL_MAX_SUITE_SZ];
-    byte   hashSigAlgo[HELLO_EXT_SIGALGO_MAX]; /* sig/algo to offer */
+    byte   hashSigAlgo[WOLFSSL_MAX_SIGALGO]; /* sig/algo to offer */
     byte   setSuites;               /* user set suites from default */
     byte   hashAlgo;                /* selected hash algorithm */
     byte   sigAlgo;                 /* selected sig algorithm */
-} Suites;
+};
 
 
@@ -1548,9 +1752,18 @@
     typedef unsigned int (*wc_psk_server_callback)(WOLFSSL*, const char*,
                           unsigned char*, unsigned int);
+#ifdef WOLFSSL_TLS13
+    typedef unsigned int (*wc_psk_client_tls13_callback)(WOLFSSL*, const char*,
+                          char*, unsigned int, unsigned char*, unsigned int,
+                          const char**);
+    typedef unsigned int (*wc_psk_server_tls13_callback)(WOLFSSL*, const char*,
+                          unsigned char*, unsigned int, const char**);
+#endif
 #endif /* PSK_TYPES_DEFINED */
-#ifdef WOLFSSL_DTLS
+#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT) && \
+   !defined(WOLFSSL_DTLS_EXPORT_TYPES)
     typedef int (*wc_dtls_export)(WOLFSSL* ssl,
                    unsigned char* exportBuffer, unsigned int sz, void* userCtx);
-#endif
+#define WOLFSSL_DTLS_EXPORT_TYPES
+#endif /* WOLFSSL_DTLS_EXPORT_TYPES */
 
 
@@ -1592,5 +1805,6 @@
     OcspEntry*            ocspList;      /* OCSP response list */
     wolfSSL_Mutex         ocspLock;      /* OCSP list lock */
-#if defined(WOLFSSL_NGINX) || defined (WOLFSSL_HAPROXY)
+#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) || \
+    defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
     int(*statusCb)(WOLFSSL*, void*);
 #endif
@@ -1765,8 +1979,10 @@
  * keep as a constant size (no additional ifdefs) for session export */
 typedef struct Keys {
-    byte client_write_MAC_secret[MAX_DIGEST_SIZE];   /* max sizes */
-    byte server_write_MAC_secret[MAX_DIGEST_SIZE];
-    byte client_write_key[AES_256_KEY_SIZE];         /* max sizes */
-    byte server_write_key[AES_256_KEY_SIZE];
+#if !defined(WOLFSSL_AEAD_ONLY) || defined(WOLFSSL_TLS13)
+    byte client_write_MAC_secret[WC_MAX_DIGEST_SIZE];   /* max sizes */
+    byte server_write_MAC_secret[WC_MAX_DIGEST_SIZE];
+#endif
+    byte client_write_key[MAX_SYM_KEY_SIZE];         /* max sizes */
+    byte server_write_key[MAX_SYM_KEY_SIZE];
     byte client_write_IV[MAX_WRITE_IV_SZ];               /* max sizes */
     byte server_write_IV[MAX_WRITE_IV_SZ];
@@ -1830,5 +2046,4 @@
     TLSX_SESSION_TICKET             = 0x0023,
 #ifdef WOLFSSL_TLS13
-    TLSX_KEY_SHARE                  = 0x0028,
     #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
     TLSX_PRE_SHARED_KEY             = 0x0029,
@@ -1844,4 +2059,10 @@
     #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
     TLSX_POST_HANDSHAKE_AUTH        = 0x0031,
+    #endif
+    #if defined(WOLFSSL_TLS13_DRAFT_18) || defined(WOLFSSL_TLS13_DRAFT_22)
+    TLSX_KEY_SHARE                  = 0x0028,
+    #else
+    TLSX_SIGNATURE_ALGORITHMS_CERT  = 0x0032,
+    TLSX_KEY_SHARE                  = 0x0033,
     #endif
 #endif
@@ -1858,18 +2079,22 @@
 
 WOLFSSL_LOCAL TLSX*  TLSX_Find(TLSX* list, TLSX_Type type);
+WOLFSSL_LOCAL void  TLSX_Remove(TLSX** list, TLSX_Type type, void* heap);
 WOLFSSL_LOCAL void   TLSX_FreeAll(TLSX* list, void* heap);
 WOLFSSL_LOCAL int    TLSX_SupportExtensions(WOLFSSL* ssl);
 WOLFSSL_LOCAL int    TLSX_PopulateExtensions(WOLFSSL* ssl, byte isRequest);
 
-#ifndef NO_WOLFSSL_CLIENT
-WOLFSSL_LOCAL word16 TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType);
-WOLFSSL_LOCAL word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output,
-                                       byte msgType);
-#endif
-
-#ifndef NO_WOLFSSL_SERVER
-WOLFSSL_LOCAL word16 TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType);
-WOLFSSL_LOCAL word16 TLSX_WriteResponse(WOLFSSL* ssl, byte* output,
-                                        byte msgType);
+#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_CLIENT)
+WOLFSSL_LOCAL int   TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType, 
+                                         word16* pLength);
+WOLFSSL_LOCAL int   TLSX_WriteRequest(WOLFSSL* ssl, byte* output,
+                                       byte msgType, word16* pOffset);
+#endif
+
+#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_SERVER)
+/* TLS 1.3 Certificate messages have extensions. */
+WOLFSSL_LOCAL int   TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType, 
+                                          word16* pLength);
+WOLFSSL_LOCAL int   TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType, 
+                                        word16* pOffset);
 #endif
 
@@ -1900,7 +2125,7 @@
     union { char* host_name; } data;    /* SNI Data          */
     struct SNI*                next;    /* List Behavior     */
+    byte                       status;  /* Matching result  */
 #ifndef NO_WOLFSSL_SERVER
     byte                       options; /* Behavior options */
-    byte                       status;  /* Matching result   */
 #endif
 } SNI;
@@ -1908,11 +2133,11 @@
 WOLFSSL_LOCAL int TLSX_UseSNI(TLSX** extensions, byte type, const void* data,
                                                        word16 size, void* heap);
+WOLFSSL_LOCAL byte TLSX_SNI_Status(TLSX* extensions, byte type);
+WOLFSSL_LOCAL word16 TLSX_SNI_GetRequest(TLSX* extensions, byte type,
+                                                                   void** data);
 
 #ifndef NO_WOLFSSL_SERVER
 WOLFSSL_LOCAL void   TLSX_SNI_SetOptions(TLSX* extensions, byte type,
                                                                   byte options);
-WOLFSSL_LOCAL byte   TLSX_SNI_Status(TLSX* extensions, byte type);
-WOLFSSL_LOCAL word16 TLSX_SNI_GetRequest(TLSX* extensions, byte type,
-                                                                   void** data);
 WOLFSSL_LOCAL int    TLSX_SNI_GetFromBuffer(const byte* buffer, word32 bufferSz,
                                          byte type, byte* sni, word32* inOutSz);
@@ -1960,11 +2185,15 @@
     byte status_type;
     byte options;
+    WOLFSSL* ssl;
     union {
         OcspRequest ocsp;
     } request;
+#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER)
+    buffer response;
+#endif
 } CertificateStatusRequest;
 
 WOLFSSL_LOCAL int   TLSX_UseCertificateStatusRequest(TLSX** extensions,
-                                    byte status_type, byte options, void* heap, int devId);
+           byte status_type, byte options, WOLFSSL* ssl, void* heap, int devId);
 #ifndef NO_CERTS
 WOLFSSL_LOCAL int   TLSX_CSR_InitRequest(TLSX* extensions, DecodedCert* cert,
@@ -2023,5 +2252,8 @@
 WOLFSSL_LOCAL int TLSX_ValidateSupportedCurves(WOLFSSL* ssl, byte first,
                                                                    byte second);
-#endif
+WOLFSSL_LOCAL int TLSX_SupportedCurve_CheckPriority(WOLFSSL* ssl);
+#endif
+WOLFSSL_LOCAL int TLSX_SupportedCurve_Preferred(WOLFSSL* ssl,
+                                                            int checkSupported);
 
 #endif /* HAVE_SUPPORTED_CURVES */
@@ -2042,4 +2274,5 @@
 typedef struct SecureRenegotiation {
    byte                 enabled;  /* secure_renegotiation flag in rfc */
+   byte                 verifySet;
    byte                 startScr; /* server requested client to start scr */
    enum key_cache_state cache_status;  /* track key cache state */
@@ -2053,5 +2286,5 @@
 
 #ifdef HAVE_SERVER_RENEGOTIATION_INFO
-WOLFSSL_LOCAL int TLSX_AddEmptyRenegotiationInfo(TLSX** extensions, void* heap);
+WOLFSSL_LOCAL int TLSX_AddEmptyRenegotiationInfo(TLSX** extensions);
 #endif
 
@@ -2141,4 +2374,6 @@
     void*                 key;    /* Private key              */
     word32                keyLen; /* Private key length       */
+    byte*                 pubKey;    /* Public key               */
+    word32                pubKeyLen; /* Public key length        */
     struct KeyShareEntry* next;   /* List pointer             */
 } KeyShareEntry;
@@ -2148,7 +2383,18 @@
 WOLFSSL_LOCAL int TLSX_KeyShare_Empty(WOLFSSL* ssl);
 WOLFSSL_LOCAL int TLSX_KeyShare_Establish(WOLFSSL* ssl);
+WOLFSSL_LOCAL int TLSX_KeyShare_DeriveSecret(WOLFSSL* ssl);
 
 
 #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+#ifndef WOLFSSL_TLS13_DRAFT_18
+/* Ticket nonce - for deriving PSK.
+ * Length allowed to be: 1..255. Only support 4 bytes.
+ */
+typedef struct TicketNonce {
+    byte len;
+    byte data[MAX_TICKET_NONCE_SZ];
+} TicketNonce;
+#endif
+
 /* The PreSharedKey extension information - entry in a linked list. */
 typedef struct PreSharedKey {
@@ -2159,5 +2405,5 @@
     byte                 cipherSuite;             /* Cipher Suite       */
     word32               binderLen;               /* Length of HMAC     */
-    byte                 binder[MAX_DIGEST_SIZE]; /* HMAC of hanshake   */
+    byte                 binder[WC_MAX_DIGEST_SIZE]; /* HMAC of hanshake   */
     byte                 hmac;                    /* HMAC algorithm     */
     byte                 resumption:1;            /* Resumption PSK     */
@@ -2212,4 +2458,12 @@
 
 
+#ifdef OPENSSL_EXTRA
+enum SetCBIO {
+    WOLFSSL_CBIO_NONE = 0,
+    WOLFSSL_CBIO_RECV = 0x1,
+    WOLFSSL_CBIO_SEND = 0x2, 
+};
+#endif
+
 /* wolfSSL context type */
 struct WOLFSSL_CTX {
@@ -2232,5 +2486,6 @@
     WOLF_STACK_OF(WOLFSSL_X509_NAME)* ca_names;
     #endif
-    #if defined(WOLFSSL_NGINX) || defined (WOLFSSL_HAPROXY)
+    #if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) || \
+        defined(WOLFSSL_NGINX) || defined (WOLFSSL_HAPROXY)
     WOLF_STACK_OF(WOLFSSL_X509)* x509Chain;
     #endif
@@ -2249,25 +2504,26 @@
     Suites*     suites;           /* make dynamic, user may not need/set */
     void*       heap;             /* for user memory overrides */
-    byte        verifyPeer;
-    byte        verifyNone;
-    byte        failNoCert;
-    byte        failNoCertxPSK;   /* fail if no cert with the exception of PSK*/
-    byte        sessionCacheOff;
-    byte        sessionCacheFlushOff;
+    byte        verifyDepth;
+    byte        verifyPeer:1;
+    byte        verifyNone:1;
+    byte        failNoCert:1;
+    byte        failNoCertxPSK:1; /* fail if no cert with the exception of PSK*/
+    byte        sessionCacheOff:1;
+    byte        sessionCacheFlushOff:1;
 #ifdef HAVE_EXT_CACHE
-    byte        internalCacheOff;
-#endif
-    byte        sendVerify;       /* for client side */
-    byte        haveRSA;          /* RSA available */
-    byte        haveECC;          /* ECC available */
-    byte        haveDH;           /* server DH parms set by user */
-    byte        haveNTRU;         /* server private NTRU  key loaded */
-    byte        haveECDSAsig;     /* server cert signed w/ ECDSA */
-    byte        haveStaticECC;    /* static server ECC private key */
-    byte        partialWrite;     /* only one msg per write call */
-    byte        quietShutdown;    /* don't send close notify */
-    byte        groupMessages;    /* group handshake messages before sending */
+    byte        internalCacheOff:1;
+#endif
+    byte        sendVerify:2;     /* for client side (can not be single bit) */
+    byte        haveRSA:1;        /* RSA available */
+    byte        haveECC:1;        /* ECC available */
+    byte        haveDH:1;         /* server DH parms set by user */
+    byte        haveNTRU:1;       /* server private NTRU  key loaded */
+    byte        haveECDSAsig:1;   /* server cert signed w/ ECDSA */
+    byte        haveStaticECC:1;  /* static server ECC private key */
+    byte        partialWrite:1;   /* only one msg per write call */
+    byte        quietShutdown:1;  /* don't send close notify */
+    byte        groupMessages:1;  /* group handshake messages before sending */
     byte        minDowngrade;     /* minimum downgrade version */
-    byte        haveEMS;          /* have extended master secret extension */
+    byte        haveEMS:1;        /* have extended master secret extension */
     byte        useClientOrder:1; /* Use client's cipher preference order */
 #ifdef WOLFSSL_TLS13
@@ -2278,4 +2534,10 @@
     byte        postHandshakeAuth:1;  /* Post-handshake auth supported. */
 #endif
+#ifndef NO_DH
+    #if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \
+        !defined(HAVE_SELFTEST)
+    byte        dhKeyTested:1;   /* Set when key has been tested. */
+    #endif
+#endif
 #ifdef WOLFSSL_MULTICAST
     byte        haveMcast;        /* multicast requested */
@@ -2288,4 +2550,5 @@
 #ifndef NO_DH
     word16      minDhKeySz;       /* minimum DH key size */
+    word16      maxDhKeySz;       /* maximum DH key size */
 #endif
 #ifndef NO_RSA
@@ -2295,8 +2558,15 @@
     short       minEccKeySz;      /* minimum ECC key size */
 #endif
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+    unsigned long     mask;             /* store SSL_OP_ flags */
+#endif
 #ifdef OPENSSL_EXTRA
+    byte              sessionCtx[ID_LEN]; /* app session context ID */
     word32            disabledCurves;   /* curves disabled by user */
-    byte              verifyDepth;      /* maximum verification depth */
-    unsigned long     mask;             /* store SSL_OP_ flags */
+    const unsigned char *alpn_cli_protos;/* ALPN client protocol list */
+    unsigned int         alpn_cli_protos_len;
+    byte              sessionCtxSz;
+    byte              cbioFlag;  /* WOLFSSL_CBIO_RECV/SEND: CBIORecv/Send is set */
+    CallbackInfoState* CBIS;      /* used to get info about SSL state */
 #endif
     CallbackIORecv CBIORecv;
@@ -2304,6 +2574,6 @@
 #ifdef WOLFSSL_DTLS
     CallbackGenCookie CBIOCookie;       /* gen cookie callback */
-    wc_dtls_export    dtls_export;      /* export function for DTLS session */
 #ifdef WOLFSSL_SESSION_EXPORT
+    wc_dtls_export  dtls_export;        /* export function for DTLS session */
     CallbackGetPeer CBGetPeer;
     CallbackSetPeer CBSetPeer;
@@ -2317,4 +2587,6 @@
 #ifdef HAVE_ECC
     word16          eccTempKeySz;       /* in octets 20 - 66 */
+#endif
+#if defined(HAVE_ECC) || defined(HAVE_ED25519)
     word32          pkCurveOID;         /* curve Ecc_Sum */
 #endif
@@ -2323,6 +2595,14 @@
     wc_psk_client_callback client_psk_cb;  /* client callback */
     wc_psk_server_callback server_psk_cb;  /* server callback */
+#ifdef WOLFSSL_TLS13
+    wc_psk_client_tls13_callback client_psk_tls13_cb;  /* client callback */
+    wc_psk_server_tls13_callback server_psk_tls13_cb;  /* server callback */
+#endif
     char        server_hint[MAX_PSK_ID_LEN + NULL_TERM_LEN];
 #endif /* HAVE_SESSION_TICKET || !NO_PSK */
+#ifdef WOLFSSL_TLS13
+    word16          group[WOLFSSL_MAX_GROUP_COUNT];
+    byte            numGroups;
+#endif
 #ifdef WOLFSSL_EARLY_DATA
     word32          maxEarlyDataSz;
@@ -2331,19 +2611,24 @@
     byte        haveAnon;               /* User wants to allow Anon suites */
 #endif /* HAVE_ANON */
+#ifdef WOLFSSL_ENCRYPTED_KEYS
+    pem_password_cb* passwd_cb;
+    void*            passwd_userdata;
+#endif
 #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
-    pem_password_cb* passwd_cb;
-    void*           userdata;
     WOLFSSL_X509_STORE x509_store; /* points to ctx->cm */
+    WOLFSSL_X509_STORE* x509_store_pt; /* take ownership of external store */
     byte            readAhead;
     void*           userPRFArg; /* passed to prf callback */
-#endif /* OPENSSL_EXTRA */
+#endif
 #ifdef HAVE_EX_DATA
     void*           ex_data[MAX_EX_DATA];
 #endif
-#if defined(HAVE_ALPN) && (defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY))
+#if defined(HAVE_ALPN) && (defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY))
     CallbackALPNSelect alpnSelect;
     void*              alpnSelectArg;
 #endif
-#if defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && (defined(HAVE_STUNNEL) || \
+                             defined(WOLFSSL_NGINX) || defined(HAVE_LIGHTY) || \
+                             defined(WOLFSSL_HAPROXY)))
     CallbackSniRecv sniRecvCb;
     void*           sniRecvCbArg;
@@ -2385,4 +2670,5 @@
 #ifdef HAVE_PK_CALLBACKS
     #ifdef HAVE_ECC
+        CallbackEccKeyGen EccKeyGenCb;  /* User EccKeyGen Callback Handler */
         CallbackEccSign   EccSignCb;    /* User EccSign   Callback handler */
         CallbackEccVerify EccVerifyCb;  /* User EccVerify Callback handler */
@@ -2395,14 +2681,21 @@
         #endif
         #ifdef HAVE_CURVE25519
-            /* User EccSharedSecret Callback handler */
+            /* User X25519 KeyGen Callback Handler */
+            CallbackX25519KeyGen X25519KeyGenCb;
+            /* User X25519 SharedSecret Callback handler */
             CallbackX25519SharedSecret X25519SharedSecretCb;
         #endif
     #endif /* HAVE_ECC */
+    #ifndef NO_DH
+        CallbackDhAgree DhAgreeCb;      /* User DH Agree Callback handler */
+    #endif
     #ifndef NO_RSA
-        CallbackRsaSign   RsaSignCb;    /* User RsaSign   Callback handler */
-        CallbackRsaVerify RsaVerifyCb;  /* User RsaVerify Callback handler */
+        CallbackRsaSign   RsaSignCb;      /* User RsaSign Callback handler (priv key) */
+        CallbackRsaVerify RsaVerifyCb;    /* User RsaVerify Callback handler (pub key) */
+        CallbackRsaVerify RsaSignCheckCb; /* User VerifyRsaSign Callback handler (priv key) */
         #ifdef WC_RSA_PSS
-            CallbackRsaPssSign   RsaPssSignCb;    /* User RsaPssSign */
-            CallbackRsaPssVerify RsaPssVerifyCb;  /* User RsaPssVerify */
+            CallbackRsaPssSign   RsaPssSignCb;       /* User RsaSign (priv key) */
+            CallbackRsaPssVerify RsaPssVerifyCb;     /* User RsaVerify (pub key) */
+            CallbackRsaPssVerify RsaPssSignCheckCb; /* User VerifyRsaSign (priv key) */
         #endif
         CallbackRsaEnc    RsaEncCb;     /* User Rsa Public Encrypt  handler */
@@ -2418,6 +2711,9 @@
         void (*rem_sess_cb)(WOLFSSL_CTX*, WOLFSSL_SESSION*);
 #endif
-};
-
+#if defined(OPENSSL_EXTRA) && defined(WOLFCRYPT_HAVE_SRP) && !defined(NO_SHA256)
+        Srp*  srp;  /* TLS Secure Remote Password Protocol*/
+        byte* srp_password;
+#endif
+};
 
 WOLFSSL_LOCAL
@@ -2531,5 +2827,9 @@
 
 
+#ifndef WOLFSSL_AEAD_ONLY
 enum CipherType { stream, block, aead };
+#else
+enum CipherType { aead };
+#endif
 
 
@@ -2662,13 +2962,24 @@
     byte               serverID[SERVER_ID_LEN];   /* for easier client lookup */
 #endif
+#ifdef OPENSSL_EXTRA
+    byte               sessionCtxSz;              /* sessionCtx length        */
+    byte               sessionCtx[ID_LEN];        /* app specific context id  */
+#endif
+#ifdef WOLFSSL_TLS13
+    word16             namedGroup;
+#endif
 #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
     #ifdef WOLFSSL_TLS13
-    byte               namedGroup;
     word32             ticketSeen;                /* Time ticket seen (ms) */
     word32             ticketAdd;                 /* Added by client */
+        #ifndef WOLFSSL_TLS13_DRAFT_18
+    TicketNonce        ticketNonce;               /* Nonce used to derive PSK */
+        #endif
     #endif
     #ifdef WOLFSSL_EARLY_DATA
     word32             maxEarlyDataSz;
     #endif
+#endif
+#ifdef HAVE_SESSION_TICKET
     byte*              ticket;
     word16             ticketLen;
@@ -2690,5 +3001,5 @@
 int          SetSession(WOLFSSL*, WOLFSSL_SESSION*);
 
-typedef int (*hmacfp) (WOLFSSL*, byte*, const byte*, word32, int, int);
+typedef int (*hmacfp) (WOLFSSL*, byte*, const byte*, word32, int, int, int);
 
 #ifndef NO_CLIENT_CACHE
@@ -2731,4 +3042,23 @@
     ACCEPT_FINISHED_DONE,
     ACCEPT_THIRD_REPLY_DONE
+};
+
+/* TLS 1.3 server accept state for nonblocking restart */
+enum AcceptStateTls13 {
+    TLS13_ACCEPT_BEGIN = 0,
+    TLS13_ACCEPT_CLIENT_HELLO_DONE,
+    TLS13_ACCEPT_HELLO_RETRY_REQUEST_DONE,
+    TLS13_ACCEPT_FIRST_REPLY_DONE,
+    TLS13_ACCEPT_SECOND_REPLY_DONE,
+    TLS13_SERVER_HELLO_SENT,
+    TLS13_ACCEPT_THIRD_REPLY_DONE,
+    TLS13_SERVER_EXTENSIONS_SENT,
+    TLS13_CERT_REQ_SENT,
+    TLS13_CERT_SENT,
+    TLS13_CERT_VERIFY_SENT,
+    TLS13_ACCEPT_FINISHED_SENT,
+    TLS13_PRE_TICKET_SENT,
+    TLS13_ACCEPT_FINISHED_DONE,
+    TLS13_TICKET_SENT
 };
 
@@ -2765,4 +3095,5 @@
 #ifdef WOLFSSL_TLS13
     int             certChainCnt;
+    DerBuffer*      certExts;
 #endif
 #endif
@@ -2819,4 +3150,8 @@
     wc_psk_client_callback client_psk_cb;
     wc_psk_server_callback server_psk_cb;
+#ifdef WOLFSSL_TLS13
+    wc_psk_client_tls13_callback client_psk_tls13_cb;  /* client callback */
+    wc_psk_server_tls13_callback server_psk_tls13_cb;  /* server callback */
+#endif
 #endif /* NO_PSK */
 #ifdef OPENSSL_EXTRA
@@ -2834,5 +3169,5 @@
     word16            internalCacheOff:1;
 #endif
-    word16            side:1;             /* client or server end */
+    word16            side:2;             /* client, server or neither end */
     word16            verifyPeer:1;
     word16            verifyNone:1;
@@ -2868,5 +3203,4 @@
     word16            certOnly:1;         /* stop once we get cert */
     word16            groupMessages:1;    /* group handshake messages */
-    word16            usingNonblock:1;    /* are we using nonblocking socket */
     word16            saveArrays:1;       /* save array Memory for user get keys
                                            or psk */
@@ -2888,4 +3222,5 @@
 #endif
 #ifdef WOLFSSL_DTLS
+    word16            dtlsUseNonblock:1;  /* are we using nonblocking socket */
     word16            dtlsHsRetain:1;     /* DTLS retaining HS data */
     word16            haveMcast:1;        /* using multicast ? */
@@ -2909,5 +3244,18 @@
     word16            usingAltCertChain:1;/* Alternate cert chain was used */
 #endif
-
+#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
+    word16            sentChangeCipher:1; /* Change Cipher Spec sent */
+#endif
+#if !defined(WOLFSSL_NO_CLIENT_AUTH) && defined(HAVE_ED25519) && \
+                                                !defined(NO_ED25519_CLIENT_AUTH)
+    word16            cacheMessages:1;    /* Cache messages for sign/verify */
+#endif
+#ifndef NO_DH
+    #if !defined(WOLFSSL_OLD_PRIME_CHECK) && \
+        !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+        word16        dhDoKeyTest:1;      /* Need to do the DH Key prime test */
+        word16        dhKeyTested:1;      /* Set when key has been tested. */
+    #endif
+#endif
     /* need full byte values for this section */
     byte            processReply;           /* nonblocking resume */
@@ -2929,4 +3277,5 @@
 #ifndef NO_DH
     word16          minDhKeySz;         /* minimum DH key size */
+    word16          maxDhKeySz;         /* minimum DH key size */
     word16          dhKeySz;            /* actual DH key size */
 #endif
@@ -2941,7 +3290,10 @@
 #endif
 #ifdef WOLFSSL_EARLY_DATA
+    word16          pskIdIndex;
     word32          maxEarlyDataSz;
 #endif
-
+#ifdef WOLFSSL_TLS13
+    byte            oldMinor;          /* client preferred version < TLS 1.3 */
+#endif
 } Options;
 
@@ -2963,6 +3315,4 @@
     byte            sessionIDSz;
 #ifdef WOLFSSL_TLS13
-    byte            clientSecret[SECRET_LEN];
-    byte            serverSecret[SECRET_LEN];
     byte            secret[SECRET_LEN];
 #endif
@@ -2999,13 +3349,15 @@
 struct WOLFSSL_X509_NAME {
     char  *name;
-    char  staticName[ASN_NAME_MAX];
     int   dynamicName;
     int   sz;
-#if defined(OPENSSL_EXTRA) && !defined(NO_ASN)
+    char  staticName[ASN_NAME_MAX];
+#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \
+    !defined(NO_ASN)
     DecodedName fullName;
     WOLFSSL_X509_NAME_ENTRY cnEntry;
+    WOLFSSL_X509_NAME_ENTRY extra[MAX_NAME_ENTRIES]; /* extra entries added */
     WOLFSSL_X509*           x509;   /* x509 that struct belongs to */
 #endif /* OPENSSL_EXTRA */
-#ifdef WOLFSSL_NGINX
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX)
     byte  raw[ASN_NAME_MAX];
     int   rawLen;
@@ -3023,17 +3375,13 @@
 struct WOLFSSL_X509 {
     int              version;
-    WOLFSSL_X509_NAME issuer;
-    WOLFSSL_X509_NAME subject;
     int              serialSz;
-    byte             serial[EXTERNAL_SERIAL_SIZE];
-    char             subjectCN[ASN_NAME_MAX];        /* common name short cut */
 #ifdef WOLFSSL_SEP
     int              deviceTypeSz;
+    int              hwTypeSz;
     byte             deviceType[EXTERNAL_SERIAL_SIZE];
-    int              hwTypeSz;
     byte             hwType[EXTERNAL_SERIAL_SIZE];
     int              hwSerialNumSz;
     byte             hwSerialNum[EXTERNAL_SERIAL_SIZE];
-    #ifdef OPENSSL_EXTRA
+    #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
         byte             certPolicySet;
         byte             certPolicyCrit;
@@ -3041,12 +3389,14 @@
 #endif
     int              notBeforeSz;
+    int              notAfterSz;
     byte             notBefore[MAX_DATE_SZ];
-    int              notAfterSz;
     byte             notAfter[MAX_DATE_SZ];
+    buffer           sig;
     int              sigOID;
-    buffer           sig;
+    DNS_entry*       altNames;                       /* alt names list */
+    buffer           pubKey;
     int              pubKeyOID;
-    buffer           pubKey;
-    #ifdef HAVE_ECC
+    DNS_entry*       altNamesNext;                   /* hint for retrieval */
+    #if defined(HAVE_ECC) || defined(HAVE_ED25519)
         word32       pkCurveOID;
     #endif /* HAVE_ECC */
@@ -3054,47 +3404,54 @@
         DerBuffer*   derCert;                        /* may need  */
     #endif
-    DNS_entry*       altNames;                       /* alt names list */
-    DNS_entry*       altNamesNext;                   /* hint for retrieval */
     void*            heap;                           /* heap hint */
     byte             dynamicMemory;                  /* dynamic memory flag */
-    byte             isCa;
+    byte             isCa:1;
 #ifdef WOLFSSL_CERT_EXT
     char             certPolicies[MAX_CERTPOL_NB][MAX_CERTPOL_SZ];
     int              certPoliciesNb;
 #endif /* WOLFSSL_CERT_EXT */
-#ifdef OPENSSL_EXTRA
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
 #ifdef HAVE_EX_DATA
     void*            ex_data[MAX_EX_DATA];
 #endif
+    byte*            authKeyId;
+    byte*            subjKeyId;
+    byte*            extKeyUsageSrc;
+    const byte*      CRLInfo;
+    byte*            authInfo;
     word32           pathLength;
     word16           keyUsage;
-    byte             CRLdistSet;
-    byte             CRLdistCrit;
-    byte*            CRLInfo;
     int              CRLInfoSz;
-    byte             authInfoSet;
-    byte             authInfoCrit;
-    byte*            authInfo;
     int              authInfoSz;
-    byte             basicConstSet;
-    byte             basicConstCrit;
-    byte             basicConstPlSet;
-    byte             subjAltNameSet;
-    byte             subjAltNameCrit;
-    byte             authKeyIdSet;
-    byte             authKeyIdCrit;
-    byte*            authKeyId;
     word32           authKeyIdSz;
-    byte             subjKeyIdSet;
-    byte             subjKeyIdCrit;
-    byte*            subjKeyId;
     word32           subjKeyIdSz;
-    byte             keyUsageSet;
-    byte             keyUsageCrit;
-    byte             extKeyUsageCrit;
-    byte*            extKeyUsageSrc;
     word32           extKeyUsageSz;
     word32           extKeyUsageCount;
-#endif /* OPENSSL_EXTRA */
+
+    byte             CRLdistSet:1;
+    byte             CRLdistCrit:1;
+    byte             authInfoSet:1;
+    byte             authInfoCrit:1;
+    byte             keyUsageSet:1;
+    byte             keyUsageCrit:1;
+    byte             extKeyUsageCrit:1;
+    byte             subjKeyIdSet:1;
+
+    byte             subjKeyIdCrit:1;
+    byte             basicConstSet:1;
+    byte             basicConstCrit:1;
+    byte             basicConstPlSet:1;
+    byte             subjAltNameSet:1;
+    byte             subjAltNameCrit:1;
+    byte             authKeyIdSet:1;
+    byte             authKeyIdCrit:1;
+#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
+    byte             serial[EXTERNAL_SERIAL_SIZE];
+    char             subjectCN[ASN_NAME_MAX];        /* common name short cut */
+#ifdef WOLFSSL_CERT_REQ
+    char             challengePw[CTC_NAME_SIZE]; /* for REQ certs */
+#endif
+    WOLFSSL_X509_NAME issuer;
+    WOLFSSL_X509_NAME subject;
 };
 
@@ -3133,5 +3490,5 @@
     word32          fragSz;    /* Length of fragments received */
     word32          seq;       /* Handshake sequence number    */
-    word32          sz;        /* Length of whole mesage       */
+    word32          sz;        /* Length of whole message      */
     byte            type;
 } DtlsMsg;
@@ -3150,10 +3507,9 @@
 #endif
 
-
 /* Handshake messages received from peer (plus change cipher */
 typedef struct MsgsReceived {
     word16 got_hello_request:1;
     word16 got_client_hello:2;
-    word16 got_server_hello:1;
+    word16 got_server_hello:2;
     word16 got_hello_verify_request:1;
     word16 got_session_ticket:1;
@@ -3193,4 +3549,9 @@
     wc_Sha512       hashSha512;         /* sha512 hash of handshake msgs */
 #endif
+#if defined(HAVE_ED25519) && !defined(WOLFSSL_NO_CLIENT_AUTH)
+    byte*           messages;           /* handshake messages */
+    int             length;             /* length of handshake messages' data */
+    int             prevLen;            /* length of messages but last */
+#endif
 } HS_Hashes;
 
@@ -3232,4 +3593,13 @@
 #endif
 
+#ifdef WOLFSSL_EARLY_DATA
+typedef enum EarlyDataState {
+    no_early_data,
+    expecting_early_data,
+    process_early_data,
+    done_early_data
+} EarlyDataState;
+#endif
+
 /* wolfSSL ssl type */
 struct WOLFSSL {
@@ -3237,4 +3607,8 @@
     Suites*         suites;             /* only need during handshake */
     Arrays*         arrays;
+#ifdef WOLFSSL_TLS13
+    byte            clientSecret[SECRET_LEN];
+    byte            serverSecret[SECRET_LEN];
+#endif
     HS_Hashes*      hsHashes;
     void*           IOCB_ReadCtx;
@@ -3249,4 +3623,9 @@
     byte            dupSide;            /* write side or read side */
 #endif
+#ifdef OPENSSL_EXTRA
+    byte              cbioFlag;  /* WOLFSSL_CBIO_RECV/SEND: CBIORecv/Send is set */
+#endif
+    CallbackIORecv  CBIORecv;
+    CallbackIOSend  CBIOSend;
 #ifdef WOLFSSL_STATIC_MEMORY
     WOLFSSL_HEAP_HINT heap_hint;
@@ -3258,9 +3637,13 @@
 #ifdef WOLFSSL_ASYNC_CRYPT
     struct WOLFSSL_ASYNC async;
+#elif defined(WOLFSSL_NONBLOCK_OCSP)
+    void*           nonblockarg;        /* dynamic arg for handling non-block resume */
 #endif
     void*           hsKey;              /* Handshake key (RsaKey or ecc_key) allocated from heap */
     word32          hsType;             /* Type of Handshake key (hsKey) */
     WOLFSSL_CIPHER  cipher;
+#ifndef WOLFSSL_AEAD_ONLY
     hmacfp          hmac;
+#endif
     Ciphers         encrypt;
     Ciphers         decrypt;
@@ -3279,4 +3662,5 @@
     word32          fragOffset;         /* fragment offset */
     word16          curSize;
+    byte            verifyDepth;
     RecordLayerHeader curRL;
     MsgsReceived    msgsReceived;       /* peer messages received */
@@ -3287,12 +3671,17 @@
     Options         options;
 #ifdef OPENSSL_EXTRA
+    CallbackInfoState* CBIS;             /* used to get info about SSL state */
+    int              cbmode;             /* read or write on info callback */
+    int              cbtype;             /* event type in info callback */
     WOLFSSL_BIO*     biord;              /* socket bio read  to free/close */
     WOLFSSL_BIO*     biowr;              /* socket bio write to free/close */
+    byte             sessionCtx[ID_LEN]; /* app session context ID */
     unsigned long    peerVerifyRet;
     byte             readAhead;
+    byte             sessionCtxSz;       /* size of sessionCtx stored */
 #ifdef HAVE_PK_CALLBACKS
     void*            loggingCtx;         /* logging callback argument */
 #endif
-#endif
+#endif /* OPENSSL_EXTRA */
 #ifndef NO_RSA
     RsaKey*         peerRsaKey;
@@ -3313,6 +3702,15 @@
 #ifdef WOLFSSL_TLS13
     word16          namedGroup;
+    word16          group[WOLFSSL_MAX_GROUP_COUNT];
+    byte            numGroups;
 #endif
     byte            pssAlgo;
+#ifdef WOLFSSL_TLS13
+    #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+    word16          certHashSigAlgoSz;  /* SigAlgoCert ext length in bytes */
+    byte            certHashSigAlgo[WOLFSSL_MAX_SIGALGO]; /* cert sig/algo to
+                                                           * offer */
+    #endif /* !WOLFSSL_TLS13_DRAFT_18 && !WOLFSSL_TLS13_DRAFT_22 */
+#endif
 #ifdef HAVE_NTRU
     word16          peerNtruKeyLen;
@@ -3332,7 +3730,9 @@
     ecc_key*        peerEccKey;              /* peer's  ECDHE key */
     ecc_key*        peerEccDsaKey;           /* peer's  ECDSA key */
-    word32          pkCurveOID;              /* curve Ecc_Sum     */
     word16          eccTempKeySz;            /* in octets 20 - 66 */
     byte            peerEccDsaKeyPresent;
+#endif
+#if defined(HAVE_ECC) || defined(HAVE_ED25519)
+    word32          pkCurveOID;              /* curve Ecc_Sum     */
 #endif
 #ifdef HAVE_ED25519
@@ -3359,5 +3759,7 @@
     void*           IOCB_CookieCtx;     /* gen cookie ctx */
     word32          dtls_expected_rx;
+#ifdef WOLFSSL_SESSION_EXPORT
     wc_dtls_export  dtls_export;        /* export function for session */
+#endif
 #ifdef WOLFSSL_SCTP
     word16          dtlsMtuSz;
@@ -3372,6 +3774,12 @@
 #endif /* WOLFSSL_DTLS */
 #ifdef WOLFSSL_CALLBACKS
+    TimeoutInfo     timeoutInfo;        /* info saved during handshake */
     HandShakeInfo   handShakeInfo;      /* info saved during handshake */
-    TimeoutInfo     timeoutInfo;        /* info saved during handshake */
+#endif
+#ifdef OPENSSL_EXTRA
+    SSL_Msg_Cb      protoMsgCb;         /* inspect protocol message callback */
+    void*           protoMsgCtx;        /* user set context with msg callback */
+#endif
+#if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
     byte            hsInfoOn;           /* track handshake info        */
     byte            toInfoOn;           /* track timeout   info        */
@@ -3420,5 +3828,5 @@
     #ifdef HAVE_ALPN
         char*   alpn_client_list;  /* keep the client's list */
-        #if defined(WOLFSSL_NGINX)  || defined(WOLFSSL_HAPROXY)
+        #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX)  || defined(WOLFSSL_HAPROXY)
             CallbackALPNSelect alpnSelect;
             void*              alpnSelectArg;
@@ -3436,5 +3844,5 @@
         byte*       ocspResp;
         int         ocspRespSz;
-        #if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+        #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
             char*   url;
         #endif
@@ -3444,4 +3852,7 @@
     NetX_Ctx        nxCtx;             /* NetX IO Context */
 #endif
+#if defined(WOLFSSL_APACHE_MYNEWT) && !defined(WOLFSSL_LWIP)
+    void*           mnCtx;             /* mynewt mn_socket IO Context */
+#endif /* defined(WOLFSSL_APACHE_MYNEWT) && !defined(WOLFSSL_LWIP) */
 #ifdef SESSION_INDEX
     int sessionIndex;                  /* Session's location in the cache. */
@@ -3453,4 +3864,5 @@
 #ifdef HAVE_PK_CALLBACKS
     #ifdef HAVE_ECC
+        void* EccKeyGenCtx;              /* EccKeyGen  Callback Context */
         void* EccSignCtx;     /* Ecc Sign   Callback Context */
         void* EccVerifyCtx;   /* Ecc Verify Callback Context */
@@ -3461,7 +3873,11 @@
         #endif
         #ifdef HAVE_CURVE25519
+            void* X25519KeyGenCtx;       /* X25519 KeyGen Callback Context */
             void* X25519SharedSecretCtx; /* X25519 Pms Callback Context */
         #endif
     #endif /* HAVE_ECC */
+    #ifndef NO_DH
+        void* DhAgreeCtx; /* DH Pms Callback Context */
+    #endif /* !NO_DH */
     #ifndef NO_RSA
         void* RsaSignCtx;     /* Rsa Sign   Callback Context */
@@ -3483,5 +3899,5 @@
 #endif /* WOLFSSL_JNI */
 #ifdef WOLFSSL_EARLY_DATA
-    int earlyData;
+    EarlyDataState earlyData;
     word32 earlyDataSz;
 #endif
@@ -3498,28 +3914,6 @@
 
 
-enum {
-    IV_SZ   = 32,          /* max iv sz */
-    NAME_SZ = 80          /* max one line */
-};
-
-
-typedef struct EncryptedInfo {
-    char     name[NAME_SZ];    /* encryption name */
-    byte     iv[IV_SZ];        /* encrypted IV */
-    word32   ivSz;             /* encrypted IV size */
-    long     consumed;         /* tracks PEM bytes consumed */
-    byte     set;              /* if encryption set */
-    WOLFSSL_CTX* ctx;              /* CTX owner */
-} EncryptedInfo;
-
 
 #ifndef NO_CERTS
-
-    WOLFSSL_LOCAL int AllocDer(DerBuffer** der, word32 length, int type, void* heap);
-    WOLFSSL_LOCAL void FreeDer(DerBuffer** der);
-
-    WOLFSSL_LOCAL int PemToDer(const unsigned char* buff, long sz, int type,
-                              DerBuffer** pDer, void* heap, EncryptedInfo* info,
-                              int* eccKey);
 
     WOLFSSL_LOCAL int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff,
@@ -3537,5 +3931,5 @@
 
 
-#ifdef WOLFSSL_CALLBACKS
+#if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
     WOLFSSL_LOCAL
     void InitHandShakeInfo(HandShakeInfo*, WOLFSSL*);
@@ -3543,5 +3937,5 @@
     void FinishHandShakeInfo(HandShakeInfo*);
     WOLFSSL_LOCAL
-    void AddPacketName(const char*, HandShakeInfo*);
+    void AddPacketName(WOLFSSL* ssl, const char* name);
 
     WOLFSSL_LOCAL
@@ -3550,5 +3944,6 @@
     void FreeTimeoutInfo(TimeoutInfo*, void*);
     WOLFSSL_LOCAL
-    void AddPacketInfo(const char*, TimeoutInfo*, const byte*, int, void*);
+    void AddPacketInfo(WOLFSSL* ssl, const char* name, int type,
+                               const byte* data, int sz, int write, void* heap);
     WOLFSSL_LOCAL
     void AddLateName(const char*, TimeoutInfo*);
@@ -3630,8 +4025,20 @@
 WOLFSSL_LOCAL int SendData(WOLFSSL*, const void*, int);
 #ifdef WOLFSSL_TLS13
+#ifdef WOLFSSL_TLS13_DRAFT_18
 WOLFSSL_LOCAL int SendTls13HelloRetryRequest(WOLFSSL*);
+#else
+WOLFSSL_LOCAL int SendTls13ServerHello(WOLFSSL*, byte);
+#endif
 #endif
 WOLFSSL_LOCAL int SendCertificate(WOLFSSL*);
 WOLFSSL_LOCAL int SendCertificateRequest(WOLFSSL*);
+#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \
+ || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
+WOLFSSL_LOCAL int CreateOcspResponse(WOLFSSL*, OcspRequest**, buffer*);
+#endif
+#if defined(HAVE_SECURE_RENEGOTIATION) && \
+    defined(HAVE_SERVER_RENEGOTIATION_INFO)
+WOLFSSL_LOCAL int SendHelloRequest(WOLFSSL*);
+#endif
 WOLFSSL_LOCAL int SendCertificateStatus(WOLFSSL*);
 WOLFSSL_LOCAL int SendServerKeyExchange(WOLFSSL*);
@@ -3660,4 +4067,5 @@
 
 WOLFSSL_LOCAL int SetTicket(WOLFSSL*, const byte*, word32);
+WOLFSSL_LOCAL int wolfSSL_GetMaxRecordSize(WOLFSSL* ssl, int maxFragment);
 
 #ifndef NO_CERTS
@@ -3665,43 +4073,39 @@
         #ifdef WC_RSA_PSS
             WOLFSSL_LOCAL int CheckRsaPssPadding(const byte* plain, word32 plainSz,
-                                                 byte* out, word32 sigSz,
-                                                 enum wc_HashType hashType);
-            WOLFSSL_LOCAL int ConvertHashPss(int hashAlgo, enum wc_HashType* hashType, int* mgf);
-        #endif
-        WOLFSSL_LOCAL int VerifyRsaSign(WOLFSSL* ssl,
-                                        byte* verifySig, word32 sigSz,
-                                        const byte* plain, word32 plainSz,
-                                        int sigAlgo, int hashAlgo,
-                                        RsaKey* key);
+                byte* out, word32 sigSz, enum wc_HashType hashType);
+            WOLFSSL_LOCAL int ConvertHashPss(int hashAlgo, 
+                enum wc_HashType* hashType, int* mgf);
+        #endif
+        WOLFSSL_LOCAL int VerifyRsaSign(WOLFSSL* ssl, byte* verifySig,
+            word32 sigSz, const byte* plain, word32 plainSz, int sigAlgo,
+            int hashAlgo, RsaKey* key, DerBuffer* keyBufInfo);
         WOLFSSL_LOCAL int RsaSign(WOLFSSL* ssl, const byte* in, word32 inSz,
             byte* out, word32* outSz, int sigAlgo, int hashAlgo, RsaKey* key,
-            const byte* keyBuf, word32 keySz, void* ctx);
+            DerBuffer* keyBufInfo);
         WOLFSSL_LOCAL int RsaVerify(WOLFSSL* ssl, byte* in, word32 inSz,
             byte** out, int sigAlgo, int hashAlgo, RsaKey* key,
-            const byte* keyBuf, word32 keySz, void* ctx);
+            buffer* keyBufInfo);
         WOLFSSL_LOCAL int RsaDec(WOLFSSL* ssl, byte* in, word32 inSz, byte** out,
-            word32* outSz, RsaKey* key, const byte* keyBuf, word32 keySz, void* ctx);
+            word32* outSz, RsaKey* key, DerBuffer* keyBufInfo);
         WOLFSSL_LOCAL int RsaEnc(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out,
-            word32* outSz, RsaKey* key, const byte* keyBuf, word32 keySz, void* ctx);
+            word32* outSz, RsaKey* key, buffer* keyBufInfo);
     #endif /* !NO_RSA */
 
     #ifdef HAVE_ECC
         WOLFSSL_LOCAL int EccSign(WOLFSSL* ssl, const byte* in, word32 inSz,
-            byte* out, word32* outSz, ecc_key* key, byte* keyBuf, word32 keySz,
-            void* ctx);
+            byte* out, word32* outSz, ecc_key* key, DerBuffer* keyBufInfo);
         WOLFSSL_LOCAL int EccVerify(WOLFSSL* ssl, const byte* in, word32 inSz,
-            const byte* out, word32 outSz, ecc_key* key, byte* keyBuf, word32 keySz,
-            void* ctx);
+            const byte* out, word32 outSz, ecc_key* key, buffer* keyBufInfo);
         WOLFSSL_LOCAL int EccSharedSecret(WOLFSSL* ssl, ecc_key* priv_key,
             ecc_key* pub_key, byte* pubKeyDer, word32* pubKeySz, byte* out,
-            word32* outlen, int side, void* ctx);
+            word32* outlen, int side);
     #endif /* HAVE_ECC */
     #ifdef HAVE_ED25519
+        WOLFSSL_LOCAL int Ed25519CheckPubKey(WOLFSSL* ssl);
         WOLFSSL_LOCAL int Ed25519Sign(WOLFSSL* ssl, const byte* in, word32 inSz,
-            byte* out, word32* outSz, ed25519_key* key, byte* keyBuf,
-            word32 keySz, void* ctx);
+            byte* out, word32* outSz, ed25519_key* key, DerBuffer* keyBufInfo);
         WOLFSSL_LOCAL int Ed25519Verify(WOLFSSL* ssl, const byte* in,
             word32 inSz, const byte* msg, word32 msgSz, ed25519_key* key,
-            byte* keyBuf, word32 keySz, void* ctx);
+            buffer* keyBufInfo);
     #endif /* HAVE_ED25519 */
 
@@ -3734,6 +4138,8 @@
 #ifndef NO_TLS
     WOLFSSL_LOCAL int  MakeTlsMasterSecret(WOLFSSL*);
+#ifndef WOLFSSL_AEAD_ONLY
     WOLFSSL_LOCAL int  TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in,
-                               word32 sz, int content, int verify);
+                                word32 sz, int padSz, int content, int verify);
+#endif
 #endif
 
@@ -3788,10 +4194,21 @@
 #endif
 
-WOLFSSL_LOCAL const char* const* GetCipherNames(void);
+typedef struct CipherSuiteInfo {
+    const char* name;
+#ifndef NO_ERROR_STRINGS
+    const char* name_iana;
+#endif
+    byte cipherSuite0;
+    byte cipherSuite;
+} CipherSuiteInfo;
+
+WOLFSSL_LOCAL const CipherSuiteInfo* GetCipherNames(void);
 WOLFSSL_LOCAL int GetCipherNamesSize(void);
-WOLFSSL_LOCAL const char* GetCipherNameInternal(const char* cipherName, int cipherSuite);
+WOLFSSL_LOCAL const char* GetCipherNameInternal(const byte cipherSuite0, const byte cipherSuite);
+WOLFSSL_LOCAL const char* GetCipherNameIana(const byte cipherSuite0, const byte cipherSuite);
 WOLFSSL_LOCAL const char* wolfSSL_get_cipher_name_internal(WOLFSSL* ssl);
-WOLFSSL_LOCAL const char* wolfSSL_get_cipher_name_from_suite(
-    const unsigned char cipherSuite, const unsigned char cipherSuite0);
+WOLFSSL_LOCAL const char* wolfSSL_get_cipher_name_iana(WOLFSSL* ssl);
+WOLFSSL_LOCAL int GetCipherSuiteFromName(const char* name, byte* cipherSuite0,
+                                         byte* cipherSuite);
 
 enum encrypt_side {
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/bio.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/bio.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/bio.h	(revision 372)
@@ -1,2 +1,23 @@
+/* bio.h
+ *
+ * Copyright (C) 2006-2017 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
 /* bio.h for openssl */
 
@@ -12,5 +33,19 @@
 #endif
 
+#define BIO_FLAG_BASE64_NO_NL WOLFSSL_BIO_FLAG_BASE64_NO_NL
+#define BIO_FLAG_READ         WOLFSSL_BIO_FLAG_READ
+#define BIO_FLAG_WRITE        WOLFSSL_BIO_FLAG_WRITE
+#define BIO_FLAG_IO_SPECIAL   WOLFSSL_BIO_FLAG_IO_SPECIAL
+#define BIO_FLAG_RETRY        WOLFSSL_BIO_FLAG_RETRY
 
+#define BIO_find_type wolfSSL_BIO_find_type
+#define BIO_next      wolfSSL_BIO_next
+#define BIO_gets      wolfSSL_BIO_gets
+
+
+#define BIO_TYPE_FILE WOLFSSL_BIO_FILE
+#define BIO_TYPE_BIO  WOLFSSL_BIO_BIO
+#define BIO_TYPE_MEM  WOLFSSL_BIO_MEMORY
+#define BIO_TYPE_BASE64 WOLFSSL_BIO_BASE64
 
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/bn.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/bn.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/bn.h	(revision 372)
@@ -1,3 +1,29 @@
+/* bn.h
+ *
+ * Copyright (C) 2006-2017 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
 /* bn.h for openssl */
+
+/*!
+    \file wolfssl/openssl/bn.h
+    \brief bn.h for openssl
+*/
 
 
@@ -38,4 +64,6 @@
 WOLFSSL_API int wolfSSL_BN_mod_exp(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *a,
         const WOLFSSL_BIGNUM *p, const WOLFSSL_BIGNUM *m, WOLFSSL_BN_CTX *ctx);
+WOLFSSL_API int wolfSSL_BN_mod_mul(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *a,
+        const WOLFSSL_BIGNUM *b, const WOLFSSL_BIGNUM *m, WOLFSSL_BN_CTX *ctx);
 WOLFSSL_API const WOLFSSL_BIGNUM* wolfSSL_BN_value_one(void);
 
@@ -56,4 +84,6 @@
 WOLFSSL_API int wolfSSL_mask_bits(WOLFSSL_BIGNUM*, int n);
 
+WOLFSSL_API int wolfSSL_BN_pseudo_rand(WOLFSSL_BIGNUM*, int bits, int top,
+        int bottom);
 WOLFSSL_API int wolfSSL_BN_rand(WOLFSSL_BIGNUM*, int bits, int top, int bottom);
 WOLFSSL_API int wolfSSL_BN_is_bit_set(const WOLFSSL_BIGNUM*, int n);
@@ -71,4 +101,5 @@
 WOLFSSL_API int wolfSSL_BN_set_bit(WOLFSSL_BIGNUM*, int);
 WOLFSSL_API int wolfSSL_BN_set_word(WOLFSSL_BIGNUM*, WOLFSSL_BN_ULONG);
+WOLFSSL_API unsigned long wolfSSL_BN_get_word(const WOLFSSL_BIGNUM*);
 
 WOLFSSL_API int wolfSSL_BN_add(WOLFSSL_BIGNUM*, WOLFSSL_BIGNUM*,
@@ -80,10 +111,11 @@
                                                  WOLFSSL_BN_ULONG);
 #if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM)
-    WOLFSSL_API int wolfSSL_BN_print_fp(FILE*, const WOLFSSL_BIGNUM*);
+    WOLFSSL_API int wolfSSL_BN_print_fp(XFILE, const WOLFSSL_BIGNUM*);
 #endif
 WOLFSSL_API int wolfSSL_BN_rshift(WOLFSSL_BIGNUM*, const WOLFSSL_BIGNUM*, int);
 WOLFSSL_API WOLFSSL_BIGNUM *wolfSSL_BN_CTX_get(WOLFSSL_BN_CTX *ctx);
 WOLFSSL_API void wolfSSL_BN_CTX_start(WOLFSSL_BN_CTX *ctx);
-
+WOLFSSL_API WOLFSSL_BIGNUM *wolfSSL_BN_mod_inverse(WOLFSSL_BIGNUM*, WOLFSSL_BIGNUM*,
+                                        const WOLFSSL_BIGNUM*, WOLFSSL_BN_CTX *ctx);
 typedef WOLFSSL_BIGNUM BIGNUM;
 typedef WOLFSSL_BN_CTX BN_CTX;
@@ -112,4 +144,5 @@
 #define BN_mod       wolfSSL_BN_mod
 #define BN_mod_exp   wolfSSL_BN_mod_exp
+#define BN_mod_mul   wolfSSL_BN_mod_mul
 #define BN_sub       wolfSSL_BN_sub
 #define BN_value_one wolfSSL_BN_value_one
@@ -117,4 +150,5 @@
 #define BN_mask_bits wolfSSL_mask_bits
 
+#define BN_pseudo_rand wolfSSL_BN_pseudo_rand
 #define BN_rand       wolfSSL_BN_rand
 #define BN_is_bit_set wolfSSL_BN_is_bit_set
@@ -124,4 +158,5 @@
 #define BN_copy wolfSSL_BN_copy
 
+#define BN_get_word wolfSSL_BN_get_word
 #define BN_set_word wolfSSL_BN_set_word
 
@@ -145,4 +180,6 @@
 #define BN_CTX_start wolfSSL_BN_CTX_start
 
+#define BN_mod_inverse wolfSSL_BN_mod_inverse
+
 #ifdef __cplusplus
     }  /* extern "C" */
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/crypto.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/crypto.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/crypto.h	(revision 372)
@@ -1,2 +1,23 @@
+/* crypto.h
+ *
+ * Copyright (C) 2006-2017 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
 /* crypto.h for openSSL */
 
@@ -16,4 +37,9 @@
 WOLFSSL_API unsigned long wolfSSLeay(void);
 
+#ifdef OPENSSL_EXTRA
+WOLFSSL_API void wolfSSL_OPENSSL_free(void*);
+WOLFSSL_API void *wolfSSL_OPENSSL_malloc(size_t a);
+#endif
+
 #define CRYPTO_THREADID void
 
@@ -24,6 +50,14 @@
 #define SSLEAY_VERSION 0x0090600fL
 #define SSLEAY_VERSION_NUMBER SSLEAY_VERSION
+#define CRYPTO_lock wc_LockMutex_ex
 
-#if defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+/* this function was used to set the default malloc, free, and realloc */
+#define CRYPTO_malloc_init() /* CRYPTO_malloc_init is not needed */
+
+#define OPENSSL_free wolfSSL_OPENSSL_free
+#define OPENSSL_malloc wolfSSL_OPENSSL_malloc
+
+#if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \
+    defined(WOLFSSL_HAPROXY) || defined(OPENSSL_EXTRA)
 #define CRYPTO_set_mem_ex_functions      wolfSSL_CRYPTO_set_mem_ex_functions
 #define FIPS_mode                        wolfSSL_FIPS_mode
@@ -35,7 +69,6 @@
 #define CRYPTO_THREADID_set_numeric wolfSSL_THREADID_set_numeric
 
-#define CRYPTO_lock wc_LockMutex
-#define CRYPTO_r_lock wc_LockMutex
-#define CRYPTO_unlock wc_UnLockMutex
+#define CRYPTO_r_lock wc_LockMutex_ex
+#define CRYPTO_unlock wc_LockMutex_ex
 
 #define CRYPTO_THREAD_lock wc_LockMutex
@@ -43,8 +76,5 @@
 #define CRYPTO_THREAD_unlock wc_UnLockMutex
 
-#define OPENSSL_malloc(a)  XMALLOC(a, NULL, DYNAMIC_TYPE_OPENSSL)
-
-#endif /* HAVE_STUNNEL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */
+#endif /* OPENSSL_ALL || HAVE_STUNNEL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */
 
 #endif /* header */
-
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/des.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/des.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/des.h	(revision 372)
@@ -46,4 +46,5 @@
 typedef /* const */ WOLFSSL_DES_cblock WOLFSSL_const_DES_cblock;
 typedef WOLFSSL_DES_cblock WOLFSSL_DES_key_schedule;
+typedef unsigned int WOLFSSL_DES_LONG;
 
 
@@ -54,4 +55,8 @@
 
 
+WOLFSSL_API int wolfSSL_DES_is_weak_key(WOLFSSL_const_DES_cblock* key);
+WOLFSSL_API WOLFSSL_DES_LONG wolfSSL_DES_cbc_cksum(const unsigned char* in,
+            WOLFSSL_DES_cblock* out, long length, WOLFSSL_DES_key_schedule* sc,
+            WOLFSSL_const_DES_cblock* iv);
 WOLFSSL_API int wolfSSL_DES_set_key(WOLFSSL_const_DES_cblock* myDes,
                                                WOLFSSL_DES_key_schedule* key);
@@ -85,6 +90,8 @@
 typedef WOLFSSL_const_DES_cblock const_DES_cblock;
 typedef WOLFSSL_DES_key_schedule DES_key_schedule;
+typedef WOLFSSL_DES_LONG DES_LONG;
 
 #define DES_check_key(x) /* Define WOLFSSL_CHECK_DESKEY to check key */
+#define DES_is_weak_key       wolfSSL_DES_is_weak_key
 #define DES_set_key           wolfSSL_DES_set_key
 #define DES_set_key_checked   wolfSSL_DES_set_key_checked
@@ -96,4 +103,5 @@
 #define DES_ecb_encrypt       wolfSSL_DES_ecb_encrypt
 #define DES_ede3_cbc_encrypt  wolfSSL_DES_ede3_cbc_encrypt
+#define DES_cbc_cksum         wolfSSL_DES_cbc_cksum
 
 #ifdef __cplusplus
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/dh.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/dh.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/dh.h	(revision 372)
@@ -1,2 +1,23 @@
+/* dh.h
+ *
+ * Copyright (C) 2006-2017 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
 /* dh.h for openSSL */
 
@@ -44,4 +65,5 @@
 #define DH_generate_key wolfSSL_DH_generate_key
 #define DH_compute_key  wolfSSL_DH_compute_key
+#define get_rfc3526_prime_1536 wolfSSL_DH_1536_prime
 
 
@@ -50,7 +72,8 @@
 #endif
 
-#ifdef HAVE_STUNNEL
+#if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL)
 #define DH_generate_parameters    wolfSSL_DH_generate_parameters
 #define DH_generate_parameters_ex wolfSSL_DH_generate_parameters_ex
-#endif /* HAVE_STUNNEL */
-#endif /* header */
+#endif /* OPENSSL_ALL || HAVE_STUNNEL */
+
+#endif /* WOLFSSL_DH_H_ */
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/dsa.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/dsa.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/dsa.h	(revision 372)
@@ -1,2 +1,23 @@
+/* dsa.h
+ *
+ * Copyright (C) 2006-2017 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
 /* dsa.h for openSSL */
 
@@ -34,4 +55,9 @@
 
 WOLFSSL_API int wolfSSL_DSA_generate_key(WOLFSSL_DSA*);
+
+typedef void (*WOLFSSL_BN_CB)(int i, int j, void* exArg);
+WOLFSSL_API WOLFSSL_DSA* wolfSSL_DSA_generate_parameters(int bits,
+                   unsigned char* seed, int seedLen, int* counterRet,
+                   unsigned long* hRet, WOLFSSL_BN_CB cb, void* CBArg);
 WOLFSSL_API int wolfSSL_DSA_generate_parameters_ex(WOLFSSL_DSA*, int bits,
                    unsigned char* seed, int seedLen, int* counterRet,
@@ -51,4 +77,5 @@
 
 #define DSA_generate_key           wolfSSL_DSA_generate_key
+#define DSA_generate_parameters    wolfSSL_DSA_generate_parameters
 #define DSA_generate_parameters_ex wolfSSL_DSA_generate_parameters_ex
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ec.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ec.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ec.h	(revision 372)
@@ -1,2 +1,23 @@
+/* ec.h
+ *
+ * Copyright (C) 2006-2017 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
 /* ec.h for openssl */
 
@@ -13,4 +34,5 @@
 /* Map OpenSSL NID value */
 enum {
+    POINT_CONVERSION_COMPRESSED = 2,
     POINT_CONVERSION_UNCOMPRESSED = 4,
 
@@ -81,4 +103,8 @@
 };
 
+
+#define WOLFSSL_EC_KEY_LOAD_PRIVATE 1
+#define WOLFSSL_EC_KEY_LOAD_PUBLIC  2
+
 WOLFSSL_API
 int wolfSSL_ECPoint_i2d(const WOLFSSL_EC_GROUP *curve,
@@ -92,4 +118,7 @@
                            const unsigned char* der, int derSz);
 WOLFSSL_API
+int wolfSSL_EC_KEY_LoadDer_ex(WOLFSSL_EC_KEY* key,
+                              const unsigned char* der, int derSz, int opt);
+WOLFSSL_API
 void wolfSSL_EC_KEY_free(WOLFSSL_EC_KEY *key);
 WOLFSSL_API
@@ -131,8 +160,4 @@
 WOLFSSL_API
 void wolfSSL_EC_GROUP_free(WOLFSSL_EC_GROUP *group);
-#if defined(DEBUG_WOLFSSL) && !defined(NO_FILESYSTEM)
-WOLFSSL_API
-void wolfssl_EC_POINT_dump(const char *msg, const WOLFSSL_EC_POINT *p);
-#endif
 WOLFSSL_API
 WOLFSSL_EC_POINT *wolfSSL_EC_POINT_new(const WOLFSSL_EC_GROUP *group);
@@ -160,4 +185,12 @@
                                     const WOLFSSL_EC_POINT *a);
 
+#ifndef HAVE_SELFTEST
+WOLFSSL_API
+char* wolfSSL_EC_POINT_point2hex(const WOLFSSL_EC_GROUP* group,
+                                 const WOLFSSL_EC_POINT* point, int form,
+                                 WOLFSSL_BN_CTX* ctx);
+#endif
+
+#define EC_KEY_new                      wolfSSL_EC_KEY_new
 #define EC_KEY_free wolfSSL_EC_KEY_free
 #define EC_KEY_get0_public_key wolfSSL_EC_KEY_get0_public_key
@@ -170,6 +203,6 @@
 #define EC_KEY_set_asn1_flag wolfSSL_EC_KEY_set_asn1_flag
 #define EC_KEY_set_public_key wolfSSL_EC_KEY_set_public_key
-#define EC_KEY_new wolfSSL_EC_KEY_new
-
+
+#define EC_GROUP_free                   wolfSSL_EC_GROUP_free
 #define EC_GROUP_set_asn1_flag wolfSSL_EC_GROUP_set_asn1_flag
 #define EC_GROUP_new_by_curve_name wolfSSL_EC_GROUP_new_by_curve_name
@@ -178,7 +211,7 @@
 #define EC_GROUP_get_degree wolfSSL_EC_GROUP_get_degree
 #define EC_GROUP_get_order wolfSSL_EC_GROUP_get_order
-#define EC_GROUP_free wolfSSL_EC_GROUP_free
 
 #define EC_POINT_new wolfSSL_EC_POINT_new
+#define EC_POINT_free                   wolfSSL_EC_POINT_free
 #define EC_POINT_get_affine_coordinates_GFp \
             wolfSSL_EC_POINT_get_affine_coordinates_GFp
@@ -186,6 +219,11 @@
 #define EC_POINT_clear_free wolfSSL_EC_POINT_clear_free
 #define EC_POINT_cmp wolfSSL_EC_POINT_cmp
-#define EC_POINT_free wolfSSL_EC_POINT_free
 #define EC_POINT_is_at_infinity wolfSSL_EC_POINT_is_at_infinity
+
+#ifndef HAVE_SELFTEST
+    #define EC_POINT_point2hex          wolfSSL_EC_POINT_point2hex
+#endif
+
+#define EC_POINT_dump                   wolfSSL_EC_POINT_dump
 
 #ifdef __cplusplus
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ec25519.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ec25519.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ec25519.h	(revision 372)
@@ -1,2 +1,23 @@
+/* ec25519.h
+ *
+ * Copyright (C) 2006-2017 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
 /* ec25519.h */
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ecdh.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ecdh.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ecdh.h	(revision 372)
@@ -1,2 +1,23 @@
+/* ecdh.h
+ *
+ * Copyright (C) 2006-2017 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
 /* ecdh.h for openssl */
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ecdsa.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ecdsa.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ecdsa.h	(revision 372)
@@ -1,2 +1,23 @@
+/* ecdsa.h
+ *
+ * Copyright (C) 2006-2017 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
 /* ecdsa.h for openssl */
 
@@ -33,8 +54,16 @@
                                         WOLFSSL_EC_KEY *eckey);
 
+WOLFSSL_API WOLFSSL_ECDSA_SIG *wolfSSL_d2i_ECDSA_SIG(WOLFSSL_ECDSA_SIG **sig,
+                                                     const unsigned char **pp,
+                                                     long len);
+WOLFSSL_API int wolfSSL_i2d_ECDSA_SIG(const WOLFSSL_ECDSA_SIG *sig,
+                                      unsigned char **pp);
+
 #define ECDSA_SIG_free wolfSSL_ECDSA_SIG_free
 #define ECDSA_SIG_new wolfSSL_ECDSA_SIG_new
 #define ECDSA_do_sign wolfSSL_ECDSA_do_sign
 #define ECDSA_do_verify wolfSSL_ECDSA_do_verify
+#define d2i_ECDSA_SIG          wolfSSL_d2i_ECDSA_SIG
+#define i2d_ECDSA_SIG          wolfSSL_i2d_ECDSA_SIG
 
 #ifdef __cplusplus
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ed25519.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ed25519.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ed25519.h	(revision 372)
@@ -1,2 +1,23 @@
+/* ed25519.h
+ *
+ * Copyright (C) 2006-2017 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
 /* ed25519.h */
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/err.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/err.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/err.h	(revision 372)
@@ -1,3 +1,32 @@
+/* err.h
+ *
+ * Copyright (C) 2006-2017 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
+#ifndef WOLFSSL_OPENSSL_ERR_
+#define WOLFSSL_OPENSSL_ERR_
+
+#include <wolfssl/openssl/ssl.h>
+
 /* err.h for openssl */
 #define ERR_load_crypto_strings          wolfSSL_ERR_load_crypto_strings
 #define ERR_peek_last_error              wolfSSL_ERR_peek_last_error
+
+#endif /* WOLFSSL_OPENSSL_ERR_ */
+
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/evp.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/evp.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/evp.h	(revision 372)
@@ -22,6 +22,7 @@
 
 
-/*  evp.h defines mini evp openssl compatibility layer
- *
+/*!
+    \file wolfssl/openssl/evp.h
+    \brief evp.h defines mini evp openssl compatibility layer
  */
 
@@ -36,4 +37,7 @@
 #endif
 
+#ifndef NO_MD4
+    #include <wolfssl/openssl/md4.h>
+#endif
 #ifndef NO_MD5
     #include <wolfssl/openssl/md5.h>
@@ -52,4 +56,5 @@
     #include <wolfssl/wolfcrypt/idea.h>
 #endif
+#include <wolfssl/wolfcrypt/pwdbased.h>
 
 #ifdef __cplusplus
@@ -57,7 +62,18 @@
 #endif
 
+
 typedef char WOLFSSL_EVP_CIPHER;
+#ifndef WOLFSSL_EVP_TYPE_DEFINED /* guard on redeclaration */
 typedef char WOLFSSL_EVP_MD;
-
+typedef struct WOLFSSL_EVP_PKEY WOLFSSL_EVP_PKEY;
+#define WOLFSSL_EVP_TYPE_DEFINED
+#endif
+
+typedef WOLFSSL_EVP_PKEY       EVP_PKEY;
+typedef WOLFSSL_EVP_PKEY       PKCS8_PRIV_KEY_INFO;
+
+#ifndef NO_MD4
+    WOLFSSL_API const WOLFSSL_EVP_MD* wolfSSL_EVP_md4(void);
+#endif
 #ifndef NO_MD5
     WOLFSSL_API const WOLFSSL_EVP_MD* wolfSSL_EVP_md5(void);
@@ -74,6 +90,8 @@
 WOLFSSL_API const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_aes_256_ecb(void);
 WOLFSSL_API const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_aes_128_cbc(void);
+#if !defined(NO_AES) && defined(HAVE_AES_CBC)
 WOLFSSL_API const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_aes_192_cbc(void);
 WOLFSSL_API const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_aes_256_cbc(void);
+#endif
 WOLFSSL_API const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_aes_128_ctr(void);
 WOLFSSL_API const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_aes_192_ctr(void);
@@ -89,4 +107,7 @@
 
 typedef union {
+    #ifndef NO_MD4
+        WOLFSSL_MD4_CTX    md4;
+    #endif
     #ifndef NO_MD5
         WOLFSSL_MD5_CTX    md5;
@@ -108,4 +129,5 @@
 } WOLFSSL_Hasher;
 
+typedef struct WOLFSSL_EVP_PKEY_CTX WOLFSSL_EVP_PKEY_CTX;
 
 typedef struct WOLFSSL_EVP_MD_CTX {
@@ -115,4 +137,5 @@
     } hash;
     unsigned char macType;
+    WOLFSSL_EVP_PKEY_CTX *pctx;
 } WOLFSSL_EVP_MD_CTX;
 
@@ -152,7 +175,10 @@
     EVP_PKEY_DSA      = 17,
     EVP_PKEY_EC       = 18,
+#ifdef HAVE_IDEA
     IDEA_CBC_TYPE     = 19,
+#endif
     NID_sha1          = 64,
-    NID_md2           = 3,
+    NID_sha224        = 65,
+    NID_md2           = 77,
     NID_md5           =  4,
     NID_hmac          = 855,
@@ -198,26 +224,16 @@
 } WOLFSSL_EVP_CIPHER_CTX;
 
-
-#ifndef WOLFSSL_EVP_PKEY_TYPE_DEFINED /* guard on redeclaration */
-typedef struct WOLFSSL_EVP_PKEY     WOLFSSL_EVP_PKEY;
-#define WOLFSSL_EVP_PKEY_TYPE_DEFINED
-#endif
-
-struct WOLFSSL_EVP_PKEY {
-    int type;         /* openssh dereference */
-    int save_type;    /* openssh dereference */
-    int pkey_sz;
-    union {
-        char* ptr; /* der format of key / or raw for NTRU */
-    } pkey;
-    #ifdef HAVE_ECC
-        int pkey_curve;
-    #endif
+struct  WOLFSSL_EVP_PKEY_CTX {
+    WOLFSSL_EVP_PKEY *pkey;
+    int op; /* operation */
+    int padding;
 };
 
 typedef int WOLFSSL_ENGINE  ;
 typedef WOLFSSL_ENGINE ENGINE;
-typedef int WOLFSSL_EVP_PKEY_CTX;
 typedef WOLFSSL_EVP_PKEY_CTX EVP_PKEY_CTX;
+
+#define EVP_PKEY_OP_ENCRYPT (1 << 6)
+#define EVP_PKEY_OP_DECRYPT (1 << 7)
 
 WOLFSSL_API void wolfSSL_EVP_init(void);
@@ -229,4 +245,7 @@
 WOLFSSL_API void wolfSSL_EVP_MD_CTX_init(WOLFSSL_EVP_MD_CTX* ctx);
 WOLFSSL_API int  wolfSSL_EVP_MD_CTX_cleanup(WOLFSSL_EVP_MD_CTX* ctx);
+WOLFSSL_API int  wolfSSL_EVP_MD_CTX_copy(WOLFSSL_EVP_MD_CTX *out, const WOLFSSL_EVP_MD_CTX *in);
+WOLFSSL_API int  wolfSSL_EVP_MD_CTX_copy_ex(WOLFSSL_EVP_MD_CTX *out, const WOLFSSL_EVP_MD_CTX *in);
+WOLFSSL_API int  wolfSSL_EVP_MD_CTX_type(const WOLFSSL_EVP_MD_CTX *ctx);
 WOLFSSL_API const WOLFSSL_EVP_MD *wolfSSL_EVP_MD_CTX_md(const WOLFSSL_EVP_MD_CTX *ctx);
 WOLFSSL_API const WOLFSSL_EVP_CIPHER *wolfSSL_EVP_get_cipherbyname(const char *name);
@@ -239,5 +258,5 @@
                                      WOLFSSL_ENGINE *impl);
 WOLFSSL_API int wolfSSL_EVP_DigestUpdate(WOLFSSL_EVP_MD_CTX* ctx, const void* data,
-                                       unsigned long sz);
+                                       size_t sz);
 WOLFSSL_API int wolfSSL_EVP_DigestFinal(WOLFSSL_EVP_MD_CTX* ctx, unsigned char* md,
                                       unsigned int* s);
@@ -255,10 +274,20 @@
                                             unsigned char *sig, size_t *siglen);
 
-#ifndef NO_MD5
+WOLFSSL_API int wolfSSL_EVP_DigestVerifyInit(WOLFSSL_EVP_MD_CTX *ctx,
+                                             WOLFSSL_EVP_PKEY_CTX **pctx,
+                                             const WOLFSSL_EVP_MD *type,
+                                             WOLFSSL_ENGINE *e,
+                                             WOLFSSL_EVP_PKEY *pkey);
+WOLFSSL_API int wolfSSL_EVP_DigestVerifyUpdate(WOLFSSL_EVP_MD_CTX *ctx,
+                                               const void *d, size_t cnt);
+WOLFSSL_API int wolfSSL_EVP_DigestVerifyFinal(WOLFSSL_EVP_MD_CTX *ctx,
+                                              const unsigned char *sig,
+                                              size_t siglen);
+
+
 WOLFSSL_API int wolfSSL_EVP_BytesToKey(const WOLFSSL_EVP_CIPHER*,
                               const WOLFSSL_EVP_MD*, const unsigned char*,
                               const unsigned char*, int, int, unsigned char*,
                               unsigned char*);
-#endif
 
 WOLFSSL_API void wolfSSL_EVP_CIPHER_CTX_init(WOLFSSL_EVP_CIPHER_CTX* ctx);
@@ -267,29 +296,36 @@
 WOLFSSL_API int  wolfSSL_EVP_CIPHER_CTX_iv_length(const WOLFSSL_EVP_CIPHER_CTX*);
 WOLFSSL_API int  wolfSSL_EVP_CIPHER_iv_length(const WOLFSSL_EVP_CIPHER*);
+WOLFSSL_API int wolfSSL_EVP_Cipher_key_length(const WOLFSSL_EVP_CIPHER* c);
 
 
 WOLFSSL_API int  wolfSSL_EVP_CipherInit(WOLFSSL_EVP_CIPHER_CTX* ctx,
                                     const WOLFSSL_EVP_CIPHER* type,
-                                    unsigned char* key, unsigned char* iv,
+                                    const unsigned char* key,
+                                    const unsigned char* iv,
                                     int enc);
 WOLFSSL_API int  wolfSSL_EVP_CipherInit_ex(WOLFSSL_EVP_CIPHER_CTX* ctx,
                                     const WOLFSSL_EVP_CIPHER* type,
                                     WOLFSSL_ENGINE *impl,
-                                    unsigned char* key, unsigned char* iv,
+                                    const unsigned char* key,
+                                    const unsigned char* iv,
                                     int enc);
 WOLFSSL_API int  wolfSSL_EVP_EncryptInit(WOLFSSL_EVP_CIPHER_CTX* ctx,
                                     const WOLFSSL_EVP_CIPHER* type,
-                                    unsigned char* key, unsigned char* iv);
+                                    const unsigned char* key,
+                                    const unsigned char* iv);
 WOLFSSL_API int  wolfSSL_EVP_EncryptInit_ex(WOLFSSL_EVP_CIPHER_CTX* ctx,
                                     const WOLFSSL_EVP_CIPHER* type,
                                     WOLFSSL_ENGINE *impl,
-                                    unsigned char* key, unsigned char* iv);
+                                    const unsigned char* key,
+                                    const unsigned char* iv);
 WOLFSSL_API int  wolfSSL_EVP_DecryptInit(WOLFSSL_EVP_CIPHER_CTX* ctx,
                                     const WOLFSSL_EVP_CIPHER* type,
-                                    unsigned char* key, unsigned char* iv);
+                                    const unsigned char* key,
+                                    const unsigned char* iv);
 WOLFSSL_API int  wolfSSL_EVP_DecryptInit_ex(WOLFSSL_EVP_CIPHER_CTX* ctx,
                                     const WOLFSSL_EVP_CIPHER* type,
                                     WOLFSSL_ENGINE *impl,
-                                    unsigned char* key, unsigned char* iv);
+                                    const unsigned char* key,
+                                    const unsigned char* iv);
 WOLFSSL_API int wolfSSL_EVP_CipherUpdate(WOLFSSL_EVP_CIPHER_CTX *ctx,
                                    unsigned char *out, int *outl,
@@ -320,7 +356,12 @@
 WOLFSSL_API const WOLFSSL_EVP_MD* wolfSSL_EVP_get_digestbynid(int);
 
+WOLFSSL_API int wolfSSL_EVP_PKEY_assign_RSA(WOLFSSL_EVP_PKEY* pkey,
+                                            WOLFSSL_RSA* key);
+WOLFSSL_API int wolfSSL_EVP_PKEY_assign_EC_KEY(WOLFSSL_EVP_PKEY* pkey,
+                                               WOLFSSL_EC_KEY* key);
 WOLFSSL_API WOLFSSL_RSA* wolfSSL_EVP_PKEY_get1_RSA(WOLFSSL_EVP_PKEY*);
 WOLFSSL_API WOLFSSL_DSA* wolfSSL_EVP_PKEY_get1_DSA(WOLFSSL_EVP_PKEY*);
 WOLFSSL_API WOLFSSL_EC_KEY *wolfSSL_EVP_PKEY_get1_EC_KEY(WOLFSSL_EVP_PKEY *key);
+WOLFSSL_API int wolfSSL_EVP_PKEY_set1_RSA(WOLFSSL_EVP_PKEY *pkey, WOLFSSL_RSA *key);
 
 WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_EVP_PKEY_new_mac_key(int type, ENGINE* e,
@@ -328,4 +369,31 @@
 WOLFSSL_API const unsigned char* wolfSSL_EVP_PKEY_get0_hmac(const WOLFSSL_EVP_PKEY* pkey,
         size_t* len);
+WOLFSSL_API int wolfSSL_EVP_PKEY_bits(const WOLFSSL_EVP_PKEY *pkey);
+WOLFSSL_API int wolfSSL_EVP_PKEY_CTX_free(WOLFSSL_EVP_PKEY_CTX *ctx);
+WOLFSSL_API WOLFSSL_EVP_PKEY_CTX *wolfSSL_EVP_PKEY_CTX_new(WOLFSSL_EVP_PKEY *pkey, WOLFSSL_ENGINE *e);
+WOLFSSL_API int wolfSSL_EVP_PKEY_CTX_set_rsa_padding(WOLFSSL_EVP_PKEY_CTX *ctx, int padding);
+WOLFSSL_API int wolfSSL_EVP_PKEY_decrypt(WOLFSSL_EVP_PKEY_CTX *ctx,
+                     unsigned char *out, size_t *outlen,
+                     const unsigned char *in, size_t inlen);
+WOLFSSL_API int wolfSSL_EVP_PKEY_decrypt_init(WOLFSSL_EVP_PKEY_CTX *ctx);
+WOLFSSL_API int wolfSSL_EVP_PKEY_encrypt(WOLFSSL_EVP_PKEY_CTX *ctx,
+                     unsigned char *out, size_t *outlen,
+                     const unsigned char *in, size_t inlen);
+WOLFSSL_API int wolfSSL_EVP_PKEY_encrypt_init(WOLFSSL_EVP_PKEY_CTX *ctx);
+WOLFSSL_API WOLFSSL_EVP_PKEY *wolfSSL_EVP_PKEY_new(void);
+WOLFSSL_API void wolfSSL_EVP_PKEY_free(WOLFSSL_EVP_PKEY*);
+WOLFSSL_API int wolfSSL_EVP_PKEY_size(WOLFSSL_EVP_PKEY *pkey);
+WOLFSSL_API int wolfSSL_EVP_PKEY_type(int type);
+WOLFSSL_API int wolfSSL_EVP_PKEY_id(const EVP_PKEY *pkey);
+WOLFSSL_API int wolfSSL_EVP_PKEY_base_id(const EVP_PKEY *pkey);
+WOLFSSL_API int wolfSSL_EVP_SignFinal(WOLFSSL_EVP_MD_CTX *ctx, unsigned char *sigret,
+                  unsigned int *siglen, WOLFSSL_EVP_PKEY *pkey);
+WOLFSSL_API int wolfSSL_EVP_SignInit(WOLFSSL_EVP_MD_CTX *ctx, const WOLFSSL_EVP_MD *type);
+WOLFSSL_API int wolfSSL_EVP_SignUpdate(WOLFSSL_EVP_MD_CTX *ctx, const void *data, size_t len);
+WOLFSSL_API int wolfSSL_EVP_VerifyFinal(WOLFSSL_EVP_MD_CTX *ctx,
+        unsigned char* sig, unsigned int sig_len, WOLFSSL_EVP_PKEY *pkey);
+WOLFSSL_API int wolfSSL_EVP_VerifyInit(WOLFSSL_EVP_MD_CTX *ctx, const WOLFSSL_EVP_MD *type);
+WOLFSSL_API int wolfSSL_EVP_VerifyUpdate(WOLFSSL_EVP_MD_CTX *ctx, const void *data, size_t len);
+
 
 /* these next ones don't need real OpenSSL type, for OpenSSH compat only */
@@ -347,8 +415,17 @@
 WOLFSSL_API unsigned long wolfSSL_EVP_CIPHER_flags(const WOLFSSL_EVP_CIPHER *cipher);
 WOLFSSL_API void wolfSSL_EVP_CIPHER_CTX_set_flags(WOLFSSL_EVP_CIPHER_CTX *ctx, int flags);
+WOLFSSL_API void wolfSSL_EVP_CIPHER_CTX_clear_flags(WOLFSSL_EVP_CIPHER_CTX *ctx, int flags);
 WOLFSSL_API unsigned long wolfSSL_EVP_CIPHER_CTX_mode(const WOLFSSL_EVP_CIPHER_CTX *ctx);
 WOLFSSL_API int  wolfSSL_EVP_CIPHER_CTX_set_padding(WOLFSSL_EVP_CIPHER_CTX *c, int pad);
 WOLFSSL_API int  wolfSSL_EVP_add_digest(const WOLFSSL_EVP_MD *digest);
 WOLFSSL_API int  wolfSSL_EVP_add_cipher(const WOLFSSL_EVP_CIPHER *cipher);
+WOLFSSL_API void wolfSSL_EVP_cleanup(void);
+WOLFSSL_API int  wolfSSL_add_all_algorithms(void);
+WOLFSSL_API int  wolfSSL_OpenSSL_add_all_algorithms_noconf(void);
+
+WOLFSSL_API int wolfSSL_PKCS5_PBKDF2_HMAC_SHA1(const char * pass, int passlen,
+                                               const unsigned char * salt,
+                                               int saltlen, int iter,
+                                               int keylen, unsigned char *out);
 
 #define EVP_CIPH_STREAM_CIPHER WOLFSSL_EVP_CIPH_STREAM_CIPHER
@@ -371,4 +448,5 @@
 #define WOLFSSL_EVP_CIPH_CCM_MODE           0x7
 #define WOLFSSL_EVP_CIPH_NO_PADDING       0x100
+#define WOLFSSL_EVP_CIPH_TYPE_INIT         0xff
 
 /* end OpenSSH compat */
@@ -379,8 +457,12 @@
 typedef WOLFSSL_EVP_CIPHER_CTX EVP_CIPHER_CTX;
 
+#ifndef NO_MD4
+    #define EVP_md4       wolfSSL_EVP_md4
+#endif
 #ifndef NO_MD5
     #define EVP_md5       wolfSSL_EVP_md5
 #endif
 #define EVP_sha1      wolfSSL_EVP_sha1
+#define EVP_dds1      wolfSSL_EVP_sha1
 #define EVP_sha224    wolfSSL_EVP_sha224
 #define EVP_sha256    wolfSSL_EVP_sha256
@@ -414,5 +496,5 @@
 #define EVP_MD_CTX_cleanup wolfSSL_EVP_MD_CTX_cleanup
 #define EVP_MD_CTX_md      wolfSSL_EVP_MD_CTX_md
-#define EVP_MD_CTX_type    wolfSSL_EVP_MD_type
+#define EVP_MD_CTX_type    wolfSSL_EVP_MD_CTX_type
 #define EVP_MD_type        wolfSSL_EVP_MD_type
 
@@ -425,4 +507,7 @@
 #define EVP_DigestSignUpdate wolfSSL_EVP_DigestSignUpdate
 #define EVP_DigestSignFinal  wolfSSL_EVP_DigestSignFinal
+#define EVP_DigestVerifyInit   wolfSSL_EVP_DigestVerifyInit
+#define EVP_DigestVerifyUpdate wolfSSL_EVP_DigestVerifyUpdate
+#define EVP_DigestVerifyFinal  wolfSSL_EVP_DigestVerifyFinal
 #define EVP_BytesToKey     wolfSSL_EVP_BytesToKey
 
@@ -438,4 +523,5 @@
 
 #define EVP_CIPHER_iv_length          wolfSSL_EVP_CIPHER_iv_length
+#define EVP_CIPHER_key_length         wolfSSL_EVP_Cipher_key_length
 
 #define EVP_CipherInit                wolfSSL_EVP_CipherInit
@@ -465,9 +551,35 @@
 #define EVP_get_digestbyname          wolfSSL_EVP_get_digestbyname
 
+#define EVP_PKEY_asign_RSA             wolfSSL_EVP_PKEY_assign_RSA
+#define EVP_PKEY_asign_EC_KEY          wolfSSL_EVP_PKEY_assign_EC_KEY
+#define EVP_PKEY_get1_DSA              wolfSSL_EVP_PKEY_get1_DSA
 #define EVP_PKEY_get1_RSA   wolfSSL_EVP_PKEY_get1_RSA
 #define EVP_PKEY_get1_DSA   wolfSSL_EVP_PKEY_get1_DSA
+#define EVP_PKEY_set1_RSA              wolfSSL_EVP_PKEY_set1_RSA
 #define EVP_PKEY_get1_EC_KEY wolfSSL_EVP_PKEY_get1_EC_KEY
 #define EVP_PKEY_get0_hmac  wolfSSL_EVP_PKEY_get0_hmac
 #define EVP_PKEY_new_mac_key       wolfSSL_EVP_PKEY_new_mac_key
+#define EVP_MD_CTX_copy                wolfSSL_EVP_MD_CTX_copy
+#define EVP_MD_CTX_copy_ex             wolfSSL_EVP_MD_CTX_copy_ex
+#define EVP_PKEY_bits                  wolfSSL_EVP_PKEY_bits
+#define EVP_PKEY_CTX_free              wolfSSL_EVP_PKEY_CTX_free
+#define EVP_PKEY_CTX_new               wolfSSL_EVP_PKEY_CTX_new
+#define EVP_PKEY_CTX_set_rsa_padding   wolfSSL_EVP_PKEY_CTX_set_rsa_padding
+#define EVP_PKEY_decrypt               wolfSSL_EVP_PKEY_decrypt
+#define EVP_PKEY_decrypt_init          wolfSSL_EVP_PKEY_decrypt_init
+#define EVP_PKEY_encrypt               wolfSSL_EVP_PKEY_encrypt
+#define EVP_PKEY_encrypt_init          wolfSSL_EVP_PKEY_encrypt_init
+#define EVP_PKEY_new                   wolfSSL_PKEY_new
+#define EVP_PKEY_free                  wolfSSL_EVP_PKEY_free
+#define EVP_PKEY_size                  wolfSSL_EVP_PKEY_size
+#define EVP_PKEY_type                  wolfSSL_EVP_PKEY_type
+#define EVP_PKEY_base_id               wolfSSL_EVP_PKEY_base_id
+#define EVP_PKEY_id                    wolfSSL_EVP_PKEY_id
+#define EVP_SignFinal                  wolfSSL_EVP_SignFinal
+#define EVP_SignInit                   wolfSSL_EVP_SignInit
+#define EVP_SignUpdate                 wolfSSL_EVP_SignUpdate
+#define EVP_VerifyFinal                wolfSSL_EVP_VerifyFinal
+#define EVP_VerifyInit                 wolfSSL_EVP_VerifyInit
+#define EVP_VerifyUpdate               wolfSSL_EVP_VerifyUpdate
 
 #define EVP_CIPHER_CTX_block_size  wolfSSL_EVP_CIPHER_CTX_block_size
@@ -475,8 +587,18 @@
 #define EVP_CIPHER_flags           wolfSSL_EVP_CIPHER_flags
 #define EVP_CIPHER_CTX_set_flags   wolfSSL_EVP_CIPHER_CTX_set_flags
+#define EVP_CIPHER_CTX_clear_flags wolfSSL_EVP_CIPHER_CTX_clear_flags
 #define EVP_CIPHER_CTX_set_padding wolfSSL_EVP_CIPHER_CTX_set_padding
 #define EVP_CIPHER_CTX_flags       wolfSSL_EVP_CIPHER_CTX_flags
 #define EVP_add_digest             wolfSSL_EVP_add_digest
 #define EVP_add_cipher             wolfSSL_EVP_add_cipher
+#define EVP_cleanup                wolfSSL_EVP_cleanup
+
+#define OpenSSL_add_all_digests()  wolfCrypt_Init()
+#define OpenSSL_add_all_ciphers()  wolfCrypt_Init()
+#define OpenSSL_add_all_algorithms wolfSSL_add_all_algorithms
+#define OpenSSL_add_all_algorithms_noconf wolfSSL_OpenSSL_add_all_algorithms_noconf
+#define wolfSSL_OPENSSL_add_all_algorithms_noconf wolfSSL_OpenSSL_add_all_algorithms_noconf
+
+#define PKCS5_PBKDF2_HMAC_SHA1     wolfSSL_PKCS5_PBKDF2_HMAC_SHA1
 
 #ifndef EVP_MAX_MD_SIZE
@@ -489,4 +611,6 @@
 #endif
 
+WOLFSSL_API void printPKEY(WOLFSSL_EVP_PKEY *k);
+
 #ifdef __cplusplus
     } /* extern "C" */
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/hmac.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/hmac.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/hmac.h	(revision 372)
@@ -37,4 +37,5 @@
 
 #include <wolfssl/openssl/evp.h>
+#include <wolfssl/openssl/opensslv.h>
 #include <wolfssl/wolfcrypt/hmac.h>
 
@@ -53,17 +54,22 @@
     Hmac hmac;
     int  type;
+    word32  save_ipad[WC_HMAC_BLOCK_SIZE  / sizeof(word32)];  /* same block size all*/
+    word32  save_opad[WC_HMAC_BLOCK_SIZE  / sizeof(word32)];
 } WOLFSSL_HMAC_CTX;
 
 
-WOLFSSL_API void wolfSSL_HMAC_Init(WOLFSSL_HMAC_CTX* ctx, const void* key,
+WOLFSSL_API int wolfSSL_HMAC_CTX_Init(WOLFSSL_HMAC_CTX* ctx);
+WOLFSSL_API int wolfSSL_HMAC_CTX_copy(WOLFSSL_HMAC_CTX* des,
+                                       WOLFSSL_HMAC_CTX* src);
+WOLFSSL_LOCAL int wolfSSL_HmacCopy(Hmac* des, Hmac* src);
+WOLFSSL_API int wolfSSL_HMAC_Init(WOLFSSL_HMAC_CTX* ctx, const void* key,
                                  int keylen, const EVP_MD* type);
 WOLFSSL_API int wolfSSL_HMAC_Init_ex(WOLFSSL_HMAC_CTX* ctx, const void* key,
-                                     int len, const EVP_MD* md, void* impl);
-WOLFSSL_API void wolfSSL_HMAC_Update(WOLFSSL_HMAC_CTX* ctx,
+                             int keylen, const EVP_MD* type, WOLFSSL_ENGINE* e);
+WOLFSSL_API int wolfSSL_HMAC_Update(WOLFSSL_HMAC_CTX* ctx,
                                    const unsigned char* data, int len);
-WOLFSSL_API void wolfSSL_HMAC_Final(WOLFSSL_HMAC_CTX* ctx, unsigned char* hash,
+WOLFSSL_API int wolfSSL_HMAC_Final(WOLFSSL_HMAC_CTX* ctx, unsigned char* hash,
                                   unsigned int* len);
-WOLFSSL_API void wolfSSL_HMAC_cleanup(WOLFSSL_HMAC_CTX* ctx);
-
+WOLFSSL_API int wolfSSL_HMAC_cleanup(WOLFSSL_HMAC_CTX* ctx);
 
 typedef struct WOLFSSL_HMAC_CTX HMAC_CTX;
@@ -71,6 +77,8 @@
 #define HMAC(a,b,c,d,e,f,g) wolfSSL_HMAC((a),(b),(c),(d),(e),(f),(g))
 
-#define HMAC_Init    wolfSSL_HMAC_Init
+#define HMAC_CTX_init wolfSSL_HMAC_CTX_Init
+#define HMAC_CTX_copy wolfSSL_HMAC_CTX_copy
 #define HMAC_Init_ex wolfSSL_HMAC_Init_ex
+#define HMAC_Init     wolfSSL_HMAC_Init
 #define HMAC_Update  wolfSSL_HMAC_Update
 #define HMAC_Final   wolfSSL_HMAC_Final
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/md4.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/md4.h	(revision 372)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/md4.h	(revision 372)
@@ -0,0 +1,62 @@
+/* md4.h
+ *
+ * Copyright (C) 2006-2016 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
+
+#ifndef WOLFSSL_MD4_H_
+#define WOLFSSL_MD4_H_
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifndef NO_MD4
+
+#ifdef WOLFSSL_PREFIX
+#include "prefix_md4.h"
+#endif
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+typedef struct WOLFSSL_MD4_CTX {
+    int buffer[32];      /* big enough to hold, check size in Init */
+} WOLFSSL_MD4_CTX;
+
+
+WOLFSSL_API void wolfSSL_MD4_Init(WOLFSSL_MD4_CTX*);
+WOLFSSL_API void wolfSSL_MD4_Update(WOLFSSL_MD4_CTX*, const void*, unsigned long);
+WOLFSSL_API void wolfSSL_MD4_Final(unsigned char*, WOLFSSL_MD4_CTX*);
+
+
+typedef WOLFSSL_MD4_CTX MD4_CTX;
+
+#define MD4_Init   wolfSSL_MD4_Init
+#define MD4_Update wolfSSL_MD4_Update
+#define MD4_Final  wolfSSL_MD4_Final
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+#endif /* NO_MD4 */
+
+#endif /* WOLFSSL_MD4_H_ */
+
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/md5.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/md5.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/md5.h	(revision 372)
@@ -1,2 +1,23 @@
+/* md5.h
+ *
+ * Copyright (C) 2006-2017 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
 /* md5.h for openssl */
 
@@ -21,5 +42,5 @@
 
 typedef struct WOLFSSL_MD5_CTX {
-    int holder[28 + (WC_ASYNC_DEV_SIZE / sizeof(int))];   /* big enough to hold wolfcrypt md5, but check on init */
+    void* holder[(112 + WC_ASYNC_DEV_SIZE) / sizeof(void*)];   /* big enough to hold wolfcrypt md5, but check on init */
 } WOLFSSL_MD5_CTX;
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ocsp.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ocsp.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ocsp.h	(revision 372)
@@ -1,2 +1,23 @@
+/* ocsp.h
+ *
+ * Copyright (C) 2006-2017 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
 /* ocsp.h for libcurl */
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/opensslv.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/opensslv.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/opensslv.h	(revision 372)
@@ -1,2 +1,23 @@
+/* opensslv.h
+ *
+ * Copyright (C) 2006-2017 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
 /* opensslv.h compatibility */
 
@@ -6,5 +27,6 @@
 
 /* api version compatibility */
-#if defined(HAVE_STUNNEL) || defined(HAVE_LIGHTY) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+#if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL) || defined(HAVE_LIGHTY) || \
+    defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
      /* version number can be increased for Lighty after compatibility for ECDH
         is added */
@@ -18,3 +40,2 @@
 
 #endif /* header */
-
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/pem.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/pem.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/pem.h	(revision 372)
@@ -1,3 +1,28 @@
+/* pem.h
+ *
+ * Copyright (C) 2006-2017 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
 /* pem.h for openssl */
+
+/*!
+    \file wolfssl/openssl/pem.h
+*/
 
 
@@ -14,6 +39,4 @@
 #endif
 
-#define PEM_write_bio_PrivateKey wolfSSL_PEM_write_bio_PrivateKey
-
 /* RSA */
 WOLFSSL_API
@@ -23,4 +46,9 @@
                                         pem_password_cb* cb, void* arg);
 WOLFSSL_API
+WOLFSSL_RSA* wolfSSL_PEM_read_bio_RSAPrivateKey(WOLFSSL_BIO* bio,
+                                                  WOLFSSL_RSA**,
+                                                  pem_password_cb* cb,
+                                                  void* arg);
+WOLFSSL_API
 int wolfSSL_PEM_write_mem_RSAPrivateKey(RSA* rsa, const EVP_CIPHER* cipher,
                                         unsigned char* passwd, int len,
@@ -28,16 +56,16 @@
 #if !defined(NO_FILESYSTEM)
 WOLFSSL_API
-int wolfSSL_PEM_write_RSAPrivateKey(FILE *fp, WOLFSSL_RSA *rsa,
+int wolfSSL_PEM_write_RSAPrivateKey(XFILE fp, WOLFSSL_RSA *rsa,
                                     const EVP_CIPHER *enc,
                                     unsigned char *kstr, int klen,
                                     pem_password_cb *cb, void *u);
 WOLFSSL_API
-WOLFSSL_RSA *wolfSSL_PEM_read_RSAPublicKey(FILE *fp, WOLFSSL_RSA **x,
+WOLFSSL_RSA *wolfSSL_PEM_read_RSAPublicKey(XFILE fp, WOLFSSL_RSA **x,
                                            pem_password_cb *cb, void *u);
 WOLFSSL_API
-int wolfSSL_PEM_write_RSAPublicKey(FILE *fp, WOLFSSL_RSA *x);
+int wolfSSL_PEM_write_RSAPublicKey(XFILE fp, WOLFSSL_RSA *x);
 
 WOLFSSL_API
-int wolfSSL_PEM_write_RSA_PUBKEY(FILE *fp, WOLFSSL_RSA *x);
+int wolfSSL_PEM_write_RSA_PUBKEY(XFILE fp, WOLFSSL_RSA *x);
 #endif /* NO_FILESYSTEM */
 
@@ -56,10 +84,10 @@
 #if !defined(NO_FILESYSTEM)
 WOLFSSL_API
-int wolfSSL_PEM_write_DSAPrivateKey(FILE *fp, WOLFSSL_DSA *dsa,
+int wolfSSL_PEM_write_DSAPrivateKey(XFILE fp, WOLFSSL_DSA *dsa,
                                     const EVP_CIPHER *enc,
                                     unsigned char *kstr, int klen,
                                     pem_password_cb *cb, void *u);
 WOLFSSL_API
-int wolfSSL_PEM_write_DSA_PUBKEY(FILE *fp, WOLFSSL_DSA *x);
+int wolfSSL_PEM_write_DSA_PUBKEY(XFILE fp, WOLFSSL_DSA *x);
 #endif /* NO_FILESYSTEM */
 
@@ -77,10 +105,10 @@
 #if !defined(NO_FILESYSTEM)
 WOLFSSL_API
-int wolfSSL_PEM_write_ECPrivateKey(FILE *fp, WOLFSSL_EC_KEY *key,
+int wolfSSL_PEM_write_ECPrivateKey(XFILE fp, WOLFSSL_EC_KEY *key,
                                    const EVP_CIPHER *enc,
                                    unsigned char *kstr, int klen,
                                    pem_password_cb *cb, void *u);
 WOLFSSL_API
-int wolfSSL_PEM_write_EC_PUBKEY(FILE *fp, WOLFSSL_EC_KEY *key);
+int wolfSSL_PEM_write_EC_PUBKEY(XFILE fp, WOLFSSL_EC_KEY *key);
 #endif /* NO_FILESYSTEM */
 
@@ -92,4 +120,8 @@
                                                   void* arg);
 WOLFSSL_API
+WOLFSSL_EVP_PKEY *wolfSSL_PEM_read_bio_PUBKEY(WOLFSSL_BIO* bio,
+                                              WOLFSSL_EVP_PKEY **key,
+                                              pem_password_cb *cb, void *pass);
+WOLFSSL_API
 int wolfSSL_PEM_write_bio_PrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key,
                                         const WOLFSSL_EVP_CIPHER* cipher,
@@ -97,27 +129,49 @@
                                         pem_password_cb* cb, void* arg);
 
-WOLFSSL_API
-int wolfSSL_EVP_PKEY_type(int type);
 
 WOLFSSL_API
-int wolfSSL_EVP_PKEY_base_id(const EVP_PKEY *pkey);
+int wolfSSL_PEM_read_bio(WOLFSSL_BIO* bio, char **name, char **header,
+                         unsigned char **data, long *len);
+WOLFSSL_API
+int wolfSSL_PEM_write_bio(WOLFSSL_BIO *bio, const char *name,
+                          const char *header, const unsigned char *data,
+                          long len);
+#if !defined(NO_FILESYSTEM)
+WOLFSSL_API
+int wolfSSL_PEM_read(XFILE fp, char **name, char **header, unsigned char **data,
+                     long *len);
+WOLFSSL_API
+int wolfSSL_PEM_write(XFILE fp, const char *name, const char *header,
+                      const unsigned char *data, long len);
+#endif
 
 #if !defined(NO_FILESYSTEM)
 WOLFSSL_API
-WOLFSSL_EVP_PKEY *wolfSSL_PEM_read_PUBKEY(FILE *fp, EVP_PKEY **x,
+WOLFSSL_EVP_PKEY *wolfSSL_PEM_read_PUBKEY(XFILE fp, EVP_PKEY **x,
 										  pem_password_cb *cb, void *u);
 WOLFSSL_API
-WOLFSSL_X509 *wolfSSL_PEM_read_X509(FILE *fp, WOLFSSL_X509 **x,
+WOLFSSL_X509 *wolfSSL_PEM_read_X509(XFILE fp, WOLFSSL_X509 **x,
                                           pem_password_cb *cb, void *u);
 WOLFSSL_API
-WOLFSSL_EVP_PKEY *wolfSSL_PEM_read_PrivateKey(FILE *fp, WOLFSSL_EVP_PKEY **x,
+WOLFSSL_EVP_PKEY *wolfSSL_PEM_read_PrivateKey(XFILE fp, WOLFSSL_EVP_PKEY **x,
                                           pem_password_cb *cb, void *u);
+
+WOLFSSL_API
+int wolfSSL_PEM_write_X509(XFILE fp, WOLFSSL_X509 *x);
 #endif /* NO_FILESYSTEM */
+
+#define PEM_read                        wolfSSL_PEM_read
+#define PEM_read_bio                    wolfSSL_PEM_read_bio
+#define PEM_write                       wolfSSL_PEM_write
+#define PEM_write_bio                   wolfSSL_PEM_write_bio
 
 #define PEM_read_X509               wolfSSL_PEM_read_X509
 #define PEM_read_PrivateKey         wolfSSL_PEM_read_PrivateKey
+#define PEM_write_X509                  wolfSSL_PEM_write_X509
 #define PEM_write_bio_PrivateKey    wolfSSL_PEM_write_bio_PrivateKey
+#define PEM_write_bio_PKCS8PrivateKey   wolfSSL_PEM_write_bio_PKCS8PrivateKey
 /* RSA */
 #define PEM_write_bio_RSAPrivateKey wolfSSL_PEM_write_bio_RSAPrivateKey
+#define PEM_read_bio_RSAPrivateKey      wolfSSL_PEM_read_bio_RSAPrivateKey
 #define PEM_write_RSAPrivateKey     wolfSSL_PEM_write_RSAPrivateKey
 #define PEM_write_RSA_PUBKEY        wolfSSL_PEM_write_RSA_PUBKEY
@@ -135,5 +189,5 @@
 #define PEM_read_bio_PrivateKey wolfSSL_PEM_read_bio_PrivateKey
 #define PEM_read_PUBKEY         wolfSSL_PEM_read_PUBKEY
-#define EVP_PKEY_type           wolfSSL_EVP_PKEY_type
+#define PEM_read_bio_PUBKEY             wolfSSL_PEM_read_bio_PUBKEY
 
 #ifdef __cplusplus
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/rand.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/rand.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/rand.h	(revision 372)
@@ -1,2 +1,23 @@
+/* rand.h
+ *
+ * Copyright (C) 2006-2017 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
 /* rand.h for openSSL */
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ripemd.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ripemd.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ripemd.h	(revision 372)
@@ -1,2 +1,23 @@
+/* ripemd.h
+ *
+ * Copyright (C) 2006-2017 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
 /* ripemd.h for openssl */
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/rsa.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/rsa.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/rsa.h	(revision 372)
@@ -1,2 +1,23 @@
+/* rsa.h
+ *
+ * Copyright (C) 2006-2017 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
 /* rsa.h for openSSL */
 
@@ -12,16 +33,7 @@
 #endif
 
-
-enum  { 
-    RSA_PKCS1_PADDING = 1,
-    RSA_PKCS1_OAEP_PADDING = 4
- };
-
-/* rsaTypes */
-enum {
-    NID_sha256 = 672,
-    NID_sha384 = 673,
-    NID_sha512 = 674
-};
+/* Padding types */
+#define RSA_PKCS1_PADDING      0
+#define RSA_PKCS1_OAEP_PADDING 1
 
 #ifndef WOLFSSL_RSA_TYPE_DEFINED /* guard on redeclaration */
@@ -33,4 +45,7 @@
 
 struct WOLFSSL_RSA {
+#ifdef WC_RSA_BLINDING
+    WC_RNG* rng;              /* for PrivateDecrypt blinding */
+#endif
 	WOLFSSL_BIGNUM* n;
 	WOLFSSL_BIGNUM* e;
@@ -41,7 +56,9 @@
 	WOLFSSL_BIGNUM* dmq1;      /* dQ */
 	WOLFSSL_BIGNUM* iqmp;      /* u */
+    void*          heap;
     void*          internal;  /* our RSA */
     char           inSet;     /* internal set from external ? */
     char           exSet;     /* external set from internal ? */
+    char           ownRng;    /* flag for if the rng should be free'd */
 };
 
@@ -58,4 +75,6 @@
 WOLFSSL_API int wolfSSL_RSA_private_decrypt(int len, const unsigned char* fr,
                                  unsigned char* to, WOLFSSL_RSA*, int padding);
+WOLFSSL_API int wolfSSL_RSA_private_encrypt(int len, unsigned char* in,
+                            unsigned char* out, WOLFSSL_RSA* rsa, int padding);
 
 WOLFSSL_API int wolfSSL_RSA_size(const WOLFSSL_RSA*);
@@ -63,9 +82,19 @@
                                unsigned int mLen, unsigned char* sigRet,
                                unsigned int* sigLen, WOLFSSL_RSA*);
+WOLFSSL_API int wolfSSL_RSA_sign_ex(int type, const unsigned char* m,
+                               unsigned int mLen, unsigned char* sigRet,
+                               unsigned int* sigLen, WOLFSSL_RSA*, int);
+WOLFSSL_API int wolfSSL_RSA_verify(int type, const unsigned char* m,
+                               unsigned int mLen, const unsigned char* sig,
+                               unsigned int sigLen, WOLFSSL_RSA*);
 WOLFSSL_API int wolfSSL_RSA_public_decrypt(int flen, const unsigned char* from,
                                   unsigned char* to, WOLFSSL_RSA*, int padding);
 WOLFSSL_API int wolfSSL_RSA_GenAdd(WOLFSSL_RSA*);
 WOLFSSL_API int wolfSSL_RSA_LoadDer(WOLFSSL_RSA*, const unsigned char*, int sz);
+WOLFSSL_API int wolfSSL_RSA_LoadDer_ex(WOLFSSL_RSA*, const unsigned char*, int sz, int opt);
 
+#define WOLFSSL_RSA_LOAD_PRIVATE 1
+#define WOLFSSL_RSA_LOAD_PUBLIC  2
+#define WOLFSSL_RSA_F4           0x10001L
 
 #define RSA_new  wolfSSL_RSA_new
@@ -77,9 +106,12 @@
 #define RSA_public_encrypt  wolfSSL_RSA_public_encrypt
 #define RSA_private_decrypt wolfSSL_RSA_private_decrypt
+#define RSA_private_encrypt wolfSSL_RSA_private_encrypt
 
 #define RSA_size           wolfSSL_RSA_size
 #define RSA_sign           wolfSSL_RSA_sign
+#define RSA_verify          wolfSSL_RSA_verify
 #define RSA_public_decrypt wolfSSL_RSA_public_decrypt
 
+#define RSA_F4             WOLFSSL_RSA_F4
 
 #ifdef __cplusplus
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/sha.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/sha.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/sha.h	(revision 372)
@@ -1,2 +1,23 @@
+/* sha.h
+ *
+ * Copyright (C) 2006-2017 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
 /* sha.h for openssl */
 
@@ -19,5 +40,5 @@
 typedef struct WOLFSSL_SHA_CTX {
     /* big enough to hold wolfcrypt Sha, but check on init */
-    int holder[28 + (WC_ASYNC_DEV_SIZE / sizeof(int))];
+    void* holder[(112 + WC_ASYNC_DEV_SIZE) / sizeof(void*)];
 } WOLFSSL_SHA_CTX;
 
@@ -54,5 +75,5 @@
 typedef struct WOLFSSL_SHA224_CTX {
     /* big enough to hold wolfcrypt Sha224, but check on init */
-    ALIGN16 int holder[34 + (WC_ASYNC_DEV_SIZE / sizeof(int))];
+    ALIGN16 void* holder[(272 + WC_ASYNC_DEV_SIZE) / sizeof(void*)];
 } WOLFSSL_SHA224_CTX;
 
@@ -81,5 +102,5 @@
 typedef struct WOLFSSL_SHA256_CTX {
     /* big enough to hold wolfcrypt Sha256, but check on init */
-    ALIGN16 int holder[34 + (WC_ASYNC_DEV_SIZE / sizeof(int))];
+    ALIGN16 void* holder[(272 + WC_ASYNC_DEV_SIZE) / sizeof(void*)];
 } WOLFSSL_SHA256_CTX;
 
@@ -99,4 +120,9 @@
 #define SHA256_Update wolfSSL_SHA256_Update
 #define SHA256_Final  wolfSSL_SHA256_Final
+#if defined(NO_OLD_SHA_NAMES) && !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+    /* SHA256 is only available in non-fips mode because of SHA256 enum in FIPS
+     * build. */
+    #define SHA256 wolfSSL_SHA256
+#endif
 
 
@@ -105,5 +131,5 @@
 typedef struct WOLFSSL_SHA384_CTX {
     /* big enough to hold wolfCrypt Sha384, but check on init */
-    long long holder[32 + (WC_ASYNC_DEV_SIZE / sizeof(long long))];
+    void* holder[(256 + WC_ASYNC_DEV_SIZE) / sizeof(void*)];
 } WOLFSSL_SHA384_CTX;
 
@@ -123,5 +149,9 @@
 #define SHA384_Update wolfSSL_SHA384_Update
 #define SHA384_Final  wolfSSL_SHA384_Final
-
+#if defined(NO_OLD_SHA_NAMES) && !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+    /* SHA384 is only available in non-fips mode because of SHA384 enum in FIPS
+     * build. */
+    #define SHA384 wolfSSL_SHA384
+#endif
 #endif /* WOLFSSL_SHA384 */
 
@@ -130,5 +160,5 @@
 typedef struct WOLFSSL_SHA512_CTX {
     /* big enough to hold wolfCrypt Sha384, but check on init */
-    long long holder[36 + (WC_ASYNC_DEV_SIZE / sizeof(long long))];
+    void* holder[(288 + WC_ASYNC_DEV_SIZE) / sizeof(void*)];
 } WOLFSSL_SHA512_CTX;
 
@@ -148,5 +178,9 @@
 #define SHA512_Update wolfSSL_SHA512_Update
 #define SHA512_Final  wolfSSL_SHA512_Final
-
+#if defined(NO_OLD_SHA_NAMES) && !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+    /* SHA512 is only available in non-fips mode because of SHA512 enum in FIPS
+     * build. */
+    #define SHA512 wolfSSL_SHA512
+#endif
 #endif /* WOLFSSL_SHA512 */
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ssl.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ssl.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/openssl/ssl.h	(revision 372)
@@ -31,7 +31,17 @@
 
 /* wolfssl_openssl compatibility layer */
+#ifndef OPENSSL_EXTRA_SSL_GUARD
+#define OPENSSL_EXTRA_SSL_GUARD
 #include <wolfssl/ssl.h>
+#endif /* OPENSSL_EXTRA_SSL_GUARD */
 
 #include <wolfssl/openssl/evp.h>
+#ifdef OPENSSL_EXTRA
+#include <wolfssl/openssl/crypto.h>
+#endif
+
+#if defined(WOLFSSL_ASIO) || defined(WOLFSSL_HAPROXY)
+#include <wolfssl/wolfcrypt/asn.h>
+#endif
 
 #ifdef __cplusplus
@@ -56,13 +66,14 @@
 
 typedef WOLFSSL_X509       X509;
+typedef WOLFSSL_X509       X509_REQ;
 typedef WOLFSSL_X509_NAME  X509_NAME;
 typedef WOLFSSL_X509_CHAIN X509_CHAIN;
 
+typedef WOLFSSL_STACK      EXTENDED_KEY_USAGE;
+
 
 /* redeclare guard */
 #define WOLFSSL_TYPES_DEFINED
 
-
-typedef WOLFSSL_EVP_PKEY               EVP_PKEY;
 typedef WOLFSSL_BIO                    BIO;
 typedef WOLFSSL_BIO_METHOD             BIO_METHOD;
@@ -87,5 +98,4 @@
 #define ASN1_GENERALIZEDTIME WOLFSSL_ASN1_TIME
 
-typedef WOLFSSL_MD4_CTX        MD4_CTX;
 typedef WOLFSSL_COMP_METHOD    COMP_METHOD;
 typedef WOLFSSL_X509_REVOKED   X509_REVOKED;
@@ -94,6 +104,34 @@
 typedef WOLFSSL_X509_STORE_CTX X509_STORE_CTX;
 
+#define EVP_CIPHER_INFO        EncryptedInfo
+
+#define STACK_OF(x) WOLFSSL_STACK
+
 #define CRYPTO_free   XFREE
 #define CRYPTO_malloc XMALLOC
+#define CRYPTO_EX_new                   WOLFSSL_CRYPTO_EX_new
+#define CRYPTO_EX_dup                   WOLFSSL_CRYPTO_EX_dup
+#define CRYPTO_EX_free                  WOLFSSL_CRYPTO_EX_free
+
+/* depreciated */
+#define CRYPTO_thread_id                wolfSSL_thread_id
+#define CRYPTO_set_id_callback          wolfSSL_set_id_callback
+ 
+#define CRYPTO_LOCK             0x01
+#define CRYPTO_UNLOCK           0x02
+#define CRYPTO_READ             0x04
+#define CRYPTO_WRITE            0x08
+
+#define CRYPTO_set_locking_callback     wolfSSL_set_locking_callback
+#define CRYPTO_set_dynlock_create_callback  wolfSSL_set_dynlock_create_callback
+#define CRYPTO_set_dynlock_lock_callback wolfSSL_set_dynlock_lock_callback
+#define CRYPTO_set_dynlock_destroy_callback wolfSSL_set_dynlock_destroy_callback
+#define CRYPTO_num_locks                wolfSSL_num_locks
+#define CRYPTO_dynlock_value            WOLFSSL_dynlock_value
+
+#define CRYPTO_cleanup_all_ex_data      wolfSSL_cleanup_all_ex_data
+
+/* this function was used to set the default malloc, free, and realloc */
+#define CRYPTO_malloc_init() /* CRYPTO_malloc_init is not needed */
 
 #define SSL_get_client_random(ssl,out,outSz) \
@@ -103,6 +141,4 @@
 #define SSL_get_shared_ciphers(ctx,buf,len) \
                                    wolfSSL_get_shared_ciphers((ctx),(buf),(len))
-
-#define ERR_print_errors_fp(file) wolfSSL_ERR_dump_errors_fp((file))
 
 /* at the moment only returns ok */
@@ -115,5 +151,13 @@
 #define SSL_use_certificate           wolfSSL_use_certificate
 #define SSL_use_certificate_ASN1      wolfSSL_use_certificate_ASN1
-
+#define d2i_PKCS8_PRIV_KEY_INFO_bio     wolfSSL_d2i_PKCS8_PKEY_bio
+#define d2i_PKCS8PrivateKey_bio         wolfSSL_d2i_PKCS8PrivateKey_bio
+#define PKCS8_PRIV_KEY_INFO_free        wolfSSL_EVP_PKEY_free
+#define d2i_PKCS12_fp                   wolfSSL_d2i_PKCS12_fp
+
+#define d2i_PUBKEY                      wolfSSL_d2i_PUBKEY
+#define d2i_PUBKEY_bio                  wolfSSL_d2i_PUBKEY_bio
+#define d2i_PrivateKey                  wolfSSL_d2i_PrivateKey
+#define d2i_AutoPrivateKey              wolfSSL_d2i_AutoPrivateKey
 #define SSL_use_PrivateKey         wolfSSL_use_PrivateKey
 #define SSL_use_PrivateKey_ASN1    wolfSSL_use_PrivateKey_ASN1
@@ -122,12 +166,23 @@
 
 #define SSLv23_method       wolfSSLv23_method
+#define SSLv23_client_method            wolfSSLv23_client_method
+#define SSLv2_client_method             wolfSSLv2_client_method
+#define SSLv2_server_method             wolfSSLv2_server_method
 #define SSLv3_server_method wolfSSLv3_server_method
 #define SSLv3_client_method wolfSSLv3_client_method
+#define TLSv1_method                    wolfTLSv1_method
 #define TLSv1_server_method wolfTLSv1_server_method
 #define TLSv1_client_method wolfTLSv1_client_method
+#define TLSv1_1_method                  wolfTLSv1_1_method
 #define TLSv1_1_server_method wolfTLSv1_1_server_method
 #define TLSv1_1_client_method wolfTLSv1_1_client_method
+#define TLSv1_2_method                  wolfTLSv1_2_method
 #define TLSv1_2_server_method wolfTLSv1_2_server_method
 #define TLSv1_2_client_method wolfTLSv1_2_client_method
+#define TLSv1_3_method                  wolfTLSv1_3_method
+#define TLSv1_3_server_method           wolfTLSv1_3_server_method
+#define TLSv1_3_client_method           wolfTLSv1_3_client_method
+
+#define X509_FILETYPE_ASN1 SSL_FILETYPE_ASN1
 
 #ifdef WOLFSSL_DTLS
@@ -185,8 +240,4 @@
 #define SSL_CTX_set_cipher_list wolfSSL_CTX_set_cipher_list
 #define SSL_set_cipher_list     wolfSSL_set_cipher_list
-
-#define ERR_error_string wolfSSL_ERR_error_string
-#define ERR_error_string_n wolfSSL_ERR_error_string_n
-#define ERR_reason_error_string wolfSSL_ERR_reason_error_string
 
 #define SSL_set_ex_data wolfSSL_set_ex_data
@@ -216,14 +267,143 @@
 #define SSL_SESSION_get_master_key_length wolfSSL_SESSION_get_master_key_length
 
-#define X509_NAME_get_text_by_NID wolfSSL_X509_NAME_get_text_by_NID
-#define X509_get_ext_d2i wolfSSL_X509_get_ext_d2i
-#define X509_digest wolfSSL_X509_digest
+#define DSA_dup_DH                      wolfSSL_DSA_dup_DH
+ 
+#define i2d_X509_bio                    wolfSSL_i2d_X509_bio
+#define d2i_X509_bio                    wolfSSL_d2i_X509_bio
+#define d2i_X509_fp                     wolfSSL_d2i_X509_fp
+#define i2d_X509                        wolfSSL_i2d_X509
+#define d2i_X509                        wolfSSL_d2i_X509
+#define PEM_read_bio_X509               wolfSSL_PEM_read_bio_X509
+#define PEM_read_bio_X509_AUX           wolfSSL_PEM_read_bio_X509_AUX
+#define PEM_read_X509                   wolfSSL_PEM_read_X509
+#define PEM_write_bio_X509              wolfSSL_PEM_write_bio_X509
+#define PEM_write_bio_X509_AUX          wolfSSL_PEM_write_bio_X509_AUX
+
+#define i2d_X509_REQ                    wolfSSL_i2d_X509_REQ
+#define X509_REQ_new                    wolfSSL_X509_REQ_new
+#define X509_REQ_free                   wolfSSL_X509_REQ_free
+#define X509_REQ_sign                   wolfSSL_X509_REQ_sign
+#define X509_REQ_set_subject_name       wolfSSL_X509_REQ_set_subject_name
+#define X509_REQ_set_pubkey             wolfSSL_X509_REQ_set_pubkey
+#define PEM_write_bio_X509_REQ          wolfSSL_PEM_write_bio_X509_REQ
+
+#define X509_new                        wolfSSL_X509_new
 #define X509_free wolfSSL_X509_free
-#define OPENSSL_free wolfSSL_OPENSSL_free
+#define X509_load_certificate_file      wolfSSL_X509_load_certificate_file
+#define X509_digest                     wolfSSL_X509_digest
+#define X509_get_ext_d2i                wolfSSL_X509_get_ext_d2i
+#define X509_get_issuer_name            wolfSSL_X509_get_issuer_name
+#define X509_get_subject_name           wolfSSL_X509_get_subject_name
+#define X509_get_pubkey                 wolfSSL_X509_get_pubkey
+#define X509_get_notBefore(cert)      (ASN1_TIME*)wolfSSL_X509_notBefore((cert))
+#define X509_get_notAfter(cert)       (ASN1_TIME*)wolfSSL_X509_notAfter((cert))
+#define X509_get_serialNumber           wolfSSL_X509_get_serialNumber
+#define X509_get0_pubkey_bitstr         wolfSSL_X509_get0_pubkey_bitstr
+#define X509_get_ex_new_index           wolfSSL_X509_get_ex_new_index
+#define X509_get_ex_data                wolfSSL_X509_get_ex_data
+#define X509_set_ex_data                wolfSSL_X509_set_ex_data
+#define X509_get1_ocsp                  wolfSSL_X509_get1_ocsp
+#ifndef WOLFSSL_HAPROXY
+#define X509_get_version                wolfSSL_X509_get_version
+#endif
+#define X509_get_signature_nid          wolfSSL_X509_get_signature_nid
+#define X509_set_subject_name           wolfSSL_X509_set_subject_name
+#define X509_set_pubkey                 wolfSSL_X509_set_pubkey
+#define X509_print                      wolfSSL_X509_print
+#define X509_verify_cert_error_string   wolfSSL_X509_verify_cert_error_string
+#define X509_verify_cert                wolfSSL_X509_verify_cert
+#define X509_check_private_key          wolfSSL_X509_check_private_key
+#define X509_check_ca                   wolfSSL_X509_check_ca
+#define X509_check_host                 wolfSSL_X509_check_host
+#define X509_email_free                 wolfSSL_X509_email_free
+#define X509_check_issued               wolfSSL_X509_check_issued
+#define X509_dup                        wolfSSL_X509_dup
+ 
+#define sk_X509_new                     wolfSSL_sk_X509_new
+#define sk_X509_num                     wolfSSL_sk_X509_num
+#define sk_X509_value                   wolfSSL_sk_X509_value
+#define sk_X509_push                    wolfSSL_sk_X509_push
+#define sk_X509_pop                     wolfSSL_sk_X509_pop
+#define sk_X509_pop_free                wolfSSL_sk_X509_pop_free
+#define sk_X509_free                    wolfSSL_sk_X509_free
+
+#define i2d_X509_NAME                   wolfSSL_i2d_X509_NAME
+#define X509_NAME_new                   wolfSSL_X509_NAME_new
+#define X509_NAME_free                  wolfSSL_X509_NAME_free
+#define X509_NAME_get_text_by_NID       wolfSSL_X509_NAME_get_text_by_NID
+#define X509_NAME_cmp                   wolfSSL_X509_NAME_cmp
+#define X509_NAME_ENTRY_free            wolfSSL_X509_NAME_ENTRY_free
+#define X509_NAME_ENTRY_create_by_NID   wolfSSL_X509_NAME_ENTRY_create_by_NID
+#define X509_NAME_add_entry             wolfSSL_X509_NAME_add_entry
+#define X509_NAME_add_entry_by_txt      wolfSSL_X509_NAME_add_entry_by_txt
+#define X509_NAME_oneline               wolfSSL_X509_NAME_oneline
+#define X509_NAME_get_index_by_NID      wolfSSL_X509_NAME_get_index_by_NID
+#define X509_NAME_print_ex              wolfSSL_X509_NAME_print_ex
+#define X509_NAME_digest                wolfSSL_X509_NAME_digest
+#define X509_cmp_current_time           wolfSSL_X509_cmp_current_time
+
+#define sk_X509_NAME_pop_free           wolfSSL_sk_X509_NAME_pop_free
+#define sk_X509_NAME_num                wolfSSL_sk_X509_NAME_num
+#define sk_X509_NAME_value              wolfSSL_sk_X509_NAME_value
+
+    typedef WOLFSSL_X509_NAME_ENTRY X509_NAME_ENTRY;
+
+#define X509_NAME_entry_count           wolfSSL_X509_NAME_entry_count
+#define X509_NAME_ENTRY_get_object      wolfSSL_X509_NAME_ENTRY_get_object
+#define X509_NAME_get_entry             wolfSSL_X509_NAME_get_entry
+#define X509_NAME_ENTRY_get_data        wolfSSL_X509_NAME_ENTRY_get_data
+#define X509_NAME_ENTRY_get_object      wolfSSL_X509_NAME_ENTRY_get_object
+
+#define X509_V_FLAG_CRL_CHECK     WOLFSSL_CRL_CHECK
+#define X509_V_FLAG_CRL_CHECK_ALL WOLFSSL_CRL_CHECKALL
+
+#define X509_V_FLAG_USE_CHECK_TIME WOLFSSL_USE_CHECK_TIME
+#define X509_V_FLAG_NO_CHECK_TIME  WOLFSSL_NO_CHECK_TIME
+#define X509_CHECK_FLAG_NO_WILDCARDS WOLFSSL_NO_WILDCARDS
+
+#define X509_STORE_CTX_get_current_cert wolfSSL_X509_STORE_CTX_get_current_cert
+#define X509_STORE_CTX_set_verify_cb    wolfSSL_X509_STORE_CTX_set_verify_cb
+#define X509_STORE_CTX_new              wolfSSL_X509_STORE_CTX_new
+#define X509_STORE_CTX_free             wolfSSL_X509_STORE_CTX_free
+#define X509_STORE_CTX_get_chain        wolfSSL_X509_STORE_CTX_get_chain
+#define X509_STORE_CTX_get_error        wolfSSL_X509_STORE_CTX_get_error
+#define X509_STORE_CTX_get_error_depth  wolfSSL_X509_STORE_CTX_get_error_depth
+#define X509_STORE_CTX_init             wolfSSL_X509_STORE_CTX_init
+#define X509_STORE_CTX_cleanup          wolfSSL_X509_STORE_CTX_cleanup
+#define X509_STORE_CTX_set_error        wolfSSL_X509_STORE_CTX_set_error
+#define X509_STORE_CTX_get_ex_data      wolfSSL_X509_STORE_CTX_get_ex_data
+ 
+#define X509_STORE_new                  wolfSSL_X509_STORE_new
+#define X509_STORE_free                 wolfSSL_X509_STORE_free
+#define X509_STORE_add_lookup           wolfSSL_X509_STORE_add_lookup
+#define X509_STORE_add_cert             wolfSSL_X509_STORE_add_cert
+#define X509_STORE_add_crl              wolfSSL_X509_STORE_add_crl
+#define X509_STORE_set_flags            wolfSSL_X509_STORE_set_flags
+#define X509_STORE_get1_certs           wolfSSL_X509_STORE_get1_certs
+#define X509_STORE_get_by_subject       wolfSSL_X509_STORE_get_by_subject
+#define X509_STORE_CTX_get1_issuer      wolfSSL_X509_STORE_CTX_get1_issuer
+#define X509_STORE_CTX_set_time         wolfSSL_X509_STORE_CTX_set_time
+
+#define X509_LOOKUP_add_dir             wolfSSL_X509_LOOKUP_add_dir
+#define X509_LOOKUP_load_file           wolfSSL_X509_LOOKUP_load_file
+#define X509_LOOKUP_hash_dir            wolfSSL_X509_LOOKUP_hash_dir
+#define X509_LOOKUP_file                wolfSSL_X509_LOOKUP_file
+ 
+#define d2i_X509_CRL                    wolfSSL_d2i_X509_CRL
+#define d2i_X509_CRL_fp                 wolfSSL_d2i_X509_CRL_fp
+#define PEM_read_X509_CRL               wolfSSL_PEM_read_X509_CRL
+ 
+#define X509_CRL_free                   wolfSSL_X509_CRL_free
+#define X509_CRL_get_lastUpdate         wolfSSL_X509_CRL_get_lastUpdate
+#define X509_CRL_get_nextUpdate         wolfSSL_X509_CRL_get_nextUpdate
+#define X509_CRL_verify                 wolfSSL_X509_CRL_verify
+#define X509_CRL_get_REVOKED            wolfSSL_X509_CRL_get_REVOKED
+
+#define sk_X509_REVOKED_num             wolfSSL_sk_X509_REVOKED_num
+#define sk_X509_REVOKED_value           wolfSSL_sk_X509_REVOKED_value
+
+#define X509_OBJECT_free_contents       wolfSSL_X509_OBJECT_free_contents
 
 #define OCSP_parse_url wolfSSL_OCSP_parse_url
-#define SSLv23_client_method wolfSSLv23_client_method
-#define SSLv2_client_method wolfSSLv2_client_method
-#define SSLv2_server_method wolfSSLv2_server_method
 
 #define MD4_Init wolfSSL_MD4_Init
@@ -260,6 +440,4 @@
 #define BIO_set_flags wolfSSL_BIO_set_flags
 
-#define OpenSSL_add_all_digests()
-#define OpenSSL_add_all_algorithms wolfSSL_add_all_algorithms
 #define SSLeay_add_ssl_algorithms  wolfSSL_add_all_algorithms
 #define SSLeay_add_all_algorithms  wolfSSL_add_all_algorithms
@@ -271,5 +449,10 @@
 #define RAND_egd        wolfSSL_RAND_egd
 #define RAND_seed       wolfSSL_RAND_seed
+#define RAND_cleanup                    wolfSSL_RAND_Cleanup
 #define RAND_add        wolfSSL_RAND_add
+#define RAND_poll                       wolfSSL_RAND_poll
+#define RAND_status                     wolfSSL_RAND_status
+#define RAND_bytes                      wolfSSL_RAND_bytes
+#define RAND_pseudo_bytes               wolfSSL_RAND_pseudo_bytes
 
 #define COMP_zlib                       wolfSSL_COMP_zlib
@@ -279,68 +462,34 @@
 #define SSL_get_ex_new_index wolfSSL_get_ex_new_index
 
-#define CRYPTO_set_id_callback wolfSSL_set_id_callback
-#define CRYPTO_set_locking_callback wolfSSL_set_locking_callback
-#define CRYPTO_set_dynlock_create_callback wolfSSL_set_dynlock_create_callback
-#define CRYPTO_set_dynlock_lock_callback wolfSSL_set_dynlock_lock_callback
-#define CRYPTO_set_dynlock_destroy_callback wolfSSL_set_dynlock_destroy_callback
-#define CRYPTO_num_locks wolfSSL_num_locks
-
-
-#define CRYPTO_LOCK             1
-#define CRYPTO_UNLOCK           2
-#define CRYPTO_READ             4
-#define CRYPTO_WRITE            8
-
-#define X509_STORE_CTX_get_current_cert wolfSSL_X509_STORE_CTX_get_current_cert
-#define X509_STORE_add_cert             wolfSSL_X509_STORE_add_cert
-#define X509_STORE_set_flags            wolfSSL_X509_STORE_set_flags
-#define X509_STORE_CTX_get_chain        wolfSSL_X509_STORE_CTX_get_chain
-#define X509_STORE_CTX_get_error wolfSSL_X509_STORE_CTX_get_error
-#define X509_STORE_CTX_get_error_depth wolfSSL_X509_STORE_CTX_get_error_depth
-
-#define X509_NAME_oneline             wolfSSL_X509_NAME_oneline
-#define X509_get_issuer_name          wolfSSL_X509_get_issuer_name
-#define X509_get_subject_name         wolfSSL_X509_get_subject_name
-#define X509_verify_cert_error_string wolfSSL_X509_verify_cert_error_string
-
-#define X509_LOOKUP_add_dir wolfSSL_X509_LOOKUP_add_dir
-#define X509_LOOKUP_load_file wolfSSL_X509_LOOKUP_load_file
-#define X509_LOOKUP_hash_dir wolfSSL_X509_LOOKUP_hash_dir
-#define X509_LOOKUP_file wolfSSL_X509_LOOKUP_file
-
-#define X509_STORE_add_lookup wolfSSL_X509_STORE_add_lookup
-#define X509_STORE_new wolfSSL_X509_STORE_new
-#define X509_STORE_get_by_subject wolfSSL_X509_STORE_get_by_subject
-#define X509_STORE_CTX_init wolfSSL_X509_STORE_CTX_init
-#define X509_STORE_CTX_cleanup wolfSSL_X509_STORE_CTX_cleanup
-
-#define X509_CRL_get_lastUpdate wolfSSL_X509_CRL_get_lastUpdate
-#define X509_CRL_get_nextUpdate wolfSSL_X509_CRL_get_nextUpdate
-
-#define X509_get_pubkey           wolfSSL_X509_get_pubkey
-#define X509_CRL_verify           wolfSSL_X509_CRL_verify
-#define X509_STORE_CTX_set_error  wolfSSL_X509_STORE_CTX_set_error
-#define X509_OBJECT_free_contents wolfSSL_X509_OBJECT_free_contents
-#define EVP_PKEY_new              wolfSSL_PKEY_new
-#define EVP_PKEY_free             wolfSSL_EVP_PKEY_free
-#define EVP_PKEY_type             wolfSSL_EVP_PKEY_type
-#define EVP_PKEY_base_id          wolfSSL_EVP_PKEY_base_id
-#define X509_cmp_current_time     wolfSSL_X509_cmp_current_time
-#define sk_X509_REVOKED_num       wolfSSL_sk_X509_REVOKED_num
-#define X509_CRL_get_REVOKED      wolfSSL_X509_CRL_get_REVOKED
-#define sk_X509_REVOKED_value     wolfSSL_sk_X509_REVOKED_value
-#define X509_get_notBefore(cert)  (ASN1_TIME*)wolfSSL_X509_notBefore((cert))
-#define X509_get_notAfter(cert)   (ASN1_TIME*)wolfSSL_X509_notAfter((cert))
-
-
-#define X509_get_serialNumber wolfSSL_X509_get_serialNumber
-
+
+typedef WOLFSSL_ASN1_BIT_STRING    ASN1_BIT_STRING;
+
+#define ASN1_TIME_adj                   wolfSSL_ASN1_TIME_adj
 #define ASN1_TIME_print              wolfSSL_ASN1_TIME_print
+#define ASN1_TIME_to_generalizedtime    wolfSSL_ASN1_TIME_to_generalizedtime
 #define ASN1_GENERALIZEDTIME_print   wolfSSL_ASN1_GENERALIZEDTIME_print
-
+#define ASN1_GENERALIZEDTIME_free       wolfSSL_ASN1_GENERALIZEDTIME_free
+
+#define ASN1_tag2str                    wolfSSL_ASN1_tag2str
+
+#define i2a_ASN1_INTEGER                wolfSSL_i2a_ASN1_INTEGER
+#define i2c_ASN1_INTEGER                wolfSSL_i2c_ASN1_INTEGER
+#define ASN1_INTEGER_new                wolfSSL_ASN1_INTEGER_new
+#define ASN1_INTEGER_free               wolfSSL_ASN1_INTEGER_free
 #define ASN1_INTEGER_cmp wolfSSL_ASN1_INTEGER_cmp
 #define ASN1_INTEGER_get wolfSSL_ASN1_INTEGER_get
 #define ASN1_INTEGER_to_BN wolfSSL_ASN1_INTEGER_to_BN
+
+#define ASN1_STRING_data                wolfSSL_ASN1_STRING_data
+#define ASN1_STRING_get0_data           wolfSSL_ASN1_STRING_data
+#define ASN1_STRING_length              wolfSSL_ASN1_STRING_length
 #define ASN1_STRING_to_UTF8 wolfSSL_ASN1_STRING_to_UTF8
+#define ASN1_STRING_print_ex            wolfSSL_ASN1_STRING_print_ex
+
+#define ASN1_UTCTIME_pr                 wolfSSL_ASN1_UTCTIME_pr
+
+#define ASN1_IA5STRING                  WOLFSSL_ASN1_STRING
+
+#define ASN1_OCTET_STRING               WOLFSSL_ASN1_STRING
 
 #define SSL_load_client_CA_file wolfSSL_load_client_CA_file
@@ -350,5 +499,4 @@
 #define SSL_CTX_set_cert_store             wolfSSL_CTX_set_cert_store
 #define SSL_CTX_get_cert_store             wolfSSL_CTX_get_cert_store
-#define X509_STORE_CTX_get_ex_data         wolfSSL_X509_STORE_CTX_get_ex_data
 #define SSL_get_ex_data_X509_STORE_CTX_idx wolfSSL_get_ex_data_X509_STORE_CTX_idx
 #define SSL_get_ex_data wolfSSL_get_ex_data
@@ -357,11 +505,8 @@
 #define SSL_CTX_set_default_passwd_cb wolfSSL_CTX_set_default_passwd_cb
 
-#define SSL_CTX_set_timeout(ctx, to) wolfSSL_CTX_set_timeout(ctx, (unsigned int) to)
+#define SSL_CTX_set_timeout(ctx, to)    \
+                                 wolfSSL_CTX_set_timeout(ctx, (unsigned int) to)
 #define SSL_CTX_set_info_callback wolfSSL_CTX_set_info_callback
-
-#define ERR_peek_error wolfSSL_ERR_peek_error
-#define ERR_peek_last_error_line  wolfSSL_ERR_peek_last_error_line
-#define ERR_peek_errors_fp         wolfSSL_ERR_peek_errors_fp
-#define ERR_GET_REASON wolfSSL_ERR_GET_REASON
+#define SSL_CTX_set_alpn_protos         wolfSSL_CTX_set_alpn_protos
 
 #define SSL_alert_type_string wolfSSL_alert_type_string
@@ -391,5 +536,4 @@
 
 #define SSL_DEFAULT_CIPHER_LIST WOLFSSL_DEFAULT_CIPHER_LIST
-#define RSA_F4 WOLFSSL_RSA_F4
 
 #define SSL_CTX_set_psk_client_callback wolfSSL_CTX_set_psk_client_callback
@@ -405,20 +549,51 @@
 #define SSL_set_psk_server_callback wolfSSL_set_psk_server_callback
 
-#define ERR_get_error_line_data wolfSSL_ERR_get_error_line_data
-
+/* system file ints for ERR_put_error */
+#define SYS_F_ACCEPT      WOLFSSL_SYS_ACCEPT
+#define SYS_F_BIND        WOLFSSL_SYS_BIND
+#define SYS_F_CONNECT     WOLFSSL_SYS_CONNECT
+#define SYS_F_FOPEN       WOLFSSL_SYS_FOPEN
+#define SYS_F_FREAD       WOLFSSL_SYS_FREAD
+#define SYS_F_GETADDRINFO WOLFSSL_SYS_GETADDRINFO
+#define SYS_F_GETSOCKOPT  WOLFSSL_SYS_GETSOCKOPT
+#define SYS_F_GETSOCKNAME WOLFSSL_SYS_GETSOCKNAME
+#define SYS_F_OPENDIR     WOLFSSL_SYS_OPENDIR
+#define SYS_F_SETSOCKOPT  WOLFSSL_SYS_SETSOCKOPT
+#define SYS_F_SOCKET      WOLFSSL_SYS_SOCKET
+#define SYS_F_GETHOSTBYNAME  WOLFSSL_SYS_GETHOSTBYNAME
+#define SYS_F_GETNAMEINFO    WOLFSSL_SYS_GETNAMEINFO
+#define SYS_F_GETSERVBYNAME  WOLFSSL_SYS_GETSERVBYNAME
+#define SYS_F_IOCTLSOCKET    WOLFSSL_SYS_IOCTLSOCKET
+#define SYS_F_LISTEN         WOLFSSL_SYS_LISTEN
+
+#define ERR_GET_REASON                  wolfSSL_ERR_GET_REASON
+
+#define ERR_put_error                   wolfSSL_ERR_put_error
+#define ERR_peek_error                  wolfSSL_ERR_peek_error
+#define ERR_peek_errors_fp              wolfSSL_ERR_peek_errors_fp
+#define ERR_peek_error_line_data        wolfSSL_ERR_peek_error_line_data
+#define ERR_peek_last_error             wolfSSL_ERR_peek_last_error
+#define ERR_peek_last_error_line        wolfSSL_ERR_peek_last_error_line
+#define ERR_get_error_line              wolfSSL_ERR_get_error_line
+#define ERR_get_error_line_data         wolfSSL_ERR_get_error_line_data
 #define ERR_get_error wolfSSL_ERR_get_error
+#define ERR_print_errors_fp(file)       wolfSSL_ERR_dump_errors_fp((file))
 #define ERR_clear_error wolfSSL_ERR_clear_error
-
-#define RAND_status wolfSSL_RAND_status
-#define RAND_bytes wolfSSL_RAND_bytes
+#define ERR_free_strings                wolfSSL_ERR_free_strings
+#define ERR_remove_state                wolfSSL_ERR_remove_state
+#define ERR_remove_thread_state         wolfSSL_ERR_remove_thread_state
+#define ERR_error_string                wolfSSL_ERR_error_string
+#define ERR_error_string_n              wolfSSL_ERR_error_string_n
+#define ERR_reason_error_string         wolfSSL_ERR_reason_error_string
+#define ERR_load_BIO_strings            wolfSSL_ERR_load_BIO_strings
+
 #define SSLv23_server_method wolfSSLv23_server_method
 #define SSL_CTX_set_options wolfSSL_CTX_set_options
-#define SSL_CTX_check_private_key wolfSSL_CTX_check_private_key
-
-#define ERR_free_strings wolfSSL_ERR_free_strings
-#define ERR_remove_state wolfSSL_ERR_remove_state
-#define EVP_cleanup wolfSSL_EVP_cleanup
-
-#define CRYPTO_cleanup_all_ex_data wolfSSL_cleanup_all_ex_data
+#define SSL_CTX_get_options             wolfSSL_CTX_get_options
+#define SSL_CTX_clear_options           wolfSSL_CTX_clear_options
+
+#define SSL_CTX_check_private_key       wolfSSL_CTX_check_private_key
+#define SSL_check_private_key           wolfSSL_check_private_key
+
 #define SSL_CTX_set_mode wolfSSL_CTX_set_mode
 #define SSL_CTX_get_mode wolfSSL_CTX_get_mode
@@ -430,4 +605,5 @@
 #define SSL_CTX_set_session_id_context wolfSSL_CTX_set_session_id_context
 #define SSL_get_peer_certificate wolfSSL_get_peer_certificate
+#define SSL_get_peer_cert_chain         wolfSSL_get_peer_cert_chain
 
 #define SSL_want_read wolfSSL_want_read
@@ -435,11 +611,15 @@
 
 #define BIO_prf wolfSSL_BIO_prf
-#define ASN1_UTCTIME_pr wolfSSL_ASN1_UTCTIME_pr
 
 #define sk_num wolfSSL_sk_num
 #define sk_value wolfSSL_sk_value
-#define sk_X509_pop  wolfSSL_sk_X509_pop
-#define sk_X509_free wolfSSL_sk_X509_free
-#define d2i_X509_bio wolfSSL_d2i_X509_bio
+
+#define d2i_PKCS12_bio                  wolfSSL_d2i_PKCS12_bio
+#define d2i_PKCS12_fp                   wolfSSL_d2i_PKCS12_fp
+
+#define d2i_RSAPublicKey                wolfSSL_d2i_RSAPublicKey
+#define d2i_RSAPrivateKey               wolfSSL_d2i_RSAPrivateKey
+#define i2d_RSAPrivateKey               wolfSSL_i2d_RSAPrivateKey
+#define i2d_RSAPublicKey                wolfSSL_i2d_RSAPublicKey
 
 #define SSL_CTX_get_ex_data wolfSSL_CTX_get_ex_data
@@ -455,6 +635,8 @@
 #define SSL_SESSION_get_time wolfSSL_SESSION_get_time
 #define SSL_CTX_get_ex_new_index wolfSSL_CTX_get_ex_new_index
-#define PEM_read_bio_X509 wolfSSL_PEM_read_bio_X509
-#define PEM_read_bio_X509_AUX wolfSSL_PEM_read_bio_X509_AUX
+#define PEM_read                        wolfSSL_PEM_read
+#define PEM_write                       wolfSSL_PEM_write
+#define PEM_get_EVP_CIPHER_INFO         wolfSSL_PEM_get_EVP_CIPHER_INFO
+#define PEM_do_header                   wolfSSL_PEM_do_header
 
 /*#if OPENSSL_API_COMPAT < 0x10100000L*/
@@ -467,4 +649,5 @@
 #define SSL_set_tmp_rsa(ssl,rsa)             1
 /*#endif*/
+
 #define CONF_modules_unload(a)
 
@@ -474,45 +657,26 @@
 #define SSL_get_default_timeout(ctx) 500
 
-/* Lighthttp compatibility */
-
-#if defined(HAVE_LIGHTY)  || defined(WOLFSSL_MYSQL_COMPATIBLE) || \
-    defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \
-    defined(HAVE_POCO_LIB) || defined(WOLFSSL_HAPROXY)
-typedef WOLFSSL_X509_NAME_ENTRY X509_NAME_ENTRY;
-
-#define X509_NAME_free wolfSSL_X509_NAME_free
 #define SSL_CTX_use_certificate wolfSSL_CTX_use_certificate
 #define SSL_CTX_use_PrivateKey wolfSSL_CTX_use_PrivateKey
 #define BIO_read_filename wolfSSL_BIO_read_filename
 #define BIO_s_file wolfSSL_BIO_s_file
-#define OBJ_nid2sn wolfSSL_OBJ_nid2sn
-#define OBJ_obj2nid wolfSSL_OBJ_obj2nid
-#define OBJ_sn2nid wolfSSL_OBJ_sn2nid
 #define SSL_CTX_set_verify_depth wolfSSL_CTX_set_verify_depth
 #define SSL_set_verify_depth wolfSSL_set_verify_depth
 #define SSL_get_app_data wolfSSL_get_app_data
 #define SSL_set_app_data wolfSSL_set_app_data
-#define X509_NAME_entry_count wolfSSL_X509_NAME_entry_count
-#define X509_NAME_ENTRY_get_object wolfSSL_X509_NAME_ENTRY_get_object
-#define X509_NAME_get_entry wolfSSL_X509_NAME_get_entry
-#define ASN1_STRING_data wolfSSL_ASN1_STRING_data
-#define ASN1_STRING_length wolfSSL_ASN1_STRING_length
-#define X509_NAME_get_index_by_NID wolfSSL_X509_NAME_get_index_by_NID
-#define X509_NAME_ENTRY_get_data wolfSSL_X509_NAME_ENTRY_get_data
-#define sk_X509_NAME_pop_free  wolfSSL_sk_X509_NAME_pop_free
 #define SHA1 wolfSSL_SHA1
-#define X509_check_private_key wolfSSL_X509_check_private_key
+
 #define SSL_dup_CA_list wolfSSL_dup_CA_list
 
-#define NID_commonName 0x03 /* matchs ASN_COMMON_NAME in asn.h */
-
-#define OBJ_nid2ln wolfSSL_OBJ_nid2ln
-#define OBJ_txt2nid wolfSSL_OBJ_txt2nid
+enum {
+    GEN_DNS   = 0x02, /* ASN_DNS_TYPE */
+    GEN_EMAIL = 0x01, /* ASN_RFC822_TYPE */
+    GEN_URI   = 0x06  /* ASN_URI_TYPE */
+};
+
 #define PEM_read_bio_DHparams wolfSSL_PEM_read_bio_DHparams
 #define PEM_read_bio_DSAparams wolfSSL_PEM_read_bio_DSAparams
-#define PEM_write_bio_X509 wolfSSL_PEM_write_bio_X509
-
-
-#ifdef WOLFSSL_HAPROXY
+
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY)
 #define SSL_get_rbio                      wolfSSL_SSL_get_rbio
 #define SSL_get_wbio                      wolfSSL_SSL_get_wbio
@@ -520,11 +684,41 @@
 #define SSL_get_ciphers(x)                wolfSSL_get_ciphers_compat(x)
 #define SSL_SESSION_get_id                wolfSSL_SESSION_get_id
-#define ASN1_STRING_get0_data             wolfSSL_ASN1_STRING_data
-#define SSL_get_cipher_bits(s,np)         wolfSSL_CIPHER_get_bits(SSL_get_current_cipher(s),np)
+#define SSL_get_cipher_bits(s,np)       \
+                          wolfSSL_CIPHER_get_bits(SSL_get_current_cipher(s),np)
 #define sk_SSL_CIPHER_num                 wolfSSL_sk_SSL_CIPHER_num
 #define sk_SSL_COMP_zero                  wolfSSL_sk_SSL_COMP_zero
 #define sk_SSL_CIPHER_value               wolfSSL_sk_SSL_CIPHER_value
-#endif /* WOLFSSL_HAPROXY */
-#endif /* HAVE_STUNNEL || HAVE_LIGHTY || WOLFSSL_MYSQL_COMPATIBLE || WOLFSSL_NGINX || HAVE_POCO_LIB || WOLFSSL_HAPROXY */
+#endif /* OPENSSL_ALL || WOLFSSL_HAPROXY */
+
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO)
+#include <wolfssl/openssl/pem.h>
+
+typedef STACK_OF(WOLFSSL_ASN1_OBJECT) GENERAL_NAMES;
+#define SSL_CTRL_CHAIN       88
+#define BIO_CTRL_WPENDING    13
+#define GEN_IPADD            7
+#define ERR_LIB_SSL          20
+#define SSL_R_SHORT_READ     10
+#define ERR_R_PEM_LIB        9
+#define V_ASN1_IA5STRING     22
+#define SSL_CTRL_MODE        33       
+
+#define SSL_CTX_clear_chain_certs(ctx) SSL_CTX_set0_chain(ctx,NULL)
+#define d2i_RSAPrivateKey_bio           wolfSSL_d2i_RSAPrivateKey_bio
+#define SSL_CTX_use_RSAPrivateKey       wolfSSL_CTX_use_RSAPrivateKey
+#define d2i_PrivateKey_bio              wolfSSL_d2i_PrivateKey_bio
+#define BIO_new_bio_pair                wolfSSL_BIO_new_bio_pair
+#define SSL_get_verify_callback         wolfSSL_get_verify_callback
+#define GENERAL_NAMES_free(GENERAL_NAMES)NULL
+
+#define SSL_set_mode(ssl,op)         wolfSSL_ctrl((ssl),SSL_CTRL_MODE,(op),NULL)
+
+#define SSL_CTX_use_certificate_ASN1    wolfSSL_CTX_use_certificate_ASN1
+#define SSL_CTX_set0_chain(ctx,sk) \
+                             wolfSSL_CTX_ctrl(ctx,SSL_CTRL_CHAIN,0,(char *)(sk))
+#define SSL_CTX_get_app_data(ctx)       wolfSSL_CTX_get_ex_data(ctx,0)
+#define SSL_CTX_set_app_data(ctx,arg)   wolfSSL_CTX_set_ex_data(ctx,0, \
+                                                                  (char *)(arg))
+#endif /* OPENSSL_ALL || WOLFSSL_ASIO */
 
 #define SSL_CTX_set_tmp_dh wolfSSL_CTX_set_tmp_dh
@@ -533,4 +727,5 @@
 #define BIO_ctrl            wolfSSL_BIO_ctrl
 #define BIO_ctrl_pending    wolfSSL_BIO_ctrl_pending
+#define BIO_wpending                    wolfSSL_BIO_wpending
 #define BIO_get_mem_ptr     wolfSSL_BIO_get_mem_ptr
 #define BIO_int_ctrl        wolfSSL_BIO_int_ctrl
@@ -551,6 +746,9 @@
 #define BIO_set_mem_eof_return wolfSSL_BIO_set_mem_eof_return
 
+#define TLSEXT_STATUSTYPE_ocsp  1
+
 #define SSL_set_options      wolfSSL_set_options
 #define SSL_get_options      wolfSSL_get_options
+#define SSL_clear_options               wolfSSL_clear_options
 #define SSL_set_tmp_dh       wolfSSL_set_tmp_dh
 #define SSL_clear_num_renegotiations    wolfSSL_clear_num_renegotiations
@@ -561,6 +759,8 @@
 #define SSL_get_tlsext_status_ids       wolfSSL_get_tlsext_status_ids
 #define SSL_set_tlsext_status_ids       wolfSSL_set_tlsext_status_ids
-#define SSL_get_tlsext_status_ocsp_resp wolfSSL_get_tlsext_status_ocsp_resp
+#define SSL_get_tlsext_status_ocsp_res  wolfSSL_get_tlsext_status_ocsp_resp
+#define SSL_set_tlsext_status_ocsp_res  wolfSSL_set_tlsext_status_ocsp_resp
 #define SSL_set_tlsext_status_ocsp_resp wolfSSL_set_tlsext_status_ocsp_resp
+#define SSL_get_tlsext_status_ocsp_resp  wolfSSL_get_tlsext_status_ocsp_resp
 
 #define SSL_CTX_add_extra_chain_cert wolfSSL_CTX_add_extra_chain_cert
@@ -615,8 +815,7 @@
 #define SSL_CTX_ctrl wolfSSL_CTX_ctrl
 
-#define X509_V_FLAG_CRL_CHECK     WOLFSSL_CRL_CHECK
-#define X509_V_FLAG_CRL_CHECK_ALL WOLFSSL_CRL_CHECKALL
-
-#if defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX)
+#define SSL3_RANDOM_SIZE                32 /* same as RAN_LEN in internal.h */
+#if defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || defined(OPENSSL_EXTRA) \
+                                                         || defined(OPENSSL_ALL)
 #include <wolfssl/openssl/asn1.h>
 
@@ -628,5 +827,4 @@
 #define SSL3_ST_SR_CLNT_HELLO_A         (0x110|0x2000)
 #define ASN1_STRFLGS_ESC_MSB             4
-#define X509_V_ERR_CERT_REJECTED         28
 
 #define SSL_MAX_MASTER_KEY_LENGTH        WOLFSSL_MAX_MASTER_KEY_LENGTH
@@ -635,28 +833,22 @@
 #define SSL_alert_type_string_long       wolfSSL_alert_type_string_long
 #define SSL_CIPHER_get_bits              wolfSSL_CIPHER_get_bits
-#define sk_X509_NAME_num                 wolfSSL_sk_X509_NAME_num
-#define sk_X509_num                      wolfSSL_sk_X509_num
-#define X509_NAME_print_ex               wolfSSL_X509_NAME_print_ex
-#define X509_get0_pubkey_bitstr          wolfSSL_X509_get0_pubkey_bitstr
+#define sk_GENERAL_NAME_num             wolfSSL_sk_GENERAL_NAME_num
 #define SSL_CTX_get_options              wolfSSL_CTX_get_options
 
 #define SSL_CTX_flush_sessions           wolfSSL_flush_sessions
 #define SSL_CTX_add_session              wolfSSL_CTX_add_session
-#define SSL_get_SSL_CTX                  wolfSSL_get_SSL_CTX
 #define SSL_version                      wolfSSL_version
 #define SSL_get_state                    wolfSSL_get_state
 #define SSL_state_string_long            wolfSSL_state_string_long
-#define SSL_get_peer_cert_chain          wolfSSL_get_peer_cert_chain
-#define sk_X509_NAME_value               wolfSSL_sk_X509_NAME_value
-#define sk_X509_value                    wolfSSL_sk_X509_value
+
+#define sk_GENERAL_NAME_value           wolfSSL_sk_GENERAL_NAME_value
 #define SSL_SESSION_get_ex_data          wolfSSL_SESSION_get_ex_data
 #define SSL_SESSION_set_ex_data          wolfSSL_SESSION_set_ex_data
 #define SSL_SESSION_get_ex_new_index     wolfSSL_SESSION_get_ex_new_index
 #define SSL_SESSION_get_id               wolfSSL_SESSION_get_id
-#define CRYPTO_dynlock_value             WOLFSSL_dynlock_value
-typedef WOLFSSL_ASN1_BIT_STRING    ASN1_BIT_STRING;
-#define X509_STORE_get1_certs            wolfSSL_X509_STORE_get1_certs
-#define sk_X509_pop_free                 wolfSSL_sk_X509_pop_free
-
+#define sk_GENERAL_NAME_pop_free        wolfSSL_sk_GENERAL_NAME_pop_free
+#define GENERAL_NAME_free               NULL
+
+#define SSL3_AL_FATAL                   2
 #define SSL_TLSEXT_ERR_OK                    0
 #define SSL_TLSEXT_ERR_ALERT_FATAL           alert_fatal
@@ -673,5 +865,4 @@
 #define PSK_MAX_PSK_LEN                      256
 #define PSK_MAX_IDENTITY_LEN                 128
-#define ERR_remove_thread_state WOLFSSL_ERR_remove_thread_state
 #define SSL_CTX_clear_options wolfSSL_CTX_clear_options
 
@@ -680,23 +871,4 @@
 #define SSL_CTX_get_default_passwd_cb          wolfSSL_CTX_get_default_passwd_cb
 #define SSL_CTX_get_default_passwd_cb_userdata wolfSSL_CTX_get_default_passwd_cb_userdata
-
-/* certificate extension NIDs */
-#define NID_basic_constraints         133
-#define NID_key_usage                 129  /* 2.5.29.15 */
-#define NID_ext_key_usage             151  /* 2.5.29.37 */
-#define NID_subject_key_identifier    128
-#define NID_authority_key_identifier  149
-#define NID_private_key_usage_period  130  /* 2.5.29.16 */
-#define NID_subject_alt_name          131
-#define NID_issuer_alt_name           132
-#define NID_info_access               69
-#define NID_sinfo_access              79  /* id-pe 11 */
-#define NID_name_constraints          144 /* 2.5.29.30 */
-#define NID_certificate_policies      146
-#define NID_policy_mappings           147
-#define NID_policy_constraints        150
-#define NID_inhibit_any_policy        168 /* 2.5.29.54 */
-#define NID_tlsfeature                92  /* id-pe 24 */
-
 
 #define SSL_CTX_set_msg_callback        wolfSSL_CTX_set_msg_callback
@@ -705,25 +877,17 @@
 #define SSL_set_msg_callback_arg        wolfSSL_set_msg_callback_arg
 
-/* certificate extension NIDs */
-#define NID_basic_constraints         133
-#define NID_key_usage                 129  /* 2.5.29.15 */
-#define NID_ext_key_usage             151  /* 2.5.29.37 */
-#define NID_subject_key_identifier    128
-#define NID_authority_key_identifier  149
-#define NID_private_key_usage_period  130  /* 2.5.29.16 */
-#define NID_subject_alt_name          131
-#define NID_issuer_alt_name           132
-#define NID_info_access               69
-#define NID_sinfo_access              79  /* id-pe 11 */
-#define NID_name_constraints          144 /* 2.5.29.30 */
-#define NID_certificate_policies      146
-#define NID_policy_mappings           147
-#define NID_policy_constraints        150
-#define NID_inhibit_any_policy        168 /* 2.5.29.54 */
-#define NID_tlsfeature                92  /* id-pe 24 */
-
+
+/* Nginx uses this to determine if reached end of certs in file.
+ * PEM_read_bio_X509 is called and the return error is lost.
+ * The error that needs to be detected is: SSL_NO_PEM_HEADER.
+ */
+#define ERR_GET_LIB(l)  (int)((((unsigned long)l)>>24L)&0xffL)
+#define PEM_R_NO_START_LINE     108
+#define ERR_LIB_PEM             9
+#define ERR_LIB_X509            10
 
 #if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \
-    defined(WOLFSSL_MYSQL_COMPATIBLE)
+    defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(OPENSSL_ALL) || \
+    defined(HAVE_LIGHTY)
 
 #include <wolfssl/error-ssl.h>
@@ -754,12 +918,8 @@
 #define SSL_R_WRONG_VERSION_NUMBER                 VERSION_ERROR
 #define SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC  ENCRYPT_ERROR
-
-/* Nginx uses this to determine if reached end of certs in file.
- * PEM_read_bio_X509 is called and the return error is lost.
- * The error that needs to be detected is: SSL_NO_PEM_HEADER.
- */
-#define ERR_GET_LIB(l)  (int)((((unsigned long)l)>>24L)&0xffL)
-#define PEM_R_NO_START_LINE     108
-#define ERR_LIB_PEM             9
+#define SSL_R_HTTPS_PROXY_REQUEST                  PARSE_ERROR
+#define SSL_R_HTTP_REQUEST                         PARSE_ERROR
+#define SSL_R_UNSUPPORTED_PROTOCOL                 VERSION_ERROR
+
 
 #ifdef HAVE_SESSION_TICKET
@@ -769,8 +929,5 @@
 
 #define OPENSSL_config	                  wolfSSL_OPENSSL_config
-#define X509_get_ex_new_index             wolfSSL_X509_get_ex_new_index
-#define X509_get_ex_data                  wolfSSL_X509_get_ex_data
-#define X509_set_ex_data                  wolfSSL_X509_set_ex_data
-#define X509_NAME_digest                  wolfSSL_X509_NAME_digest
+#define OPENSSL_memdup                  wolfSSL_OPENSSL_memdup
 #define SSL_CTX_get_timeout               wolfSSL_SSL_CTX_get_timeout
 #define SSL_CTX_set_tmp_ecdh              wolfSSL_SSL_CTX_set_tmp_ecdh
@@ -781,17 +938,7 @@
 #define SSL_in_init                       wolfSSL_SSL_in_init
 #define SSL_get0_session                  wolfSSL_SSL_get0_session
-#define X509_check_host                   wolfSSL_X509_check_host
-#define i2a_ASN1_INTEGER                  wolfSSL_i2a_ASN1_INTEGER
-#define ERR_peek_error_line_data          wolfSSL_ERR_peek_error_line_data
 #define SSL_CTX_set_tlsext_ticket_key_cb  wolfSSL_CTX_set_tlsext_ticket_key_cb
-#define X509_email_free                   wolfSSL_X509_email_free
-#define X509_get1_ocsp                    wolfSSL_X509_get1_ocsp
 #define SSL_CTX_set_tlsext_status_cb      wolfSSL_CTX_set_tlsext_status_cb
-#define X509_check_issued                 wolfSSL_X509_check_issued
-#define X509_dup                          wolfSSL_X509_dup
-#define X509_STORE_CTX_new                wolfSSL_X509_STORE_CTX_new
-#define X509_STORE_CTX_free               wolfSSL_X509_STORE_CTX_free
 #define SSL_CTX_get_extra_chain_certs     wolfSSL_CTX_get_extra_chain_certs
-#define X509_STORE_CTX_get1_issuer        wolfSSL_X509_STORE_CTX_get1_issuer
 #define sk_OPENSSL_STRING_value           wolfSSL_sk_WOLFSSL_STRING_value
 #define SSL_get0_alpn_selected            wolfSSL_get0_alpn_selected
@@ -804,5 +951,25 @@
 #define SSL_CTX_set1_curves_list          wolfSSL_CTX_set1_curves_list
 
-#endif /* WOLFSSL_NGINX || WOLFSSL_HAPROXY */
+#endif /* WOLFSSL_NGINX || WOLFSSL_HAPROXY || WOLFSSL_MYSQL_COMPATIBLE || 
+          OPENSSL_ALL || HAVE_LIGHTY */
+
+#ifdef OPENSSL_EXTRA
+#define SSL_CTX_add_client_CA           wolfSSL_CTX_add_client_CA
+#define SSL_CTX_set_srp_password        wolfSSL_CTX_set_srp_password
+#define SSL_CTX_set_srp_username        wolfSSL_CTX_set_srp_username
+#define SSL_get_SSL_CTX                 wolfSSL_get_SSL_CTX
+
+#define ERR_NUM_ERRORS                  16
+#define EVP_PKEY_RSA                    6 
+#define EVP_PKEY_RSA2                   19
+#define SN_pkcs9_emailAddress           "Email"
+#define LN_pkcs9_emailAddress           "emailAddress"
+#define NID_pkcs9_emailAddress          48
+#define OBJ_pkcs9_emailAddress          1L,2L,840L,113539L,1L,9L,1L
+
+#define SSL_get_rbio                    wolfSSL_SSL_get_rbio
+#define SSL_get_wbio                    wolfSSL_SSL_get_wbio
+#define SSL_do_handshake                wolfSSL_SSL_do_handshake
+#endif  /* OPENSSL_EXTRA */
 
 #ifdef __cplusplus
@@ -810,4 +977,3 @@
 #endif
 
-
 #endif /* wolfSSL_openssl_h__ */
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/ssl.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/ssl.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/ssl.h	(revision 372)
@@ -19,6 +19,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
  */
-
-
+/*!
+    \file ../wolfssl/ssl.h
+    \brief Header file containing key wolfSSL API
+*/
 
 /* wolfSSL API */
@@ -31,4 +33,6 @@
 #include <wolfssl/wolfcrypt/settings.h>
 #include <wolfssl/version.h>
+#include <wolfssl/wolfcrypt/logging.h>
+#include <wolfssl/wolfcrypt/asn_public.h>
 
 #ifdef HAVE_WOLF_EVENT
@@ -84,5 +88,5 @@
     #endif
 
-#elif defined(OPENSSL_EXTRA)
+#elif (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL))
     #include <wolfssl/openssl/bn.h>
     #include <wolfssl/openssl/hmac.h>
@@ -118,8 +122,11 @@
 typedef struct WOLFSSL_X509_NAME_ENTRY  WOLFSSL_X509_NAME_ENTRY;
 typedef struct WOLFSSL_X509_CHAIN WOLFSSL_X509_CHAIN;
+typedef struct WC_PKCS12          WOLFSSL_X509_PKCS12;
 
 typedef struct WOLFSSL_CERT_MANAGER WOLFSSL_CERT_MANAGER;
 typedef struct WOLFSSL_SOCKADDR     WOLFSSL_SOCKADDR;
 typedef struct WOLFSSL_CRL          WOLFSSL_CRL;
+
+typedef void  *WOLFSSL_X509_STORE_CTX_verify_cb; /* verify callback */
 
 /* redeclare guard */
@@ -159,6 +166,7 @@
 typedef struct WOLFSSL_X509_LOOKUP    WOLFSSL_X509_LOOKUP;
 typedef struct WOLFSSL_X509_LOOKUP_METHOD WOLFSSL_X509_LOOKUP_METHOD;
-typedef struct WOLFSSL_X509_CRL       WOLFSSL_X509_CRL;
+typedef struct WOLFSSL_CRL            WOLFSSL_X509_CRL;
 typedef struct WOLFSSL_X509_STORE     WOLFSSL_X509_STORE;
+typedef struct WOLFSSL_X509_VERIFY_PARAM  WOLFSSL_X509_VERIFY_PARAM;
 typedef struct WOLFSSL_BIO            WOLFSSL_BIO;
 typedef struct WOLFSSL_BIO_METHOD     WOLFSSL_BIO_METHOD;
@@ -172,14 +180,19 @@
 typedef struct WOLFSSL_DH               WOLFSSL_DH;
 typedef struct WOLFSSL_ASN1_BIT_STRING  WOLFSSL_ASN1_BIT_STRING;
-typedef unsigned char*                  WOLFSSL_BUF_MEM;
 
 #define WOLFSSL_ASN1_UTCTIME          WOLFSSL_ASN1_TIME
 #define WOLFSSL_ASN1_GENERALIZEDTIME  WOLFSSL_ASN1_TIME
 
+#define WOLFSSL_ASN1_INTEGER_MAX 20
 struct WOLFSSL_ASN1_INTEGER {
     /* size can be increased set at 20 for tag, length then to hold at least 16
      * byte type */
-    unsigned char data[20];
+    unsigned char  intData[WOLFSSL_ASN1_INTEGER_MAX];
     /* ASN_INTEGER | LENGTH | hex of number */
+    unsigned char  negative;   /* negative number flag */
+
+    unsigned char* data;
+    unsigned int   dataMax;   /* max size of data buffer */
+    unsigned int   isDynamic:1; /* flag for if data pointer dynamic (1 is yes 0 is no) */
 };
 
@@ -190,13 +203,89 @@
 };
 
-#ifndef WOLFSSL_EVP_PKEY_TYPE_DEFINED /* guard on redeclaration */
+struct WOLFSSL_ASN1_STRING {
+    int length;
+    int type; /* type of string i.e. CTC_UTF8 */
+    char* data;
+    long flags;
+};
+
+#define WOLFSSL_MAX_SNAME 40
+struct WOLFSSL_ASN1_OBJECT {
+    void*  heap;
+    const unsigned char* obj;
+    /* sName is short name i.e sha256 rather than oid (null terminated) */
+    char   sName[WOLFSSL_MAX_SNAME];
+    int    type; /* oid */
+    int    grp;  /* type of OID, i.e. oidCertPolicyType */
+    int    nid;
+    unsigned int  objSz;
+    unsigned char dynamic; /* if 1 then obj was dynamiclly created, 0 otherwise */
+    #define WOLFSSL_ASN1_DYNAMIC 0x1
+    #define WOLFSSL_ASN1_DYNAMIC_DATA 0x2
+    struct d { /* derefrenced */
+        WOLFSSL_ASN1_STRING  ia5_internal;
+        WOLFSSL_ASN1_STRING* ia5; /* points to ia5_internal */
+        WOLFSSL_ASN1_STRING* dNSName;
+        WOLFSSL_ASN1_STRING* iPAddress;
+    } d;
+};
+
+struct WOLFSSL_EVP_PKEY {
+    void* heap;
+    int type;         /* openssh dereference */
+    int save_type;    /* openssh dereference */
+    int pkey_sz;
+    union {
+        char* ptr; /* der format of key / or raw for NTRU */
+    } pkey;
+    #if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL))
+    #ifndef NO_RSA
+        WOLFSSL_RSA* rsa;
+        byte      ownRsa; /* if struct owns RSA and should free it */
+    #endif
+    #ifdef HAVE_ECC
+        WOLFSSL_EC_KEY* ecc;
+        byte      ownEcc; /* if struct owns ECC and should free it */
+    #endif
+    WC_RNG rng;
+    #endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
+    #ifdef HAVE_ECC
+        int pkey_curve;
+    #endif
+};
+typedef struct WOLFSSL_EVP_PKEY WOLFSSL_PKCS8_PRIV_KEY_INFO;
+
+#ifndef WOLFSSL_EVP_TYPE_DEFINED /* guard on redeclaration */
 typedef struct WOLFSSL_EVP_PKEY     WOLFSSL_EVP_PKEY;
-#define WOLFSSL_EVP_PKEY_TYPE_DEFINED
-#endif
-
-typedef struct WOLFSSL_MD4_CTX {
-    int buffer[32];      /* big enough to hold, check size in Init */
-} WOLFSSL_MD4_CTX;
-
+typedef char   WOLFSSL_EVP_MD;
+#define WOLFSSL_EVP_TYPE_DEFINED
+#endif
+
+#define WOLFSSL_EVP_PKEY_DEFAULT EVP_PKEY_RSA /* default key type */
+
+
+enum BIO_TYPE {
+    WOLFSSL_BIO_BUFFER = 1,
+    WOLFSSL_BIO_SOCKET = 2,
+    WOLFSSL_BIO_SSL    = 3,
+    WOLFSSL_BIO_MEMORY = 4,
+    WOLFSSL_BIO_BIO    = 5,
+    WOLFSSL_BIO_FILE   = 6,
+    WOLFSSL_BIO_BASE64 = 7
+};
+
+enum BIO_FLAGS {
+    WOLFSSL_BIO_FLAG_BASE64_NO_NL = 0x01,
+    WOLFSSL_BIO_FLAG_READ         = 0x02,
+    WOLFSSL_BIO_FLAG_WRITE        = 0x04,
+    WOLFSSL_BIO_FLAG_IO_SPECIAL   = 0x08,
+    WOLFSSL_BIO_FLAG_RETRY        = 0x10
+};
+
+typedef struct WOLFSSL_BUF_MEM {
+    char*  data;   /* dereferenced */
+    size_t length; /* current length */
+    size_t max;    /* maximum length */
+} WOLFSSL_BUF_MEM;
 
 typedef struct WOLFSSL_COMP_METHOD {
@@ -219,5 +308,18 @@
     int                   isDynamic;
 #endif
-};
+#if defined(OPENSSL_EXTRA) && defined(HAVE_CRL)
+    WOLFSSL_X509_CRL *crl;
+#endif
+};
+
+#ifdef OPENSSL_EXTRA
+#define WOLFSSL_USE_CHECK_TIME 0x2
+#define WOLFSSL_NO_CHECK_TIME  0x200000
+#define WOLFSSL_NO_WILDCARDS   0x4
+struct WOLFSSL_X509_VERIFY_PARAM {
+    time_t  check_time;
+    unsigned long flags;
+};
+#endif
 
 typedef struct WOLFSSL_ALERT {
@@ -251,19 +353,29 @@
 typedef struct WOLFSSL_X509_STORE_CTX {
     WOLFSSL_X509_STORE* store;    /* Store full of a CA cert chain */
-    WOLFSSL_X509* current_cert;   /* stunnel dereference */
+    WOLFSSL_X509* current_cert;   /* current X509 (OPENSSL_EXTRA) */
+#ifdef WOLFSSL_ASIO
+    WOLFSSL_X509* current_issuer; /* asio dereference */
+#endif
+    WOLFSSL_X509_CHAIN* sesChain; /* pointer to WOLFSSL_SESSION peer chain */
     WOLFSSL_STACK* chain;
+#ifdef OPENSSL_EXTRA
+    WOLFSSL_X509_VERIFY_PARAM* param; /* certificate validation parameter */
+#endif
     char* domain;                /* subject CN domain name */
     void* ex_data;               /* external data, for fortress build */
     void* userCtx;               /* user ctx */
     int   error;                 /* current error */
-    int   error_depth;           /* cert depth for this error */
+    int   error_depth;           /* index of cert depth for this error */
     int   discardSessionCerts;   /* so verify callback can flag for discard */
     int   totalCerts;            /* number of peer cert buffers */
     WOLFSSL_BUFFER_INFO* certs;  /* peer certs */
+    WOLFSSL_X509_STORE_CTX_verify_cb verify_cb; /* verify callback */
 } WOLFSSL_X509_STORE_CTX;
 
 typedef char* WOLFSSL_STRING;
 
-/* Valid Alert types from page 16/17 */
+/* Valid Alert types from page 16/17
+ * Add alert string to the function wolfSSL_alert_type_string_long in src/ssl.c
+ */
 enum AlertDescription {
     close_notify                    =   0,
@@ -289,6 +401,8 @@
     #endif
     no_renegotiation                = 100,
+    unsupported_extension           = 110, /**< RFC 5246, section 7.2.2 */
     unrecognized_name               = 112, /**< RFC 6066, section 3 */
     bad_certificate_status_response = 113, /**< RFC 6066, section 8 */
+    unknown_psk_identity            = 115, /**< RFC 4279, section 2 */
     no_application_protocol         = 120
 };
@@ -302,34 +416,54 @@
 /* Maximum master key length (SECRET_LEN) */
 #define WOLFSSL_MAX_MASTER_KEY_LENGTH 48
+/* Maximum number of groups that can be set */
+#define WOLFSSL_MAX_GROUP_COUNT       10
 
 typedef WOLFSSL_METHOD* (*wolfSSL_method_func)(void* heap);
+
+/* CTX Method EX Constructor Functions */
 WOLFSSL_API WOLFSSL_METHOD *wolfSSLv3_server_method_ex(void* heap);
 WOLFSSL_API WOLFSSL_METHOD *wolfSSLv3_client_method_ex(void* heap);
+WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_method_ex(void* heap);
 WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_server_method_ex(void* heap);
 WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_client_method_ex(void* heap);
+WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_1_method_ex(void* heap);
 WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_1_server_method_ex(void* heap);
 WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_1_client_method_ex(void* heap);
+WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_2_method_ex(void* heap);
 WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_2_server_method_ex(void* heap);
 WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_2_client_method_ex(void* heap);
 #ifdef WOLFSSL_TLS13
+    WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_3_method_ex(void* heap);
     WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_3_server_method_ex(void* heap);
     WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_3_client_method_ex(void* heap);
 #endif
+
+WOLFSSL_API WOLFSSL_METHOD *wolfSSLv23_method_ex(void* heap);
 WOLFSSL_API WOLFSSL_METHOD *wolfSSLv23_server_method_ex(void* heap);
 WOLFSSL_API WOLFSSL_METHOD *wolfSSLv23_client_method_ex(void* heap);
 
 #ifdef WOLFSSL_DTLS
+    WOLFSSL_API WOLFSSL_METHOD *wolfDTLS_method_ex(void* heap);
+    WOLFSSL_API WOLFSSL_METHOD *wolfDTLS_client_method_ex(void* heap);
+    WOLFSSL_API WOLFSSL_METHOD *wolfDTLS_server_method_ex(void* heap);
+    WOLFSSL_API WOLFSSL_METHOD *wolfDTLSv1_method_ex(void* heap);
     WOLFSSL_API WOLFSSL_METHOD *wolfDTLSv1_client_method_ex(void* heap);
     WOLFSSL_API WOLFSSL_METHOD *wolfDTLSv1_server_method_ex(void* heap);
+    WOLFSSL_API WOLFSSL_METHOD *wolfDTLSv1_2_method_ex(void* heap);
     WOLFSSL_API WOLFSSL_METHOD *wolfDTLSv1_2_client_method_ex(void* heap);
     WOLFSSL_API WOLFSSL_METHOD *wolfDTLSv1_2_server_method_ex(void* heap);
 #endif
+
+/* CTX Method Constructor Functions */
 WOLFSSL_API WOLFSSL_METHOD *wolfSSLv23_method(void);
 WOLFSSL_API WOLFSSL_METHOD *wolfSSLv3_server_method(void);
 WOLFSSL_API WOLFSSL_METHOD *wolfSSLv3_client_method(void);
+WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_method(void);
 WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_server_method(void);
 WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_client_method(void);
+WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_1_method(void);
 WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_1_server_method(void);
 WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_1_client_method(void);
+WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_2_method(void);
 WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_2_server_method(void);
 WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_2_client_method(void);
@@ -340,6 +474,11 @@
 
 #ifdef WOLFSSL_DTLS
+    WOLFSSL_API WOLFSSL_METHOD *wolfDTLS_method(void);
+    WOLFSSL_API WOLFSSL_METHOD *wolfDTLS_server_method(void);
+    WOLFSSL_API WOLFSSL_METHOD *wolfDTLS_client_method(void);
+    WOLFSSL_API WOLFSSL_METHOD *wolfDTLSv1_method(void);
     WOLFSSL_API WOLFSSL_METHOD *wolfDTLSv1_client_method(void);
     WOLFSSL_API WOLFSSL_METHOD *wolfDTLSv1_server_method(void);
+    WOLFSSL_API WOLFSSL_METHOD *wolfDTLSv1_2_method(void);
     WOLFSSL_API WOLFSSL_METHOD *wolfDTLSv1_2_client_method(void);
     WOLFSSL_API WOLFSSL_METHOD *wolfDTLSv1_2_server_method(void);
@@ -352,6 +491,11 @@
 #ifdef WOLFSSL_SESSION_EXPORT
 #ifdef WOLFSSL_DTLS
+
+#ifndef WOLFSSL_DTLS_EXPORT_TYPES
 typedef int (*wc_dtls_export)(WOLFSSL* ssl,
                    unsigned char* exportBuffer, unsigned int sz, void* userCtx);
+#define WOLFSSL_DTLS_EXPORT_TYPES
+#endif /* WOLFSSL_DTLS_EXPORT_TYPES */
+
 WOLFSSL_API int wolfSSL_dtls_import(WOLFSSL* ssl, unsigned char* buf,
                                                                unsigned int sz);
@@ -384,4 +528,11 @@
 WOLFSSL_API int wolfSSL_CTX_use_certificate_file(WOLFSSL_CTX*, const char*, int);
 WOLFSSL_API int wolfSSL_CTX_use_PrivateKey_file(WOLFSSL_CTX*, const char*, int);
+
+#define WOLFSSL_LOAD_FLAG_NONE          0x00000000
+#define WOLFSSL_LOAD_FLAG_IGNORE_ERR    0x00000001
+#define WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY 0x00000002
+#define WOLFSSL_LOAD_FLAG_PEM_CA_ONLY   0x00000004
+WOLFSSL_API int wolfSSL_CTX_load_verify_locations_ex(WOLFSSL_CTX*, const char*,
+                                                const char*, unsigned int);
 WOLFSSL_API int wolfSSL_CTX_load_verify_locations(WOLFSSL_CTX*, const char*,
                                                 const char*);
@@ -391,11 +542,16 @@
 WOLFSSL_API int wolfSSL_CTX_use_certificate_chain_file(WOLFSSL_CTX *,
                                                      const char *file);
+WOLFSSL_API int wolfSSL_CTX_use_certificate_chain_file_format(WOLFSSL_CTX *,
+                                                  const char *file, int format);
 WOLFSSL_API int wolfSSL_CTX_use_RSAPrivateKey_file(WOLFSSL_CTX*, const char*, int);
 
 WOLFSSL_API long wolfSSL_get_verify_depth(WOLFSSL* ssl);
 WOLFSSL_API long wolfSSL_CTX_get_verify_depth(WOLFSSL_CTX* ctx);
+WOLFSSL_API void wolfSSL_CTX_set_verify_depth(WOLFSSL_CTX *ctx,int depth);
 WOLFSSL_API int wolfSSL_use_certificate_file(WOLFSSL*, const char*, int);
 WOLFSSL_API int wolfSSL_use_PrivateKey_file(WOLFSSL*, const char*, int);
 WOLFSSL_API int wolfSSL_use_certificate_chain_file(WOLFSSL*, const char *file);
+WOLFSSL_API int wolfSSL_use_certificate_chain_file_format(WOLFSSL*,
+                                                  const char *file, int format);
 WOLFSSL_API int wolfSSL_use_RSAPrivateKey_file(WOLFSSL*, const char*, int);
 
@@ -410,13 +566,9 @@
 #endif
 
-#ifndef WOLFSSL_PEMCERT_TODER_DEFINED
-    WOLFSSL_API int wolfSSL_PemCertToDer(const char*, unsigned char*, int);
-    #define WOLFSSL_PEMCERT_TODER_DEFINED
-#endif
-
 #endif /* !NO_FILESYSTEM && !NO_CERTS */
 
 WOLFSSL_API WOLFSSL_CTX* wolfSSL_CTX_new(WOLFSSL_METHOD*);
 WOLFSSL_API WOLFSSL* wolfSSL_new(WOLFSSL_CTX*);
+WOLFSSL_API WOLFSSL_CTX* wolfSSL_get_SSL_CTX(WOLFSSL* ssl);
 WOLFSSL_API int  wolfSSL_is_server(WOLFSSL*);
 WOLFSSL_API WOLFSSL* wolfSSL_write_dup(WOLFSSL*);
@@ -428,10 +580,10 @@
 WOLFSSL_API int  wolfSSL_get_ciphers(char*, int);
 WOLFSSL_API const char* wolfSSL_get_cipher_name(WOLFSSL* ssl);
+WOLFSSL_API const char* wolfSSL_get_cipher_name_from_suite(const unsigned char,
+    const unsigned char);
 WOLFSSL_API const char* wolfSSL_get_shared_ciphers(WOLFSSL* ssl, char* buf,
     int len);
 WOLFSSL_API const char* wolfSSL_get_curve_name(WOLFSSL* ssl);
 WOLFSSL_API int  wolfSSL_get_fd(const WOLFSSL*);
-WOLFSSL_API void wolfSSL_set_using_nonblock(WOLFSSL*, int);
-WOLFSSL_API int  wolfSSL_get_using_nonblock(WOLFSSL*);
 /* please see note at top of README if you get an error from connect */
 WOLFSSL_API int  wolfSSL_connect(WOLFSSL*);
@@ -452,4 +604,9 @@
 WOLFSSL_API int  wolfSSL_request_certificate(WOLFSSL* ssl);
 
+WOLFSSL_API int  wolfSSL_preferred_group(WOLFSSL* ssl);
+WOLFSSL_API int  wolfSSL_CTX_set_groups(WOLFSSL_CTX* ctx, int* groups,
+                                        int count);
+WOLFSSL_API int  wolfSSL_set_groups(WOLFSSL* ssl, int* groups, int count);
+
 WOLFSSL_API int  wolfSSL_connect_TLSv13(WOLFSSL*);
 WOLFSSL_API int  wolfSSL_accept_TLSv13(WOLFSSL*);
@@ -475,10 +632,20 @@
 WOLFSSL_API int  wolfSSL_get_alert_history(WOLFSSL*, WOLFSSL_ALERT_HISTORY *);
 
-WOLFSSL_API int        wolfSSL_set_session(WOLFSSL* ssl,WOLFSSL_SESSION* session);
-WOLFSSL_API long       wolfSSL_SSL_SESSION_set_timeout(WOLFSSL_SESSION* session, long t);
-WOLFSSL_API WOLFSSL_SESSION* wolfSSL_get_session(WOLFSSL* ssl);
-WOLFSSL_API void       wolfSSL_flush_sessions(WOLFSSL_CTX *ctx, long tm);
-WOLFSSL_API int        wolfSSL_SetServerID(WOLFSSL* ssl, const unsigned char*,
-                                         int, int);
+WOLFSSL_API int  wolfSSL_set_session(WOLFSSL*, WOLFSSL_SESSION*);
+WOLFSSL_API long wolfSSL_SSL_SESSION_set_timeout(WOLFSSL_SESSION*, long);
+WOLFSSL_API WOLFSSL_SESSION* wolfSSL_get_session(WOLFSSL*);
+WOLFSSL_API void wolfSSL_flush_sessions(WOLFSSL_CTX*, long);
+WOLFSSL_API int  wolfSSL_SetServerID(WOLFSSL*, const unsigned char*, int, int);
+
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO)
+WOLFSSL_API int  wolfSSL_BIO_new_bio_pair(WOLFSSL_BIO**, size_t,
+                     WOLFSSL_BIO**, size_t);
+
+WOLFSSL_API WOLFSSL_RSA* wolfSSL_d2i_RSAPrivateKey_bio(WOLFSSL_BIO*, WOLFSSL_RSA**);
+WOLFSSL_API int wolfSSL_CTX_use_certificate_ASN1(WOLFSSL_CTX*,
+                                           int, const unsigned char*);
+WOLFSSL_API int wolfSSL_CTX_use_RSAPrivateKey(WOLFSSL_CTX*, WOLFSSL_RSA*);
+WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_bio(WOLFSSL_BIO*, WOLFSSL_EVP_PKEY**);
+#endif /* OPENSSL_ALL || WOLFSSL_ASIO */
 
 #ifdef SESSION_INDEX
@@ -493,5 +660,22 @@
 
 typedef int (*VerifyCallback)(int, WOLFSSL_X509_STORE_CTX*);
-typedef int (pem_password_cb)(char*, int, int, void*);
+#ifdef OPENSSL_EXTRA
+typedef void (CallbackInfoState)(const WOLFSSL*, int, int);
+
+typedef struct WOLFSSL_CRYPTO_EX_DATA {
+    WOLFSSL_STACK* data;
+} WOLFSSL_CRYPTO_EX_DATA;
+
+typedef int  (WOLFSSL_CRYPTO_EX_new)(void* p, void* ptr,
+        WOLFSSL_CRYPTO_EX_DATA* a, int idx, long argValue, void* arg);
+typedef int  (WOLFSSL_CRYPTO_EX_dup)(WOLFSSL_CRYPTO_EX_DATA* out,
+        WOLFSSL_CRYPTO_EX_DATA* in, void* inPtr, int idx, long argV, void* arg);
+typedef void (WOLFSSL_CRYPTO_EX_free)(void* p, void* ptr,
+        WOLFSSL_CRYPTO_EX_DATA* a, int idx, long argValue, void* arg);
+
+WOLFSSL_API int  wolfSSL_get_ex_new_index(long argValue, void* arg,
+        WOLFSSL_CRYPTO_EX_new* a, WOLFSSL_CRYPTO_EX_dup* b,
+        WOLFSSL_CRYPTO_EX_free* c);
+#endif
 
 WOLFSSL_API void wolfSSL_CTX_set_verify(WOLFSSL_CTX*, int,
@@ -531,4 +715,9 @@
 
 /* Nonblocking DTLS helper functions */
+WOLFSSL_API void wolfSSL_dtls_set_using_nonblock(WOLFSSL*, int);
+WOLFSSL_API int  wolfSSL_dtls_get_using_nonblock(WOLFSSL*);
+#define wolfSSL_set_using_nonblock wolfSSL_dtls_set_using_nonblock
+#define wolfSSL_get_using_nonblock wolfSSL_dtls_get_using_nonblock
+    /* The old names are deprecated. */
 WOLFSSL_API int  wolfSSL_dtls_get_current_timeout(WOLFSSL* ssl);
 WOLFSSL_API int  wolfSSL_dtls_set_timeout_init(WOLFSSL* ssl, int);
@@ -585,4 +774,9 @@
 WOLFSSL_API WOLFSSL_X509* wolfSSL_sk_X509_pop(WOLF_STACK_OF(WOLFSSL_X509_NAME)* sk);
 WOLFSSL_API void wolfSSL_sk_X509_free(WOLF_STACK_OF(WOLFSSL_X509_NAME)* sk);
+WOLFSSL_API WOLFSSL_ASN1_OBJECT* wolfSSL_sk_GENERAL_NAME_value(
+        WOLFSSL_STACK* sk, int i);
+WOLFSSL_API int wolfSSL_sk_GENERAL_NAME_num(WOLFSSL_STACK* sk);
+WOLFSSL_API void wolfSSL_sk_GENERAL_NAME_pop_free(WOLFSSL_STACK* sk,
+        void f (WOLFSSL_ASN1_OBJECT*));
 WOLFSSL_API WOLFSSL_ASN1_OBJECT* wolfSSL_ASN1_OBJECT_new(void);
 WOLFSSL_API void wolfSSL_ASN1_OBJECT_free(WOLFSSL_ASN1_OBJECT* obj);
@@ -617,6 +811,5 @@
                            /* what's ref count */
 
-WOLFSSL_API void wolfSSL_X509_free(WOLFSSL_X509*);
-WOLFSSL_API void wolfSSL_OPENSSL_free(void*);
+WOLFSSL_API WOLFSSL_X509* wolfSSL_X509_new(void);
 
 WOLFSSL_API int wolfSSL_OCSP_parse_url(char* url, char** host, char** port,
@@ -627,12 +820,10 @@
 WOLFSSL_API WOLFSSL_METHOD* wolfSSLv2_server_method(void);
 
-WOLFSSL_API void wolfSSL_MD4_Init(WOLFSSL_MD4_CTX*);
-WOLFSSL_API void wolfSSL_MD4_Update(WOLFSSL_MD4_CTX*, const void*, unsigned long);
-WOLFSSL_API void wolfSSL_MD4_Final(unsigned char*, WOLFSSL_MD4_CTX*);
-
-
 WOLFSSL_API WOLFSSL_BIO* wolfSSL_BIO_new(WOLFSSL_BIO_METHOD*);
 WOLFSSL_API int  wolfSSL_BIO_free(WOLFSSL_BIO*);
 WOLFSSL_API int  wolfSSL_BIO_free_all(WOLFSSL_BIO*);
+WOLFSSL_API int wolfSSL_BIO_gets(WOLFSSL_BIO* bio, char* buf, int sz);
+WOLFSSL_API WOLFSSL_BIO* wolfSSL_BIO_next(WOLFSSL_BIO* bio);
+WOLFSSL_API WOLFSSL_BIO* wolfSSL_BIO_find_type(WOLFSSL_BIO* bio, int type);
 WOLFSSL_API int  wolfSSL_BIO_read(WOLFSSL_BIO*, void*, int);
 WOLFSSL_API int  wolfSSL_BIO_write(WOLFSSL_BIO*, const void*, int);
@@ -659,5 +850,4 @@
 WOLFSSL_API long wolfSSL_BIO_set_fd(WOLFSSL_BIO* b, int fd, int flag);
 WOLFSSL_API void wolfSSL_set_bio(WOLFSSL*, WOLFSSL_BIO* rd, WOLFSSL_BIO* wr);
-WOLFSSL_API int  wolfSSL_add_all_algorithms(void);
 
 #ifndef NO_FILESYSTEM
@@ -690,5 +880,7 @@
 WOLFSSL_API int         wolfSSL_RAND_egd(const char*);
 WOLFSSL_API int         wolfSSL_RAND_seed(const void*, int);
+WOLFSSL_API void        wolfSSL_RAND_Cleanup(void);
 WOLFSSL_API void        wolfSSL_RAND_add(const void*, int, double);
+WOLFSSL_API int         wolfSSL_RAND_poll(void);
 
 WOLFSSL_API WOLFSSL_COMP_METHOD* wolfSSL_COMP_zlib(void);
@@ -696,6 +888,5 @@
 WOLFSSL_API int wolfSSL_COMP_add_compression_method(int, void*);
 
-WOLFSSL_API int wolfSSL_get_ex_new_index(long, void*, void*, void*, void*);
-
+WOLFSSL_API unsigned long wolfSSL_thread_id(void);
 WOLFSSL_API void wolfSSL_set_id_callback(unsigned long (*f)(void));
 WOLFSSL_API void wolfSSL_set_locking_callback(void (*f)(int, int, const char*,
@@ -714,4 +905,9 @@
 WOLFSSL_API int   wolfSSL_X509_STORE_CTX_get_error_depth(WOLFSSL_X509_STORE_CTX*);
 
+WOLFSSL_API void  wolfSSL_X509_STORE_CTX_set_verify_cb(WOLFSSL_X509_STORE_CTX *ctx,
+                                  WOLFSSL_X509_STORE_CTX_verify_cb verify_cb);
+WOLFSSL_API int wolfSSL_i2d_X509_NAME(WOLFSSL_X509_NAME* n,
+                                                           unsigned char** out);
+WOLFSSL_API int wolfSSL_X509_print(WOLFSSL_BIO* bio, WOLFSSL_X509* x509);
 WOLFSSL_API char*       wolfSSL_X509_NAME_oneline(WOLFSSL_X509_NAME*, char*, int);
 WOLFSSL_API WOLFSSL_X509_NAME*  wolfSSL_X509_get_issuer_name(WOLFSSL_X509*);
@@ -727,4 +923,9 @@
 WOLFSSL_API unsigned char* wolfSSL_X509_get_subjectKeyID(
                                             WOLFSSL_X509*, unsigned char*, int*);
+
+WOLFSSL_API int wolfSSL_X509_set_subject_name(WOLFSSL_X509*,
+                                              WOLFSSL_X509_NAME*);
+WOLFSSL_API int wolfSSL_X509_set_pubkey(WOLFSSL_X509*, WOLFSSL_EVP_PKEY*);
+
 WOLFSSL_API int wolfSSL_X509_NAME_entry_count(WOLFSSL_X509_NAME*);
 WOLFSSL_API int wolfSSL_X509_NAME_get_text_by_NID(
@@ -733,5 +934,11 @@
                                            WOLFSSL_X509_NAME*, int, int);
 WOLFSSL_API WOLFSSL_ASN1_STRING* wolfSSL_X509_NAME_ENTRY_get_data(WOLFSSL_X509_NAME_ENTRY*);
-WOLFSSL_API char* wolfSSL_ASN1_STRING_data(WOLFSSL_ASN1_STRING*);
+
+WOLFSSL_API WOLFSSL_ASN1_STRING* wolfSSL_ASN1_STRING_new(void);
+WOLFSSL_API WOLFSSL_ASN1_STRING* wolfSSL_ASN1_STRING_type_new(int type);
+WOLFSSL_API void wolfSSL_ASN1_STRING_free(WOLFSSL_ASN1_STRING* asn1);
+WOLFSSL_API int wolfSSL_ASN1_STRING_set(WOLFSSL_ASN1_STRING* asn1,
+                                                  const void* data, int dataSz);
+WOLFSSL_API unsigned char* wolfSSL_ASN1_STRING_data(WOLFSSL_ASN1_STRING*);
 WOLFSSL_API int wolfSSL_ASN1_STRING_length(WOLFSSL_ASN1_STRING*);
 WOLFSSL_API int         wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX*);
@@ -770,21 +977,35 @@
 WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_X509_get_pubkey(WOLFSSL_X509*);
 WOLFSSL_API int       wolfSSL_X509_CRL_verify(WOLFSSL_X509_CRL*, WOLFSSL_EVP_PKEY*);
-WOLFSSL_API void      wolfSSL_X509_STORE_CTX_set_error(WOLFSSL_X509_STORE_CTX*,
-                                                     int);
 WOLFSSL_API void      wolfSSL_X509_OBJECT_free_contents(WOLFSSL_X509_OBJECT*);
+WOLFSSL_API WOLFSSL_PKCS8_PRIV_KEY_INFO* wolfSSL_d2i_PKCS8_PKEY_bio(
+        WOLFSSL_BIO* bio, WOLFSSL_PKCS8_PRIV_KEY_INFO** pkey);
+WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_d2i_PUBKEY_bio(WOLFSSL_BIO* bio,
+                                         WOLFSSL_EVP_PKEY** out);
+WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_d2i_PUBKEY(WOLFSSL_EVP_PKEY** key,
+        unsigned char** in, long inSz);
 WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey(int type,
         WOLFSSL_EVP_PKEY** out, const unsigned char **in, long inSz);
+WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_EVP(WOLFSSL_EVP_PKEY** key,
+        unsigned char** in, long inSz);
+WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_PKEY_new_ex(void* heap);
 WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_PKEY_new(void);
-WOLFSSL_API void      wolfSSL_EVP_PKEY_free(WOLFSSL_EVP_PKEY*);
 WOLFSSL_API int       wolfSSL_X509_cmp_current_time(const WOLFSSL_ASN1_TIME*);
 WOLFSSL_API int       wolfSSL_sk_X509_REVOKED_num(WOLFSSL_X509_REVOKED*);
-
+#ifdef OPENSSL_EXTRA
+WOLFSSL_API void      wolfSSL_X509_STORE_CTX_set_time(WOLFSSL_X509_STORE_CTX*,
+                                                      unsigned long flags,
+                                                      time_t t);
+#endif
 WOLFSSL_API WOLFSSL_X509_REVOKED* wolfSSL_X509_CRL_get_REVOKED(WOLFSSL_X509_CRL*);
 WOLFSSL_API WOLFSSL_X509_REVOKED* wolfSSL_sk_X509_REVOKED_value(
                                                       WOLFSSL_X509_REVOKED*,int);
 WOLFSSL_API WOLFSSL_ASN1_INTEGER* wolfSSL_X509_get_serialNumber(WOLFSSL_X509*);
+WOLFSSL_API void wolfSSL_ASN1_INTEGER_free(WOLFSSL_ASN1_INTEGER*);
+WOLFSSL_API WOLFSSL_ASN1_INTEGER* wolfSSL_ASN1_INTEGER_new(void);
 
 WOLFSSL_API int wolfSSL_ASN1_TIME_print(WOLFSSL_BIO*, const WOLFSSL_ASN1_TIME*);
 
+WOLFSSL_API char* wolfSSL_ASN1_TIME_to_string(WOLFSSL_ASN1_TIME* t,
+                                                            char* buf, int len);
 WOLFSSL_API int  wolfSSL_ASN1_INTEGER_cmp(const WOLFSSL_ASN1_INTEGER*,
                                        const WOLFSSL_ASN1_INTEGER*);
@@ -794,7 +1015,9 @@
 WOLFSSL_API WOLFSSL_BIGNUM *wolfSSL_ASN1_INTEGER_to_BN(const WOLFSSL_ASN1_INTEGER *ai,
                                        WOLFSSL_BIGNUM *bn);
+WOLFSSL_API WOLFSSL_ASN1_TIME* wolfSSL_ASN1_TIME_adj(WOLFSSL_ASN1_TIME*, time_t,
+                                                     int, long);
+#endif
+
 WOLFSSL_API WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_load_client_CA_file(const char*);
-#endif
-
 WOLFSSL_API WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_SSL_CTX_get_client_CA_list(
         const WOLFSSL_CTX *s);
@@ -803,4 +1026,6 @@
 WOLFSSL_API void* wolfSSL_X509_STORE_CTX_get_ex_data(WOLFSSL_X509_STORE_CTX*, int);
 WOLFSSL_API int   wolfSSL_get_ex_data_X509_STORE_CTX_idx(void);
+WOLFSSL_API void wolfSSL_X509_STORE_CTX_set_error(
+                                           WOLFSSL_X509_STORE_CTX* ctx, int er);
 WOLFSSL_API void* wolfSSL_get_ex_data(const WOLFSSL*, int);
 
@@ -809,5 +1034,6 @@
 WOLFSSL_API void wolfSSL_CTX_set_default_passwd_cb(WOLFSSL_CTX*,
                                                    pem_password_cb*);
-
+WOLFSSL_API pem_password_cb* wolfSSL_CTX_get_default_passwd_cb(WOLFSSL_CTX *ctx);
+WOLFSSL_API void *wolfSSL_CTX_get_default_passwd_cb_userdata(WOLFSSL_CTX *ctx);
 
 WOLFSSL_API void wolfSSL_CTX_set_info_callback(WOLFSSL_CTX*,
@@ -817,10 +1043,16 @@
 WOLFSSL_API int           wolfSSL_GET_REASON(int);
 
-WOLFSSL_API char* wolfSSL_alert_type_string_long(int);
-WOLFSSL_API char* wolfSSL_alert_desc_string_long(int);
-WOLFSSL_API char* wolfSSL_state_string_long(const WOLFSSL*);
+WOLFSSL_API const char* wolfSSL_alert_type_string_long(int);
+WOLFSSL_API const char* wolfSSL_alert_desc_string_long(int);
+WOLFSSL_API const char* wolfSSL_state_string_long(const WOLFSSL*);
 
 WOLFSSL_API WOLFSSL_RSA* wolfSSL_RSA_generate_key(int, unsigned long,
                                                void(*)(int, int, void*), void*);
+WOLFSSL_API WOLFSSL_RSA *wolfSSL_d2i_RSAPublicKey(WOLFSSL_RSA **r,
+                                            const unsigned char **pp, long len);
+WOLFSSL_API WOLFSSL_RSA *wolfSSL_d2i_RSAPrivateKey(WOLFSSL_RSA**,
+                                            const unsigned char**, long);
+WOLFSSL_API int wolfSSL_i2d_RSAPublicKey(WOLFSSL_RSA *r, const unsigned char **pp);
+WOLFSSL_API int wolfSSL_i2d_RSAPrivateKey(WOLFSSL_RSA *r, unsigned char **pp);
 WOLFSSL_API void wolfSSL_CTX_set_tmp_rsa_callback(WOLFSSL_CTX*,
                                              WOLFSSL_RSA*(*)(WOLFSSL*, int, int));
@@ -851,7 +1083,11 @@
 WOLFSSL_API long wolfSSL_CTX_set_tlsext_opaque_prf_input_callback_arg(
         WOLFSSL_CTX*, void* arg);
-
-WOLFSSL_API unsigned long wolfSSL_set_options(WOLFSSL *s, unsigned long op);
-WOLFSSL_API unsigned long wolfSSL_get_options(const WOLFSSL *s);
+WOLFSSL_API int  wolfSSL_CTX_add_client_CA(WOLFSSL_CTX*, WOLFSSL_X509*);
+WOLFSSL_API int  wolfSSL_CTX_set_srp_password(WOLFSSL_CTX*, char*);
+WOLFSSL_API int  wolfSSL_CTX_set_srp_username(WOLFSSL_CTX*, char*);
+
+WOLFSSL_API long wolfSSL_set_options(WOLFSSL *s, long op);
+WOLFSSL_API long wolfSSL_get_options(const WOLFSSL *s);
+WOLFSSL_API long wolfSSL_clear_options(WOLFSSL *s,  long op);
 WOLFSSL_API long wolfSSL_clear_num_renegotiations(WOLFSSL *s);
 WOLFSSL_API long wolfSSL_total_renegotiations(WOLFSSL *s);
@@ -870,5 +1106,4 @@
 
 #define WOLFSSL_DEFAULT_CIPHER_LIST ""   /* default all */
-#define WOLFSSL_RSA_F4 0x10001L
 
 enum {
@@ -881,5 +1116,5 @@
 };
 
-#ifdef OPENSSL_EXTRA
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
 /* seperated out from other enums because of size */
 enum {
@@ -946,4 +1181,5 @@
     SSL_ST_CONNECT = 0x1000,
     SSL_ST_ACCEPT  = 0x2000,
+    SSL_ST_MASK    = 0x0FFF,
 
     SSL_CB_LOOP = 0x01,
@@ -960,4 +1196,6 @@
     SSL_CB_CONNECT_LOOP = (SSL_ST_CONNECT | SSL_CB_LOOP),
     SSL_CB_CONNECT_EXIT = (SSL_ST_CONNECT | SSL_CB_EXIT),
+	SSL_CB_MODE_READ = 1,
+	SSL_CB_MODE_WRITE = 2,
 
     SSL_MODE_ENABLE_PARTIAL_WRITE = 2,
@@ -966,6 +1204,4 @@
     BIO_CLOSE   = 1,
     BIO_NOCLOSE = 0,
-
-    NID_undef = 0,
 
     X509_FILETYPE_PEM = 8,
@@ -1020,4 +1256,6 @@
     X509_V_ERR_UNNESTED_RESOURCE,
 
+    X509_R_CERT_ALREADY_IN_HASH_TABLE,
+
     XN_FLAG_SPC_EQ  = (1 << 23),
     XN_FLAG_ONELINE = 0,
@@ -1037,7 +1275,7 @@
    since not using thread storage error queue */
 #include <stdio.h>
-WOLFSSL_API void  wolfSSL_ERR_print_errors_fp(FILE*, int err);
+WOLFSSL_API void  wolfSSL_ERR_print_errors_fp(XFILE, int err);
 #if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE)
-WOLFSSL_API void wolfSSL_ERR_dump_errors_fp(FILE* fp);
+WOLFSSL_API void wolfSSL_ERR_dump_errors_fp(XFILE fp);
 #endif
 #endif
@@ -1167,4 +1405,12 @@
     WOLFSSL_API void wolfSSL_set_psk_client_callback(WOLFSSL*,
                                                     wc_psk_client_callback);
+#ifdef WOLFSSL_TLS13
+    typedef unsigned int (*wc_psk_client_tls13_callback)(WOLFSSL*, const char*,
+               char*, unsigned int, unsigned char*, unsigned int, const char**);
+    WOLFSSL_API void wolfSSL_CTX_set_psk_client_tls13_callback(WOLFSSL_CTX*,
+                                                  wc_psk_client_tls13_callback);
+    WOLFSSL_API void wolfSSL_set_psk_client_tls13_callback(WOLFSSL*,
+                                                  wc_psk_client_tls13_callback);
+#endif
 
     WOLFSSL_API const char* wolfSSL_get_psk_identity_hint(const WOLFSSL*);
@@ -1180,4 +1426,12 @@
     WOLFSSL_API void wolfSSL_set_psk_server_callback(WOLFSSL*,
                                                     wc_psk_server_callback);
+#ifdef WOLFSSL_TLS13
+    typedef unsigned int (*wc_psk_server_tls13_callback)(WOLFSSL*, const char*,
+                          unsigned char*, unsigned int, const char**);
+    WOLFSSL_API void wolfSSL_CTX_set_psk_server_tls13_callback(WOLFSSL_CTX*,
+                                                  wc_psk_server_tls13_callback);
+    WOLFSSL_API void wolfSSL_set_psk_server_tls13_callback(WOLFSSL*,
+                                                  wc_psk_server_tls13_callback);
+#endif
 
     #define PSK_TYPES_DEFINED
@@ -1202,7 +1456,9 @@
     WOLFSSL_BIO_SIZE  = 17000 /* default BIO write size if not set */
 };
-
-#endif
-
+#endif
+
+WOLFSSL_API void wolfSSL_ERR_put_error(int lib, int fun, int err,
+                                       const char* file, int line);
+WOLFSSL_API unsigned long wolfSSL_ERR_get_error_line(const char**, int*);
 WOLFSSL_API unsigned long wolfSSL_ERR_get_error_line_data(const char**, int*,
                                                  const char**, int *);
@@ -1213,14 +1469,17 @@
 
 WOLFSSL_API int  wolfSSL_RAND_status(void);
+WOLFSSL_API int  wolfSSL_RAND_pseudo_bytes(unsigned char* buf, int num);
 WOLFSSL_API int  wolfSSL_RAND_bytes(unsigned char* buf, int num);
 WOLFSSL_API WOLFSSL_METHOD *wolfSSLv23_server_method(void);
 WOLFSSL_API long wolfSSL_CTX_set_options(WOLFSSL_CTX*, long);
+WOLFSSL_API long wolfSSL_CTX_get_options(WOLFSSL_CTX* ctx);
+WOLFSSL_API long wolfSSL_CTX_clear_options(WOLFSSL_CTX*, long);
+
 #ifndef NO_CERTS
-  WOLFSSL_API int  wolfSSL_CTX_check_private_key(WOLFSSL_CTX*);
+  WOLFSSL_API int  wolfSSL_CTX_check_private_key(const WOLFSSL_CTX*);
 #endif /* !NO_CERTS */
 
 WOLFSSL_API void wolfSSL_ERR_free_strings(void);
 WOLFSSL_API void wolfSSL_ERR_remove_state(unsigned long);
-WOLFSSL_API void wolfSSL_EVP_cleanup(void);
 WOLFSSL_API int  wolfSSL_clear(WOLFSSL* ssl);
 WOLFSSL_API int  wolfSSL_state(WOLFSSL* ssl);
@@ -1237,4 +1496,5 @@
                                             const unsigned char*, unsigned int);
 WOLFSSL_API WOLFSSL_X509* wolfSSL_get_peer_certificate(WOLFSSL* ssl);
+WOLFSSL_API WOLF_STACK_OF(WOLFSSL_X509)* wolfSSL_get_peer_cert_chain(const WOLFSSL*);
 
 WOLFSSL_API int wolfSSL_want_read(WOLFSSL*);
@@ -1246,6 +1506,7 @@
 WOLFSSL_API int wolfSSL_ASN1_GENERALIZEDTIME_print(WOLFSSL_BIO*,
                                          const WOLFSSL_ASN1_GENERALIZEDTIME*);
-WOLFSSL_API int   wolfSSL_sk_num(WOLFSSL_X509_REVOKED*);
-WOLFSSL_API void* wolfSSL_sk_value(WOLFSSL_X509_REVOKED*, int);
+WOLFSSL_API void wolfSSL_ASN1_GENERALIZEDTIME_free(WOLFSSL_ASN1_GENERALIZEDTIME*);
+WOLFSSL_API int   wolfSSL_sk_num(WOLF_STACK_OF(WOLFSSL_ASN1_OBJECT)*);
+WOLFSSL_API void* wolfSSL_sk_value(WOLF_STACK_OF(WOLFSSL_ASN1_OBJECT)*, int);
 
 /* stunnel 4.28 needs */
@@ -1286,9 +1547,4 @@
 WOLFSSL_API unsigned int wolfSSL_lib_version_hex(void);
 
-/* turn logging on, only if compiled in */
-WOLFSSL_API int  wolfSSL_Debugging_ON(void);
-/* turn logging off */
-WOLFSSL_API void wolfSSL_Debugging_OFF(void);
-
 /* do accept or connect depedning on side */
 WOLFSSL_API int wolfSSL_negotiate(WOLFSSL* ssl);
@@ -1315,5 +1571,6 @@
 WOLFSSL_API WOLFSSL_X509* wolfSSL_get_chain_X509(WOLFSSL_X509_CHAIN*, int idx);
 /* free X509 */
-WOLFSSL_API void wolfSSL_FreeX509(WOLFSSL_X509*);
+#define wolfSSL_FreeX509(x509) wolfSSL_X509_free((x509))
+WOLFSSL_API void wolfSSL_X509_free(WOLFSSL_X509*);
 /* get index cert in PEM */
 WOLFSSL_API int  wolfSSL_get_chain_cert_pem(WOLFSSL_X509_CHAIN*, int idx,
@@ -1331,10 +1588,20 @@
 WOLFSSL_API char* wolfSSL_X509_get_next_altname(WOLFSSL_X509*);
 
+WOLFSSL_API WOLFSSL_X509* wolfSSL_d2i_X509(WOLFSSL_X509** x509,
+        const unsigned char** in, int len);
 WOLFSSL_API WOLFSSL_X509*
     wolfSSL_X509_d2i(WOLFSSL_X509** x509, const unsigned char* in, int len);
+WOLFSSL_API int wolfSSL_i2d_X509(WOLFSSL_X509* x509, unsigned char** out);
+WOLFSSL_API WOLFSSL_X509_CRL *wolfSSL_d2i_X509_CRL(WOLFSSL_X509_CRL **crl,
+                                                   const unsigned char *in, int len);
+#ifndef NO_FILESYSTEM
+WOLFSSL_API WOLFSSL_X509_CRL *wolfSSL_d2i_X509_CRL_fp(XFILE file, WOLFSSL_X509_CRL **crl);
+#endif
+WOLFSSL_API void wolfSSL_X509_CRL_free(WOLFSSL_X509_CRL *crl);
+
 #ifndef NO_FILESYSTEM
     #ifndef NO_STDIO_FILESYSTEM
     WOLFSSL_API WOLFSSL_X509*
-        wolfSSL_X509_d2i_fp(WOLFSSL_X509** x509, FILE* file);
+        wolfSSL_X509_d2i_fp(WOLFSSL_X509** x509, XFILE file);
     #endif
 WOLFSSL_API WOLFSSL_X509*
@@ -1362,6 +1629,15 @@
 WOLFSSL_API WC_PKCS12* wolfSSL_d2i_PKCS12_bio(WOLFSSL_BIO* bio,
                                        WC_PKCS12** pkcs12);
+#ifndef NO_FILESYSTEM
+WOLFSSL_API WOLFSSL_X509_PKCS12* wolfSSL_d2i_PKCS12_fp(XFILE fp,
+                                       WOLFSSL_X509_PKCS12** pkcs12);
+#endif
 WOLFSSL_API int wolfSSL_PKCS12_parse(WC_PKCS12* pkcs12, const char* psw,
-     WOLFSSL_EVP_PKEY** pkey, WOLFSSL_X509** cert, WOLF_STACK_OF(WOLFSSL_X509)** ca);
+     WOLFSSL_EVP_PKEY** pkey, WOLFSSL_X509** cert,
+     WOLF_STACK_OF(WOLFSSL_X509)** ca);
+WOLFSSL_API WC_PKCS12* wolfSSL_PKCS12_create(char* pass, char* name,
+        WOLFSSL_EVP_PKEY* pkey, WOLFSSL_X509* cert,
+        WOLF_STACK_OF(WOLFSSL_X509)* ca,
+        int keyNID, int certNID, int itt, int macItt, int keytype);
 WOLFSSL_API void wolfSSL_PKCS12_PBE_add(void);
 
@@ -1374,4 +1650,5 @@
 WOLFSSL_API int  wolfSSL_SetTmpDH_buffer(WOLFSSL*, const unsigned char* b, long sz,
                                        int format);
+WOLFSSL_API int wolfSSL_SetEnableDhKeyTest(WOLFSSL*, int);
 #ifndef NO_FILESYSTEM
     WOLFSSL_API int  wolfSSL_SetTmpDH_file(WOLFSSL*, const char* f, int format);
@@ -1391,4 +1668,6 @@
 WOLFSSL_API int wolfSSL_CTX_SetMinDhKey_Sz(WOLFSSL_CTX*, unsigned short);
 WOLFSSL_API int wolfSSL_SetMinDhKey_Sz(WOLFSSL*, unsigned short);
+WOLFSSL_API int wolfSSL_CTX_SetMaxDhKey_Sz(WOLFSSL_CTX*, unsigned short);
+WOLFSSL_API int wolfSSL_SetMaxDhKey_Sz(WOLFSSL*, unsigned short);
 WOLFSSL_API int wolfSSL_GetDhKey_Sz(WOLFSSL*);
 #endif /* NO_DH */
@@ -1426,5 +1705,6 @@
         #elif !defined(WOLFSSL_MDK_ARM) && !defined(WOLFSSL_IAR_ARM) && \
               !defined(WOLFSSL_PICOTCP) && !defined(WOLFSSL_ROWLEY_ARM) && \
-              !defined(WOLFSSL_EMBOS) && !defined(WOLFSSL_FROSTED)
+              !defined(WOLFSSL_EMBOS) && !defined(WOLFSSL_FROSTED) && \
+              !defined(WOLFSSL_CHIBIOS) && !defined(WOLFSSL_CONTIKI)
             #include <sys/uio.h>
         #endif
@@ -1445,4 +1725,6 @@
 #endif
     WOLFSSL_API int wolfSSL_CTX_load_verify_buffer(WOLFSSL_CTX*,
+                                               const unsigned char*, long, int);
+    WOLFSSL_API int wolfSSL_CTX_load_verify_chain_buffer_format(WOLFSSL_CTX*,
                                                const unsigned char*, long, int);
     WOLFSSL_API int wolfSSL_CTX_use_certificate_buffer(WOLFSSL_CTX*,
@@ -1458,4 +1740,6 @@
     WOLFSSL_API int wolfSSL_use_certificate_buffer(WOLFSSL*, const unsigned char*,
                                                long, int);
+    WOLFSSL_API int wolfSSL_use_certificate_ASN1(WOLFSSL* ssl, unsigned char* der,
+                                                                     int derSz);
     WOLFSSL_API int wolfSSL_use_PrivateKey_buffer(WOLFSSL*, const unsigned char*,
                                                long, int);
@@ -1514,4 +1798,5 @@
     WOLFSSL_TLSV1_1  = 2,
     WOLFSSL_TLSV1_2  = 3,
+    WOLFSSL_TLSV1_3  = 4,
     WOLFSSL_USER_CA  = 1,          /* user added as trusted */
     WOLFSSL_CHAIN_CA = 2           /* added to cache from trusted chain */
@@ -1527,20 +1812,14 @@
 WOLFSSL_API int wolfSSL_GetOutputSize(WOLFSSL*, int);
 WOLFSSL_API int wolfSSL_GetMaxOutputSize(WOLFSSL*);
+WOLFSSL_API int wolfSSL_GetVersion(WOLFSSL* ssl);
 WOLFSSL_API int wolfSSL_SetVersion(WOLFSSL* ssl, int version);
-WOLFSSL_API int wolfSSL_KeyPemToDer(const unsigned char*, int,
-                                    unsigned char*, int, const char*);
-WOLFSSL_API int wolfSSL_CertPemToDer(const unsigned char*, int,
-                                     unsigned char*, int, int);
-#if defined(WOLFSSL_CERT_EXT) || defined(WOLFSSL_PUB_PEM_TO_DER)
-    #ifndef WOLFSSL_PEMPUBKEY_TODER_DEFINED
-        #ifndef NO_FILESYSTEM
-            WOLFSSL_API int wolfSSL_PemPubKeyToDer(const char* fileName,
-                                                   unsigned char* derBuf, int derSz);
-        #endif
-        WOLFSSL_API int wolfSSL_PubKeyPemToDer(const unsigned char*, int,
-                                               unsigned char*, int);
-        #define WOLFSSL_PEMPUBKEY_TODER_DEFINED
-    #endif /* WOLFSSL_PEMPUBKEY_TODER_DEFINED */
-#endif /* WOLFSSL_CERT_EXT || WOLFSSL_PUB_PEM_TO_DER*/
+
+/* moved to asn.c, old names kept for backwards compatability */
+#define wolfSSL_KeyPemToDer    wc_KeyPemToDer
+#define wolfSSL_CertPemToDer   wc_CertPemToDer
+#define wolfSSL_PemPubKeyToDer wc_PemPubKeyToDer
+#define wolfSSL_PubKeyPemToDer wc_PubKeyPemToDer
+#define wolfSSL_PemCertToDer   wc_PemCertToDer
+
 
 typedef void (*CallbackCACache)(unsigned char* der, int sz, int type);
@@ -1609,5 +1888,7 @@
     wolfssl_triple_des,             /* leading 3 (3des) not valid identifier */
     wolfssl_des40,
+#ifdef HAVE_IDEA
     wolfssl_idea,
+#endif
     wolfssl_aes,
     wolfssl_aes_gcm,
@@ -1629,4 +1910,15 @@
 
 /* Public Key Callback support */
+#ifdef HAVE_PK_CALLBACKS
+#ifdef HAVE_ECC
+
+struct ecc_key;
+
+typedef int (*CallbackEccKeyGen)(WOLFSSL* ssl, struct ecc_key* key,
+    unsigned int keySz, int ecc_curve, void* ctx);
+WOLFSSL_API void  wolfSSL_CTX_SetEccKeyGenCb(WOLFSSL_CTX*, CallbackEccKeyGen);
+WOLFSSL_API void  wolfSSL_SetEccKeyGenCtx(WOLFSSL* ssl, void *ctx);
+WOLFSSL_API void* wolfSSL_GetEccKeyGenCtx(WOLFSSL* ssl);
+
 typedef int (*CallbackEccSign)(WOLFSSL* ssl,
        const unsigned char* in, unsigned int inSz,
@@ -1647,5 +1939,4 @@
 WOLFSSL_API void* wolfSSL_GetEccVerifyCtx(WOLFSSL* ssl);
 
-struct ecc_key;
 typedef int (*CallbackEccSharedSecret)(WOLFSSL* ssl, struct ecc_key* otherKey,
         unsigned char* pubKeyDer, unsigned int* pubKeySz,
@@ -1655,5 +1946,20 @@
 WOLFSSL_API void  wolfSSL_SetEccSharedSecretCtx(WOLFSSL* ssl, void *ctx);
 WOLFSSL_API void* wolfSSL_GetEccSharedSecretCtx(WOLFSSL* ssl);
-
+#endif
+
+#ifndef NO_DH
+/* Public DH Key Callback support */
+struct DhKey;
+typedef int (*CallbackDhAgree)(WOLFSSL* ssl, struct DhKey* key,
+        const unsigned char* priv, unsigned int privSz,
+        const unsigned char* otherPubKeyDer, unsigned int otherPubKeySz,
+        unsigned char* out, unsigned int* outlen,
+        void* ctx);
+WOLFSSL_API void  wolfSSL_CTX_SetDhAgreeCb(WOLFSSL_CTX*, CallbackDhAgree);
+WOLFSSL_API void  wolfSSL_SetDhAgreeCtx(WOLFSSL* ssl, void *ctx);
+WOLFSSL_API void* wolfSSL_GetDhAgreeCtx(WOLFSSL* ssl);
+#endif /* !NO_DH */
+
+#ifdef HAVE_ED25519
 struct ed25519_key;
 typedef int (*CallbackEd25519Sign)(WOLFSSL* ssl,
@@ -1676,6 +1982,15 @@
 WOLFSSL_API void  wolfSSL_SetEd25519VerifyCtx(WOLFSSL* ssl, void *ctx);
 WOLFSSL_API void* wolfSSL_GetEd25519VerifyCtx(WOLFSSL* ssl);
-
+#endif
+
+#ifdef HAVE_CURVE25519
 struct curve25519_key;
+
+typedef int (*CallbackX25519KeyGen)(WOLFSSL* ssl, struct curve25519_key* key,
+    unsigned int keySz, void* ctx);
+WOLFSSL_API void  wolfSSL_CTX_SetX25519KeyGenCb(WOLFSSL_CTX*, CallbackX25519KeyGen);
+WOLFSSL_API void  wolfSSL_SetX25519KeyGenCtx(WOLFSSL* ssl, void *ctx);
+WOLFSSL_API void* wolfSSL_GetX25519KeyGenCtx(WOLFSSL* ssl);
+
 typedef int (*CallbackX25519SharedSecret)(WOLFSSL* ssl,
         struct curve25519_key* otherKey,
@@ -1688,5 +2003,7 @@
 WOLFSSL_API void  wolfSSL_SetX25519SharedSecretCtx(WOLFSSL* ssl, void *ctx);
 WOLFSSL_API void* wolfSSL_GetX25519SharedSecretCtx(WOLFSSL* ssl);
-
+#endif
+
+#ifndef NO_RSA
 typedef int (*CallbackRsaSign)(WOLFSSL* ssl,
        const unsigned char* in, unsigned int inSz,
@@ -1704,4 +2021,5 @@
        void* ctx);
 WOLFSSL_API void  wolfSSL_CTX_SetRsaVerifyCb(WOLFSSL_CTX*, CallbackRsaVerify);
+WOLFSSL_API void  wolfSSL_CTX_SetRsaSignCheckCb(WOLFSSL_CTX*, CallbackRsaVerify);
 WOLFSSL_API void  wolfSSL_SetRsaVerifyCtx(WOLFSSL* ssl, void *ctx);
 WOLFSSL_API void* wolfSSL_GetRsaVerifyCtx(WOLFSSL* ssl);
@@ -1726,4 +2044,6 @@
 WOLFSSL_API void  wolfSSL_CTX_SetRsaPssVerifyCb(WOLFSSL_CTX*,
                                                 CallbackRsaPssVerify);
+WOLFSSL_API void  wolfSSL_CTX_SetRsaPssSignCheckCb(WOLFSSL_CTX*,
+                                                    CallbackRsaPssVerify);
 WOLFSSL_API void  wolfSSL_SetRsaPssVerifyCtx(WOLFSSL* ssl, void *ctx);
 WOLFSSL_API void* wolfSSL_GetRsaPssVerifyCtx(WOLFSSL* ssl);
@@ -1749,5 +2069,6 @@
 WOLFSSL_API void  wolfSSL_SetRsaDecCtx(WOLFSSL* ssl, void *ctx);
 WOLFSSL_API void* wolfSSL_GetRsaDecCtx(WOLFSSL* ssl);
-
+#endif
+#endif /* HAVE_PK_CALLBACKS */
 
 #ifndef NO_CERTS
@@ -1855,6 +2176,8 @@
 
 /* async additions */
-WOLFSSL_API int wolfSSL_UseAsync(WOLFSSL*, int devId);
-WOLFSSL_API int wolfSSL_CTX_UseAsync(WOLFSSL_CTX*, int devId);
+#define wolfSSL_UseAsync wolfSSL_SetDevId
+#define wolfSSL_CTX_UseAsync wolfSSL_CTX_SetDevId
+WOLFSSL_API int wolfSSL_SetDevId(WOLFSSL*, int devId);
+WOLFSSL_API int wolfSSL_CTX_SetDevId(WOLFSSL_CTX*, int devId);
 
 /* helpers to get device id and heap */
@@ -1896,4 +2219,9 @@
 WOLFSSL_API void wolfSSL_CTX_SNI_SetOptions(WOLFSSL_CTX* ctx,
                                      unsigned char type, unsigned char options);
+WOLFSSL_API int wolfSSL_SNI_GetFromBuffer(
+                 const unsigned char* clientHello, unsigned int helloSz,
+                 unsigned char type, unsigned char* sni, unsigned int* inOutSz);
+
+#endif /* NO_WOLFSSL_SERVER */
 
 /* SNI status */
@@ -1909,10 +2237,6 @@
 WOLFSSL_API unsigned short wolfSSL_SNI_GetRequest(WOLFSSL *ssl,
                                                unsigned char type, void** data);
-WOLFSSL_API int wolfSSL_SNI_GetFromBuffer(
-                 const unsigned char* clientHello, unsigned int helloSz,
-                 unsigned char type, unsigned char* sni, unsigned int* inOutSz);
-
-#endif
-#endif
+
+#endif /* HAVE_SNI */
 
 /* Application-Layer Protocol Negotiation */
@@ -1932,5 +2256,5 @@
 };
 
-#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
 typedef int (*CallbackALPNSelect)(WOLFSSL* ssl, const unsigned char** out,
     unsigned char* outLen, const unsigned char* in, unsigned int inLen,
@@ -1959,5 +2283,8 @@
     WOLFSSL_MFL_2_11 = 3, /* 2048 bytes */
     WOLFSSL_MFL_2_12 = 4, /* 4096 bytes */
-    WOLFSSL_MFL_2_13 = 5  /* 8192 bytes *//* wolfSSL ONLY!!! */
+    WOLFSSL_MFL_2_13 = 5, /* 8192 bytes *//* wolfSSL ONLY!!! */
+    WOLFSSL_MFL_2_8  = 6, /*  256 bytes *//* wolfSSL ONLY!!! */
+    WOLFSSL_MFL_MIN  = WOLFSSL_MFL_2_9,
+    WOLFSSL_MFL_MAX  = WOLFSSL_MFL_2_8,
 };
 
@@ -1968,5 +2295,5 @@
 
 #endif
-#endif
+#endif /* HAVE_MAX_FRAGMENT */
 
 /* Truncated HMAC */
@@ -2117,5 +2444,4 @@
 #endif /* NO_WOLFSSL_CLIENT */
 
-#ifndef NO_WOLFSSL_SERVER
 
 #define WOLFSSL_TICKET_NAME_SZ 16
@@ -2129,4 +2455,6 @@
     WOLFSSL_TICKET_RET_CREATE        /* existing ticket ok and create new one */
 };
+
+#ifndef NO_WOLFSSL_SERVER
 
 typedef int (*SessionTicketEncCb)(WOLFSSL*,
@@ -2232,15 +2560,55 @@
 #endif
 
-#if defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
-WOLFSSL_API char* wolfSSL_ASN1_TIME_to_string(WOLFSSL_ASN1_TIME* time,
-                                                            char* buf, int len);
-#endif /* WOLFSSL_MYSQL_COMPATIBLE */
-
-#ifdef OPENSSL_EXTRA
-
-#ifndef NO_FILESYSTEM
-WOLFSSL_API long wolfSSL_BIO_set_fp(WOLFSSL_BIO *bio, XFILE fp, int c);
-WOLFSSL_API long wolfSSL_BIO_get_fp(WOLFSSL_BIO *bio, XFILE* fp);
-#endif
+#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+/* Smaller subset of X509 compatibility functions. Avoid increasing the size of
+ * this subset and its memory usage */
+
+#include <wolfssl/openssl/asn1.h>
+struct WOLFSSL_X509_NAME_ENTRY {
+    WOLFSSL_ASN1_OBJECT  object;  /* static object just for keeping grp, type */
+    WOLFSSL_ASN1_STRING  data;
+    WOLFSSL_ASN1_STRING* value;  /* points to data, for lighttpd port */
+    int nid; /* i.e. ASN_COMMON_NAME */
+    int set;
+    int size;
+};
+#endif /* OPENSSL_ALL || OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
+
+
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)
+
+enum {
+    WOLFSSL_SYS_ACCEPT = 0,
+    WOLFSSL_SYS_BIND,
+    WOLFSSL_SYS_CONNECT,
+    WOLFSSL_SYS_FOPEN,
+    WOLFSSL_SYS_FREAD,
+    WOLFSSL_SYS_GETADDRINFO,
+    WOLFSSL_SYS_GETSOCKOPT,
+    WOLFSSL_SYS_GETSOCKNAME,
+    WOLFSSL_SYS_GETHOSTBYNAME,
+    WOLFSSL_SYS_GETNAMEINFO,
+    WOLFSSL_SYS_GETSERVBYNAME,
+    WOLFSSL_SYS_IOCTLSOCKET,
+    WOLFSSL_SYS_LISTEN,
+    WOLFSSL_SYS_OPENDIR,
+    WOLFSSL_SYS_SETSOCKOPT,
+    WOLFSSL_SYS_SOCKET
+};
+
+/* Object functions */
+WOLFSSL_API const char *  wolfSSL_OBJ_nid2sn(int n);
+WOLFSSL_API int wolfSSL_OBJ_obj2nid(const WOLFSSL_ASN1_OBJECT *o);
+WOLFSSL_API int wolfSSL_OBJ_sn2nid(const char *sn);
+
+WOLFSSL_API char* wolfSSL_OBJ_nid2ln(int n);
+WOLFSSL_API int wolfSSL_OBJ_txt2nid(const char *sn);
+
+WOLFSSL_API WOLFSSL_ASN1_OBJECT* wolfSSL_OBJ_nid2obj(int n);
+WOLFSSL_LOCAL WOLFSSL_ASN1_OBJECT* wolfSSL_OBJ_nid2obj_ex(int n, WOLFSSL_ASN1_OBJECT *arg_obj);
+WOLFSSL_API int wolfSSL_OBJ_obj2txt(char *buf, int buf_len, WOLFSSL_ASN1_OBJECT *a, int no_name);
+
+WOLFSSL_API void wolfSSL_OBJ_cleanup(void);
+/* end of object functions */
 
 WOLFSSL_API unsigned long wolfSSL_ERR_peek_last_error_line(const char **file, int *line);
@@ -2249,4 +2617,15 @@
 
 #ifndef NO_CERTS
+WOLFSSL_API WOLFSSL_X509_NAME_ENTRY* wolfSSL_X509_NAME_ENTRY_create_by_NID(
+            WOLFSSL_X509_NAME_ENTRY** out, int nid, int type,
+            unsigned char* data, int dataSz);
+WOLFSSL_API int wolfSSL_X509_NAME_add_entry(WOLFSSL_X509_NAME* name,
+                              WOLFSSL_X509_NAME_ENTRY* entry, int idx, int set);
+WOLFSSL_API int wolfSSL_X509_NAME_add_entry_by_txt(WOLFSSL_X509_NAME *name,
+    const char *field, int type, const unsigned char *bytes, int len, int loc,
+    int set);
+WOLFSSL_API int wolfSSL_X509_NAME_cmp(const WOLFSSL_X509_NAME* x,
+            const WOLFSSL_X509_NAME* y);
+WOLFSSL_API WOLFSSL_X509_NAME* wolfSSL_X509_NAME_new(void);
 WOLFSSL_API int wolfSSL_check_private_key(const WOLFSSL* ssl);
 WOLFSSL_API void* wolfSSL_X509_get_ext_d2i(const WOLFSSL_X509* x509,
@@ -2255,6 +2634,4 @@
         const WOLFSSL_EVP_MD* digest, unsigned char* buf, unsigned int* len);
 WOLFSSL_API int wolfSSL_use_certificate(WOLFSSL* ssl, WOLFSSL_X509* x509);
-WOLFSSL_API int wolfSSL_use_certificate_ASN1(WOLFSSL* ssl, unsigned char* der,
-                                                                     int derSz);
 WOLFSSL_API int wolfSSL_use_PrivateKey(WOLFSSL* ssl, WOLFSSL_EVP_PKEY* pkey);
 WOLFSSL_API int wolfSSL_use_PrivateKey_ASN1(int pri, WOLFSSL* ssl,
@@ -2275,7 +2652,14 @@
 WOLFSSL_API void wolfSSL_CTX_set_cert_store(WOLFSSL_CTX* ctx,
                                                        WOLFSSL_X509_STORE* str);
-WOLFSSL_X509* wolfSSL_d2i_X509_bio(WOLFSSL_BIO* bio, WOLFSSL_X509** x509);
+WOLFSSL_API int wolfSSL_i2d_X509_bio(WOLFSSL_BIO* bio, WOLFSSL_X509* x509);
+#if !defined(NO_FILESYSTEM)
+WOLFSSL_API WOLFSSL_X509* wolfSSL_d2i_X509_fp(XFILE fp,
+                                               WOLFSSL_X509** x509);
+#endif
+WOLFSSL_API WOLFSSL_X509* wolfSSL_d2i_X509_bio(WOLFSSL_BIO* bio,
+                                               WOLFSSL_X509** x509);
 WOLFSSL_API WOLFSSL_X509_STORE* wolfSSL_CTX_get_cert_store(WOLFSSL_CTX* ctx);
 
+WOLFSSL_API size_t wolfSSL_BIO_wpending(const WOLFSSL_BIO *bio);
 WOLFSSL_API size_t wolfSSL_BIO_ctrl_pending(WOLFSSL_BIO *b);
 WOLFSSL_API size_t wolfSSL_get_server_random(const WOLFSSL *ssl,
@@ -2283,35 +2667,41 @@
 WOLFSSL_API size_t wolfSSL_get_client_random(const WOLFSSL* ssl,
                                               unsigned char* out, size_t outSz);
-WOLFSSL_API pem_password_cb* wolfSSL_CTX_get_default_passwd_cb(WOLFSSL_CTX *ctx);
-WOLFSSL_API void *wolfSSL_CTX_get_default_passwd_cb_userdata(WOLFSSL_CTX *ctx);
 WOLFSSL_API int wolfSSL_CTX_use_PrivateKey(WOLFSSL_CTX *ctx, WOLFSSL_EVP_PKEY *pkey);
 WOLFSSL_API WOLFSSL_X509 *wolfSSL_PEM_read_bio_X509(WOLFSSL_BIO *bp, WOLFSSL_X509 **x, pem_password_cb *cb, void *u);
 WOLFSSL_API WOLFSSL_X509 *wolfSSL_PEM_read_bio_X509_AUX
         (WOLFSSL_BIO *bp, WOLFSSL_X509 **x, pem_password_cb *cb, void *u);
+#ifndef NO_FILESYSTEM
+WOLFSSL_API WOLFSSL_X509_CRL *wolfSSL_PEM_read_X509_CRL(XFILE fp,
+        WOLFSSL_X509_CRL **x, pem_password_cb *cb, void *u);
+#endif
+WOLFSSL_API int wolfSSL_PEM_get_EVP_CIPHER_INFO(char* header,
+                                                EncryptedInfo* cipher);
+WOLFSSL_API int wolfSSL_PEM_do_header(EncryptedInfo* cipher,
+                                      unsigned char* data, long* len,
+                                      pem_password_cb* callback, void* ctx);
 
 /*lighttp compatibility */
 
-#include <wolfssl/openssl/asn1.h>
-struct WOLFSSL_X509_NAME_ENTRY {
-    WOLFSSL_ASN1_OBJECT* object; /* not defined yet */
-    WOLFSSL_ASN1_STRING  data;
-    WOLFSSL_ASN1_STRING* value;  /* points to data, for lighttpd port */
-    int set;
-    int size;
-};
-
-#if defined(HAVE_LIGHTY) || defined(WOLFSSL_MYSQL_COMPATIBLE) \
+struct WOLFSSL_ASN1_BIT_STRING {
+    int length;
+    int type;
+    char* data;
+    long flags;
+};
+
+
+#if    defined(OPENSSL_EXTRA) \
+    || defined(OPENSSL_ALL) \
+    || defined(HAVE_LIGHTY) \
+    || defined(WOLFSSL_MYSQL_COMPATIBLE) \
                          || defined(HAVE_STUNNEL) \
                          || defined(WOLFSSL_NGINX) \
-                         || defined(WOLFSSL_HAPROXY) \
-                         || defined(OPENSSL_EXTRA)
+    || defined(WOLFSSL_HAPROXY)
+WOLFSSL_API void wolfSSL_X509_NAME_ENTRY_free(WOLFSSL_X509_NAME_ENTRY* ne);
+WOLFSSL_API WOLFSSL_X509_NAME_ENTRY* wolfSSL_X509_NAME_ENTRY_new(void);
 WOLFSSL_API void wolfSSL_X509_NAME_free(WOLFSSL_X509_NAME *name);
 WOLFSSL_API char wolfSSL_CTX_use_certificate(WOLFSSL_CTX *ctx, WOLFSSL_X509 *x);
 WOLFSSL_API int wolfSSL_BIO_read_filename(WOLFSSL_BIO *b, const char *name);
 /* These are to be merged shortly */
-WOLFSSL_API const char *  wolfSSL_OBJ_nid2sn(int n);
-WOLFSSL_API int wolfSSL_OBJ_obj2nid(const WOLFSSL_ASN1_OBJECT *o);
-WOLFSSL_API int wolfSSL_OBJ_sn2nid(const char *sn);
-WOLFSSL_API void wolfSSL_CTX_set_verify_depth(WOLFSSL_CTX *ctx,int depth);
 WOLFSSL_API void wolfSSL_set_verify_depth(WOLFSSL *ssl,int depth);
 WOLFSSL_API void* wolfSSL_get_app_data( const WOLFSSL *ssl);
@@ -2321,18 +2711,28 @@
 WOLFSSL_API void wolfSSL_sk_X509_NAME_pop_free(WOLF_STACK_OF(WOLFSSL_X509_NAME)* sk, void f (WOLFSSL_X509_NAME*));
 WOLFSSL_API unsigned char *wolfSSL_SHA1(const unsigned char *d, size_t n, unsigned char *md);
+WOLFSSL_API unsigned char *wolfSSL_SHA256(const unsigned char *d, size_t n, unsigned char *md);
+WOLFSSL_API unsigned char *wolfSSL_SHA384(const unsigned char *d, size_t n, unsigned char *md);
+WOLFSSL_API unsigned char *wolfSSL_SHA512(const unsigned char *d, size_t n, unsigned char *md);
 WOLFSSL_API int wolfSSL_X509_check_private_key(WOLFSSL_X509*, WOLFSSL_EVP_PKEY*);
 WOLFSSL_API WOLF_STACK_OF(WOLFSSL_X509_NAME) *wolfSSL_dup_CA_list( WOLF_STACK_OF(WOLFSSL_X509_NAME) *sk );
-
-/* end lighttpd*/
-#endif
-#endif
-
-#if defined(HAVE_STUNNEL) || defined(HAVE_LIGHTY) \
+WOLFSSL_API int wolfSSL_X509_check_ca(WOLFSSL_X509 *x509);
+
+#ifndef NO_FILESYSTEM
+WOLFSSL_API long wolfSSL_BIO_set_fp(WOLFSSL_BIO *bio, XFILE fp, int c);
+WOLFSSL_API long wolfSSL_BIO_get_fp(WOLFSSL_BIO *bio, XFILE* fp);
+#endif
+
+#endif /* OPENSSL_EXTRA || OPENSSL_ALL || HAVE_LIGHTY || WOLFSSL_MYSQL_COMPATIBLE || HAVE_STUNNEL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */
+
+#endif /* OPENSSL_EXTRA || OPENSSL_ALL */
+
+
+#if defined(OPENSSL_ALL) \
+    || defined(HAVE_STUNNEL) \
+    || defined(HAVE_LIGHTY) \
                           || defined(WOLFSSL_MYSQL_COMPATIBLE) \
                           || defined(WOLFSSL_HAPROXY) \
                           || defined(OPENSSL_EXTRA)
 
-WOLFSSL_API char* wolfSSL_OBJ_nid2ln(int n);
-WOLFSSL_API int wolfSSL_OBJ_txt2nid(const char *sn);
 WOLFSSL_API WOLFSSL_BIO* wolfSSL_BIO_new_file(const char *filename, const char *mode);
 WOLFSSL_API long wolfSSL_CTX_set_tmp_dh(WOLFSSL_CTX*, WOLFSSL_DH*);
@@ -2341,13 +2741,29 @@
 WOLFSSL_API WOLFSSL_DSA *wolfSSL_PEM_read_bio_DSAparams(WOLFSSL_BIO *bp,
     WOLFSSL_DSA **x, pem_password_cb *cb, void *u);
+WOLFSSL_API int wolfSSL_PEM_write_bio_X509_REQ(WOLFSSL_BIO *bp,WOLFSSL_X509 *x);
+WOLFSSL_API int wolfSSL_PEM_write_bio_X509_AUX(WOLFSSL_BIO *bp,WOLFSSL_X509 *x);
 WOLFSSL_API int wolfSSL_PEM_write_bio_X509(WOLFSSL_BIO *bp, WOLFSSL_X509 *x);
-WOLFSSL_API long wolfSSL_CTX_get_options(WOLFSSL_CTX* ctx);
-
-
 
 #endif /* HAVE_STUNNEL || HAVE_LIGHTY */
 
-
-#if defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+#ifdef OPENSSL_ALL
+WOLFSSL_API int wolfSSL_i2d_X509_REQ(WOLFSSL_X509* req, unsigned char** out);
+WOLFSSL_API WOLFSSL_X509* wolfSSL_X509_REQ_new(void);
+WOLFSSL_API void wolfSSL_X509_REQ_free(WOLFSSL_X509* req);
+WOLFSSL_API int wolfSSL_X509_REQ_sign(WOLFSSL_X509 *req, WOLFSSL_EVP_PKEY *pkey,
+                                      const WOLFSSL_EVP_MD *md);
+WOLFSSL_API int wolfSSL_X509_REQ_set_subject_name(WOLFSSL_X509 *req,
+                                                  WOLFSSL_X509_NAME *name);
+WOLFSSL_API int wolfSSL_X509_REQ_set_pubkey(WOLFSSL_X509 *req,
+                                            WOLFSSL_EVP_PKEY *pkey);
+#endif
+
+
+#if defined(OPENSSL_ALL) \
+    || defined(HAVE_STUNNEL) \
+    || defined(WOLFSSL_NGINX) \
+    || defined(WOLFSSL_HAPROXY) \
+    || defined(OPENSSL_EXTRA) \
+    || defined(HAVE_LIGHTY)
 
 #include <wolfssl/openssl/crypto.h>
@@ -2359,4 +2775,7 @@
     void *(*r) (void *, size_t, const char *, int), void (*f) (void *));
 
+WOLFSSL_API void wolfSSL_CRYPTO_cleanup_all_ex_data(void);
+
+WOLFSSL_API WOLFSSL_BIGNUM* wolfSSL_DH_1536_prime(WOLFSSL_BIGNUM* bn);
 WOLFSSL_API WOLFSSL_DH *wolfSSL_DH_generate_parameters(int prime_len, int generator,
     void (*callback) (int, int, void *), void *cb_arg);
@@ -2379,4 +2798,5 @@
 WOLFSSL_API int wolfSSL_sk_X509_NAME_num(const WOLF_STACK_OF(WOLFSSL_X509_NAME) *s);
 
+WOLFSSL_API WOLFSSL_STACK* wolfSSL_sk_X509_new(void);
 WOLFSSL_API int wolfSSL_sk_X509_num(const WOLF_STACK_OF(WOLFSSL_X509) *s);
 
@@ -2389,6 +2809,4 @@
 WOLFSSL_API int        wolfSSL_CTX_add_session(WOLFSSL_CTX*, WOLFSSL_SESSION*);
 
-WOLFSSL_API WOLFSSL_CTX* wolfSSL_get_SSL_CTX(WOLFSSL* ssl);
-
 WOLFSSL_API int  wolfSSL_version(WOLFSSL*);
 
@@ -2398,6 +2816,4 @@
 
 WOLFSSL_API void* wolfSSL_sk_X509_value(WOLF_STACK_OF(WOLFSSL_X509)*, int);
-
-WOLFSSL_API WOLF_STACK_OF(WOLFSSL_X509)* wolfSSL_get_peer_cert_chain(const WOLFSSL*);
 
 WOLFSSL_API void* wolfSSL_SESSION_get_ex_data(const WOLFSSL_SESSION*, int);
@@ -2421,4 +2837,6 @@
 
 WOLFSSL_API VerifyCallback wolfSSL_CTX_get_verify_callback(WOLFSSL_CTX*);
+
+WOLFSSL_API VerifyCallback wolfSSL_get_verify_callback(WOLFSSL*);
 
 WOLFSSL_API void wolfSSL_CTX_set_servername_callback(WOLFSSL_CTX *,
@@ -2429,11 +2847,12 @@
 WOLFSSL_API void wolfSSL_CTX_set_servername_arg(WOLFSSL_CTX *, void*);
 
-WOLFSSL_API void WOLFSSL_ERR_remove_thread_state(void*);
+WOLFSSL_API void wolfSSL_ERR_remove_thread_state(void*);
+
+/* support for depricated old name */
+#define WOLFSSL_ERR_remove_thread_state wolfSSL_ERR_remove_thread_state
 
 #ifndef NO_FILESYSTEM
-WOLFSSL_API void wolfSSL_print_all_errors_fp(XFILE *fp);
-#endif
-
-WOLFSSL_API long wolfSSL_CTX_clear_options(WOLFSSL_CTX*, long);
+WOLFSSL_API void wolfSSL_print_all_errors_fp(XFILE fp);
+#endif
 
 WOLFSSL_API void wolfSSL_THREADID_set_callback(void (*threadid_func)(void*));
@@ -2445,8 +2864,9 @@
 
 WOLFSSL_API void wolfSSL_sk_X509_pop_free(WOLF_STACK_OF(WOLFSSL_X509)* sk, void f (WOLFSSL_X509*));
-#endif /* HAVE_STUNNEL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */
-
-#if defined(HAVE_STUNNEL) || defined(WOLFSSL_MYSQL_COMPATIBLE) \
-                          || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+#endif /* OPENSSL_ALL || HAVE_STUNNEL || WOLFSSL_NGINX || WOLFSSL_HAPROXY || HAVE_LIGHTY */
+
+#if defined(OPENSSL_ALL) || \
+    defined(HAVE_STUNNEL) || defined(WOLFSSL_MYSQL_COMPATIBLE) || \
+    defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
 
 WOLFSSL_API int wolfSSL_CTX_get_verify_mode(WOLFSSL_CTX* ctx);
@@ -2476,12 +2896,21 @@
 WOLFSSL_API int wolfSSL_CTX_set_msg_callback_arg(WOLFSSL_CTX *ctx, void* arg);
 WOLFSSL_API int wolfSSL_set_msg_callback_arg(WOLFSSL *ssl, void* arg);
-#endif
-
-#ifdef OPENSSL_EXTRA
 WOLFSSL_API unsigned long wolfSSL_ERR_peek_error_line_data(const char **file,
     int *line, const char **data, int *flags);
-#endif
-
-#if defined WOLFSSL_NGINX || defined WOLFSSL_HAPROXY
+WOLFSSL_API int wolfSSL_CTX_set_alpn_protos(WOLFSSL_CTX *ctx,
+    const unsigned char *protos, unsigned int protos_len);
+WOLFSSL_API void *wolfSSL_OPENSSL_memdup(const void *data,
+    size_t siz, const char* file, int line);
+WOLFSSL_API void wolfSSL_ERR_load_BIO_strings(void);
+#endif
+
+#if defined(OPENSSL_ALL) \
+    || defined(WOLFSSL_NGINX) \
+    || defined(WOLFSSL_HAPROXY) \
+    || defined(OPENSSL_EXTRA)
+WOLFSSL_API void wolfSSL_OPENSSL_config(char *config_name);
+#endif
+
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
 /* Not an OpenSSL API. */
 WOLFSSL_LOCAL int wolfSSL_get_ocsp_response(WOLFSSL* ssl, byte** response);
@@ -2490,7 +2919,9 @@
 /* Not an OpenSSL API. */
 WOLFSSL_API int wolfSSL_set_ocsp_url(WOLFSSL* ssl, char* url);
-
+#endif
+
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) \
+    || defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY)
 WOLFSSL_API WOLF_STACK_OF(WOLFSSL_CIPHER) *wolfSSL_get_ciphers_compat(const WOLFSSL *ssl);
-WOLFSSL_API void wolfSSL_OPENSSL_config(char *config_name);
 WOLFSSL_API int wolfSSL_X509_get_ex_new_index(int idx, void *arg, void *a,
     void *b, void *c);
@@ -2527,5 +2958,6 @@
 #endif
 
-#ifdef HAVE_OCSP
+#if defined(HAVE_OCSP) || defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) || \
+    defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
 WOLFSSL_API int wolfSSL_CTX_get_extra_chain_certs(WOLFSSL_CTX* ctx,
     WOLF_STACK_OF(X509)** chain);
@@ -2551,5 +2983,6 @@
     WOLFSSL_X509 *cert);
 
-#endif /* WOLFSSL_NGINX */
+#endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY ||
+    OPENSSL_EXTRA || HAVE_LIGHTY*/
 
 WOLFSSL_API void wolfSSL_get0_alpn_selected(const WOLFSSL *ssl,
@@ -2584,5 +3017,5 @@
 
 #ifdef OPENSSL_EXTRA
-#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
 WOLFSSL_API const unsigned char *SSL_SESSION_get0_id_context(
         const WOLFSSL_SESSION *sess, unsigned int *sid_ctx_length);
@@ -2597,15 +3030,39 @@
 WOLFSSL_API void *X509_get_X509_PUBKEY(void * x);
 WOLFSSL_API int X509_PUBKEY_get0_param(WOLFSSL_ASN1_OBJECT **ppkalg, const unsigned char **pk, int *ppklen, void **pa, WOLFSSL_EVP_PKEY *pub);
-WOLFSSL_API int EVP_PKEY_bits(WOLFSSL_EVP_PKEY *pkey);
-WOLFSSL_API int i2d_X509(WOLFSSL_X509 *x, unsigned char **out);
 WOLFSSL_API int i2t_ASN1_OBJECT(char *buf, int buf_len, WOLFSSL_ASN1_OBJECT *a);
 WOLFSSL_API void SSL_CTX_set_tmp_dh_callback(WOLFSSL_CTX *ctx, WOLFSSL_DH *(*dh) (WOLFSSL *ssl, int is_export, int keylength));
 WOLFSSL_API WOLF_STACK_OF(SSL_COMP) *SSL_COMP_get_compression_methods(void);
 WOLFSSL_API int X509_STORE_load_locations(WOLFSSL_X509_STORE *ctx, const char *file, const char *dir);
+WOLFSSL_API int wolfSSL_X509_STORE_add_crl(WOLFSSL_X509_STORE *ctx, WOLFSSL_X509_CRL *x);
 WOLFSSL_API int wolfSSL_sk_SSL_CIPHER_num(const void * p);
 WOLFSSL_API int wolfSSL_sk_SSL_COMP_zero(WOLFSSL_STACK* st);
 WOLFSSL_API WOLFSSL_CIPHER* wolfSSL_sk_SSL_CIPHER_value(void *ciphers, int idx);
 WOLFSSL_API void ERR_load_SSL_strings(void);
+WOLFSSL_API void wolfSSL_EC_POINT_dump(const char *msg, const WOLFSSL_EC_POINT *p);
+
+WOLFSSL_API const char *wolfSSL_ASN1_tag2str(int tag);
+WOLFSSL_API int wolfSSL_ASN1_STRING_print_ex(WOLFSSL_BIO *out, WOLFSSL_ASN1_STRING *str, unsigned long flags);
+WOLFSSL_API int wolfSSL_ASN1_TIME_get_length(WOLFSSL_ASN1_TIME *t);
+WOLFSSL_API unsigned char* wolfSSL_ASN1_TIME_get_data(WOLFSSL_ASN1_TIME *t);
+WOLFSSL_API WOLFSSL_ASN1_TIME *wolfSSL_ASN1_TIME_to_generalizedtime(WOLFSSL_ASN1_TIME *t,
+                                                                WOLFSSL_ASN1_TIME **out);
+WOLFSSL_API int wolfSSL_i2c_ASN1_INTEGER(WOLFSSL_ASN1_INTEGER *a, unsigned char **pp);
+WOLFSSL_API int wolfSSL_X509_CA_num(WOLFSSL_X509_STORE *store);
+WOLFSSL_API long wolfSSL_X509_get_version(const WOLFSSL_X509 *x);
+WOLFSSL_API int wolfSSL_X509_get_signature_nid(const WOLFSSL_X509* x);
+
+WOLFSSL_API int wolfSSL_PEM_write_bio_PKCS8PrivateKey(WOLFSSL_BIO* bio,
+    WOLFSSL_EVP_PKEY* pkey, const WOLFSSL_EVP_CIPHER* enc, char* passwd,
+    int passwdSz, pem_password_cb* cb, void* ctx);
+WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_d2i_PKCS8PrivateKey_bio(WOLFSSL_BIO* bio,
+    WOLFSSL_EVP_PKEY** pkey, pem_password_cb* cb, void* u);
+WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_d2i_AutoPrivateKey(
+    WOLFSSL_EVP_PKEY** pkey, const unsigned char** data, long length);
+
 #endif /* OPENSSL_EXTRA */
+
+#ifdef HAVE_PK_CALLBACKS
+WOLFSSL_API int wolfSSL_CTX_IsPrivatePkSet(WOLFSSL_CTX* ctx);
+#endif
 
 #ifdef __cplusplus
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/test.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/test.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/test.h	(revision 372)
@@ -11,4 +11,8 @@
 #include <wolfssl/wolfcrypt/error-crypt.h>
 #include <wolfssl/wolfcrypt/random.h>
+#include <wolfssl/wolfcrypt/mem_track.h>
+#if defined(OPENSSL_EXTRA) && defined(SHOW_CERTS)
+    #include <wolfssl/wolfcrypt/asn.h> /* for domain component NID value */
+#endif
 
 #ifdef ATOMIC_USER
@@ -25,4 +29,7 @@
         #include <wolfssl/wolfcrypt/ecc.h>
     #endif /* HAVE_ECC */
+    #ifndef NO_DH
+        #include <wolfssl/wolfcrypt/dh.h>
+    #endif /* !NO_DH */
     #ifdef HAVE_ED25519
         #include <wolfssl/wolfcrypt/ed25519.h>
@@ -59,8 +66,4 @@
         #define sleep(t)  osDelay(t/1000+1) ;
     #endif
-
-    static int wolfssl_tcp_select(int sd, int timeout)
-    {        return 0 ;  }
-        #define tcp_select(sd,t)   wolfssl_tcp_select(sd, t)  /* avoid conflicting Keil TCP tcp_select */
 #elif defined(WOLFSSL_TIRTOS)
     #include <string.h>
@@ -122,5 +125,4 @@
     #include <wolfssl/wolfcrypt/port/cavium/cavium_nitrox.h>
 #endif
-
 #ifdef _MSC_VER
     /* disable conversion warning */
@@ -136,5 +138,5 @@
 #ifndef WOLFSSL_HAVE_MIN
     #define WOLFSSL_HAVE_MIN
-    static INLINE word32 min(word32 a, word32 b)
+    static WC_INLINE word32 min(word32 a, word32 b)
     {
         return a > b ? b : a;
@@ -181,15 +183,4 @@
 #endif
 
-
-#ifdef USE_WINDOWS_API
-    #define CloseSocket(s) closesocket(s)
-    #define StartTCP() { WSADATA wsd; WSAStartup(0x0002, &wsd); }
-#elif defined(WOLFSSL_MDK_ARM) || defined(WOLFSSL_KEIL_TCP_NET)
-    #define CloseSocket(s) closesocket(s)
-    #define StartTCP()
-#else
-    #define CloseSocket(s) close(s)
-    #define StartTCP()
-#endif
 
 
@@ -230,14 +221,27 @@
 
 
+#ifndef WOLFSSL_NO_TLS12
 #define SERVER_DEFAULT_VERSION 3
+#else
+#define SERVER_DEFAULT_VERSION 4
+#endif
 #define SERVER_DTLS_DEFAULT_VERSION (-2)
 #define SERVER_INVALID_VERSION (-99)
+#define SERVER_DOWNGRADE_VERSION (-98)
+#ifndef WOLFSSL_NO_TLS12
 #define CLIENT_DEFAULT_VERSION 3
+#else
+#define CLIENT_DEFAULT_VERSION 4
+#endif
 #define CLIENT_DTLS_DEFAULT_VERSION (-2)
 #define CLIENT_INVALID_VERSION (-99)
+#define CLIENT_DOWNGRADE_VERSION (-98)
+#define EITHER_DOWNGRADE_VERSION (-97)
 #if !defined(NO_FILESYSTEM) && defined(WOLFSSL_MAX_STRENGTH)
     #define DEFAULT_MIN_DHKEY_BITS 2048
+    #define DEFAULT_MAX_DHKEY_BITS 3072
 #else
     #define DEFAULT_MIN_DHKEY_BITS 1024
+    #define DEFAULT_MAX_DHKEY_BITS 2048
 #endif
 #if !defined(NO_FILESYSTEM) && defined(WOLFSSL_MAX_STRENGTH)
@@ -257,7 +261,9 @@
 #define eccCertFile    "certs/server-ecc.pem"
 #define eccKeyFile     "certs/ecc-key.pem"
+#define eccRsaCertFile "certs/server-ecc-rsa.pem"
 #define svrCertFile    "certs/server-cert.pem"
 #define svrKeyFile     "certs/server-key.pem"
 #define cliCertFile    "certs/client-cert.pem"
+#define cliCertDerFile "certs/client-cert.der"
 #define cliKeyFile     "certs/client-key.pem"
 #define ntruCertFile   "certs/ntru-cert.pem"
@@ -268,4 +274,9 @@
 #define caEccCertFile  "certs/ca-ecc-cert/pem"
 #define crlPemDir      "certs/crl"
+#define edCertFile     "certs/ed25519/server-ed25519-cert.pem"
+#define edKeyFile      "certs/ed25519/server-ed25519-priv.pem"
+#define cliEdCertFile  "certs/ed25519/client-ed25519.pem"
+#define cliEdKeyFile   "certs/ed25519/client-ed25519-priv.pem"
+#define caEdCertFile   "certs/ed25519/ca-ed25519.pem"
 #ifdef HAVE_WNR
     /* Whitewood netRandom default config file */
@@ -276,7 +287,9 @@
 #define eccCertFile    "./certs/server-ecc.pem"
 #define eccKeyFile     "./certs/ecc-key.pem"
+#define eccRsaCertFile "./certs/server-ecc-rsa.pem"
 #define svrCertFile    "./certs/server-cert.pem"
 #define svrKeyFile     "./certs/server-key.pem"
 #define cliCertFile    "./certs/client-cert.pem"
+#define cliCertDerFile "./certs/client-cert.der"
 #define cliKeyFile     "./certs/client-key.pem"
 #define ntruCertFile   "./certs/ntru-cert.pem"
@@ -287,4 +300,9 @@
 #define caEccCertFile  "./certs/ca-ecc-cert.pem"
 #define crlPemDir      "./certs/crl"
+#define edCertFile     "./certs/ed25519/server-ed25519.pem"
+#define edKeyFile      "./certs/ed25519/server-ed25519-priv.pem"
+#define cliEdCertFile  "./certs/ed25519/client-ed25519.pem"
+#define cliEdKeyFile   "./certs/ed25519/client-ed25519-priv.pem"
+#define caEdCertFile   "./certs/ed25519/root-ed25519.pem"
 #ifdef HAVE_WNR
     /* Whitewood netRandom default config file */
@@ -304,5 +322,5 @@
 
 
-static INLINE void InitTcpReady(tcp_ready* ready)
+static WC_INLINE void InitTcpReady(tcp_ready* ready)
 {
     ready->ready = 0;
@@ -317,5 +335,5 @@
 
 
-static INLINE void FreeTcpReady(tcp_ready* ready)
+static WC_INLINE void FreeTcpReady(tcp_ready* ready)
 {
 #ifdef SINGLE_THREADED
@@ -338,4 +356,5 @@
     ssl_callback ssl_ready;
     ssl_callback on_result;
+    WOLFSSL_CTX* ctx;
 } callback_functions;
 
@@ -367,11 +386,29 @@
 
 
-#if defined(__GNUC__)
-    #define WC_NORETURN __attribute__((noreturn))
+
+#ifndef MY_EX_USAGE
+#define MY_EX_USAGE 2
+#endif
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif
+
+#ifdef WOLFSSL_FORCE_MALLOC_FAIL_TEST
+    #define XEXIT(rc)   return rc
+    #define XEXIT_T(rc) return (THREAD_RETURN)rc
 #else
-    #define WC_NORETURN
-#endif
-
-static INLINE WC_NORETURN void err_sys(const char* msg)
+    #define XEXIT(rc)   exit((int)(rc))
+    #define XEXIT_T(rc) exit((int)(rc))
+#endif
+
+
+static WC_INLINE
+#ifdef WOLFSSL_FORCE_MALLOC_FAIL_TEST
+THREAD_RETURN
+#else
+WC_NORETURN void
+#endif
+err_sys(const char* msg)
 {
     printf("wolfSSL error: %s\n", msg);
@@ -387,15 +424,13 @@
 #endif
     {
-        exit(EXIT_FAILURE);
-    }
-}
-
-
-#define MY_EX_USAGE 2
+        XEXIT_T(EXIT_FAILURE);
+    }
+}
+
 
 extern int   myoptind;
 extern char* myoptarg;
 
-static INLINE int mygetopt(int argc, char** argv, const char* optstring)
+static WC_INLINE int mygetopt(int argc, char** argv, const char* optstring)
 {
     static char* next = NULL;
@@ -461,20 +496,71 @@
 
 
-#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
-
-static INLINE int PasswordCallBack(char* passwd, int sz, int rw, void* userdata)
+#ifdef WOLFSSL_ENCRYPTED_KEYS
+
+static WC_INLINE int PasswordCallBack(char* passwd, int sz, int rw, void* userdata)
 {
     (void)rw;
     (void)userdata;
+    if (userdata != NULL) {
+        strncpy(passwd, (char*)userdata, sz);
+        return (int)XSTRLEN((char*)userdata);
+    }
+    else {
     strncpy(passwd, "yassl123", sz);
     return 8;
 }
-
-#endif
-
+}
+
+#endif
+
+static const char* client_showpeer_msg[][8] = {
+    /* English */
+    {
+        "SSL version is",
+        "SSL cipher suite is",
+        "SSL curve name is",
+        "SSL DH size is",
+        "SSL reused session",
+        "Alternate cert chain used",
+        "peer's cert info:",
+        NULL
+    },
+    /* Japanese */
+    {
+        "SSL バージョンは",
+        "SSL 暗号スイートは",
+        "SSL 曲線名は",
+        "SSL DH サイズは",
+        "SSL 再利用セッション",
+        "代替証明チェーンを使用",
+        "相手方証明書情報",
+        NULL
+    }
+};
 
 #if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS)
-
-static INLINE void ShowX509(WOLFSSL_X509* x509, const char* hdr)
+static const char* client_showx509_msg[][5] = {
+    /* English */
+    {
+        "issuer",
+        "subject",
+        "altname",
+        "serial number",
+        NULL
+    },
+    /* Japanese */
+    {
+        "発行者",
+        "サブジェクト",
+        "代替名",
+        "シリアル番号",
+        NULL
+    },
+};
+
+/* lng_index is to specify the language for displaying message.              */
+/* 0:English, 1:Japanese                                                     */
+static WC_INLINE void ShowX509Ex(WOLFSSL_X509* x509, const char* hdr, 
+                                                                 int lng_index)
 {
     char* altName;
@@ -484,4 +570,5 @@
     int   ret;
     int   sz = sizeof(serial);
+    const char** words = client_showx509_msg[lng_index];
 
     if (x509 == NULL) {
@@ -495,8 +582,8 @@
                                      wolfSSL_X509_get_subject_name(x509), 0, 0);
 
-    printf("%s\n issuer : %s\n subject: %s\n", hdr, issuer, subject);
+    printf("%s\n %s : %s\n %s: %s\n", hdr, words[0], issuer, words[1], subject);
 
     while ( (altName = wolfSSL_X509_get_next_altname(x509)) != NULL)
-        printf(" altname = %s\n", altName);
+        printf(" %s = %s\n", words[2], altName);
 
     ret = wolfSSL_X509_get_serial_number(x509, serial, &sz);
@@ -508,5 +595,5 @@
         /* testsuite has multiple threads writing to stdout, get output
            message ready to write once */
-        strLen = sprintf(serialMsg, " serial number");
+        strLen = sprintf(serialMsg, " %s", words[3]);
         for (i = 0; i < sz; i++)
             sprintf(serialMsg + strLen + (i*3), ":%02x ", serial[i]);
@@ -516,4 +603,33 @@
     XFREE(subject, 0, DYNAMIC_TYPE_OPENSSL);
     XFREE(issuer,  0, DYNAMIC_TYPE_OPENSSL);
+
+#if defined(OPENSSL_EXTRA) && defined(SHOW_CERTS)
+    {
+        WOLFSSL_BIO* bio;
+        char buf[256]; /* should be size of ASN_NAME_MAX */
+        int  textSz;
+
+
+        /* print out domain component if certificate has it */
+        textSz = wolfSSL_X509_NAME_get_text_by_NID(
+                wolfSSL_X509_get_subject_name(x509), NID_domainComponent,
+                buf, sizeof(buf));
+        if (textSz > 0) {
+            printf("Domain Component = %s\n", buf);
+        }
+
+        bio = wolfSSL_BIO_new(wolfSSL_BIO_s_file());
+        if (bio != NULL) {
+            wolfSSL_BIO_set_fp(bio, stdout, BIO_NOCLOSE);
+            wolfSSL_X509_print(bio, x509);
+            wolfSSL_BIO_free(bio);
+        }
+    }
+#endif
+}
+/* original ShowX509 to maintain compatibility */
+static WC_INLINE void ShowX509(WOLFSSL_X509* x509, const char* hdr)
+{
+    ShowX509Ex(x509, hdr, 0);
 }
 
@@ -521,5 +637,5 @@
 
 #if defined(SESSION_CERTS) && defined(SHOW_CERTS)
-static INLINE void ShowX509Chain(WOLFSSL_X509_CHAIN* chain, int count,
+static WC_INLINE void ShowX509Chain(WOLFSSL_X509_CHAIN* chain, int count,
     const char* hdr)
 {
@@ -544,7 +660,11 @@
 #endif
 
-static INLINE void showPeer(WOLFSSL* ssl)
+/* lng_index is to specify the language for displaying message.              */
+/* 0:English, 1:Japanese                                                     */
+static WC_INLINE void showPeerEx(WOLFSSL* ssl, int lng_index)
 {
     WOLFSSL_CIPHER* cipher;
+    const char** words = client_showpeer_msg[lng_index];
+
 #ifdef HAVE_ECC
     const char *name;
@@ -556,5 +676,5 @@
     WOLFSSL_X509* peer = wolfSSL_get_peer_certificate(ssl);
     if (peer)
-        ShowX509(peer, "peer's cert info:");
+        ShowX509Ex(peer, words[6], lng_index);
     else
         printf("peer has no cert!\n");
@@ -565,26 +685,26 @@
     printf("Peer verify result = %lu\n", wolfSSL_get_verify_result(ssl));
 #endif /* SHOW_CERTS */
-    printf("SSL version is %s\n", wolfSSL_get_version(ssl));
+    printf("%s %s\n", words[0], wolfSSL_get_version(ssl));
 
     cipher = wolfSSL_get_current_cipher(ssl);
 #ifdef HAVE_QSH
-    printf("SSL cipher suite is %s%s\n", (wolfSSL_isQSH(ssl))? "QSH:": "",
+    printf("%s %s%s\n", words[1], (wolfSSL_isQSH(ssl))? "QSH:": "",
             wolfSSL_CIPHER_get_name(cipher));
 #else
-    printf("SSL cipher suite is %s\n", wolfSSL_CIPHER_get_name(cipher));
+    printf("%s %s\n", words[1], wolfSSL_CIPHER_get_name(cipher));
 #endif
 #ifdef HAVE_ECC
     if ((name = wolfSSL_get_curve_name(ssl)) != NULL)
-        printf("SSL curve name is %s\n", name);
+        printf("%s %s\n", words[2], name);
 #endif
 #ifndef NO_DH
     if ((bits = wolfSSL_GetDhKey_Sz(ssl)) > 0)
-        printf("SSL DH size is %d bits\n", bits);
+        printf("%s %d bits\n", words[3], bits);
 #endif
     if (wolfSSL_session_reused(ssl))
-        printf("SSL reused session\n");
+        printf("%s\n", words[4]);
 #ifdef WOLFSSL_ALT_CERT_CHAINS
     if (wolfSSL_is_peer_alt_cert_chain(ssl))
-        printf("Alternate cert chain used\n");
+        printf("%s\n", words[5]);
 #endif
 
@@ -606,7 +726,11 @@
   (void)ssl;
 }
-
-
-static INLINE void build_addr(SOCKADDR_IN_T* addr, const char* peer,
+/* original showPeer to maintain compatibility */
+static WC_INLINE void showPeer(WOLFSSL* ssl)
+{
+    showPeerEx(ssl, 0);
+}
+
+static WC_INLINE void build_addr(SOCKADDR_IN_T* addr, const char* peer,
                               word16 port, int udp, int sctp)
 {
@@ -619,5 +743,5 @@
         err_sys("invalid argument to build_addr, addr is NULL");
 
-    memset(addr, 0, sizeof(SOCKADDR_IN_T));
+    XMEMSET(addr, 0, sizeof(SOCKADDR_IN_T));
 
 #ifndef TEST_IPV6
@@ -662,6 +786,7 @@
     addr->sin6_family = AF_INET_V;
     addr->sin6_port = XHTONS(port);
-    if (peer == INADDR_ANY)
+    if ((size_t)peer == INADDR_ANY) {
         addr->sin6_addr = in6addr_any;
+    }
     else {
         #ifdef HAVE_GETADDRINFO
@@ -671,5 +796,5 @@
             char   strPort[80];
 
-            memset(&hints, 0, sizeof(hints));
+            XMEMSET(&hints, 0, sizeof(hints));
 
             hints.ai_family   = AF_INET_V;
@@ -707,5 +832,5 @@
 
 
-static INLINE void tcp_socket(SOCKET_T* sockfd, int udp, int sctp)
+static WC_INLINE void tcp_socket(SOCKET_T* sockfd, int udp, int sctp)
 {
     (void)sctp;
@@ -753,5 +878,5 @@
 }
 
-static INLINE void tcp_connect(SOCKET_T* sockfd, const char* ip, word16 port,
+static WC_INLINE void tcp_connect(SOCKET_T* sockfd, const char* ip, word16 port,
                                int udp, int sctp, WOLFSSL* ssl)
 {
@@ -770,5 +895,5 @@
 
 
-static INLINE void udp_connect(SOCKET_T* sockfd, void* addr, int addrSz)
+static WC_INLINE void udp_connect(SOCKET_T* sockfd, void* addr, int addrSz)
 {
     if (connect(*sockfd, (const struct sockaddr*)addr, addrSz) != 0)
@@ -787,9 +912,13 @@
 #if !defined(WOLFSSL_MDK_ARM) && !defined(WOLFSSL_KEIL_TCP_NET) && \
                                  !defined(WOLFSSL_TIRTOS)
-static INLINE int tcp_select(SOCKET_T socketfd, int to_sec)
+static WC_INLINE int tcp_select(SOCKET_T socketfd, int to_sec)
 {
     fd_set recvfds, errfds;
     SOCKET_T nfds = socketfd + 1;
+#if !defined(__INTEGRITY)
     struct timeval timeout = { (to_sec > 0) ? to_sec : 0, 0};
+#else
+    struct timeval timeout;
+#endif
     int result;
 
@@ -799,4 +928,7 @@
     FD_SET(socketfd, &errfds);
 
+#if defined(__INTEGRITY)
+    timeout.tv_sec = (long long)(to_sec > 0) ? to_sec : 0, 0;
+#endif
     result = select(nfds, &recvfds, NULL, &errfds, &timeout);
 
@@ -812,6 +944,6 @@
     return TEST_SELECT_FAIL;
 }
-#elif defined(WOLFSSL_TIRTOS)
-static INLINE int tcp_select(SOCKET_T socketfd, int to_sec)
+#elif defined(WOLFSSL_TIRTOS) || defined(WOLFSSL_KEIL_TCP_NET)
+static WC_INLINE int tcp_select(SOCKET_T socketfd, int to_sec)
 {
     return TEST_RECV_READY;
@@ -820,5 +952,5 @@
 
 
-static INLINE void tcp_listen(SOCKET_T* sockfd, word16* port, int useAnyAddr,
+static WC_INLINE void tcp_listen(SOCKET_T* sockfd, word16* port, int useAnyAddr,
                               int udp, int sctp)
 {
@@ -844,5 +976,10 @@
         err_sys("tcp bind failed");
     if (!udp) {
-        if (listen(*sockfd, 5) != 0)
+        #ifdef WOLFSSL_KEIL_TCP_NET
+            #define SOCK_LISTEN_MAX_QUEUE 1
+        #else
+            #define SOCK_LISTEN_MAX_QUEUE 5
+        #endif
+        if (listen(*sockfd, SOCK_LISTEN_MAX_QUEUE) != 0)
             err_sys("tcp listen failed");
     }
@@ -863,5 +1000,5 @@
 
 #if 0
-static INLINE int udp_read_connect(SOCKET_T sockfd)
+static WC_INLINE int udp_read_connect(SOCKET_T sockfd)
 {
     SOCKADDR_IN_T cliaddr;
@@ -884,5 +1021,5 @@
 #endif
 
-static INLINE void udp_accept(SOCKET_T* sockfd, SOCKET_T* clientfd,
+static WC_INLINE void udp_accept(SOCKET_T* sockfd, SOCKET_T* clientfd,
                               int useAnyAddr, word16 port, func_args* args)
 {
@@ -941,5 +1078,5 @@
 }
 
-static INLINE void tcp_accept(SOCKET_T* sockfd, SOCKET_T* clientfd,
+static WC_INLINE void tcp_accept(SOCKET_T* sockfd, SOCKET_T* clientfd,
                               func_args* args, word16 port, int useAnyAddr,
                               int udp, int sctp, int ready_file, int do_listen)
@@ -982,5 +1119,5 @@
         if (ready_file) {
         #if !defined(NO_FILESYSTEM) || defined(FORCE_BUFFER_TEST)
-            FILE* srf = NULL;
+            XFILE srf = NULL;
             if (args)
                 ready = args->signal;
@@ -1011,5 +1148,5 @@
 
 
-static INLINE void tcp_set_nonblocking(SOCKET_T* sockfd)
+static WC_INLINE void tcp_set_nonblocking(SOCKET_T* sockfd)
 {
     #ifdef USE_WINDOWS_API
@@ -1037,5 +1174,5 @@
 static const char* kIdentityStr = "Client_identity";
 
-static INLINE unsigned int my_psk_client_cb(WOLFSSL* ssl, const char* hint,
+static WC_INLINE unsigned int my_psk_client_cb(WOLFSSL* ssl, const char* hint,
         char* identity, unsigned int id_max_len, unsigned char* key,
         unsigned int key_max_len)
@@ -1048,16 +1185,31 @@
     strncpy(identity, kIdentityStr, id_max_len);
 
+    if (wolfSSL_GetVersion(ssl) < WOLFSSL_TLSV1_3) {
     /* test key in hex is 0x1a2b3c4d , in decimal 439,041,101 , we're using
        unsigned binary */
-    key[0] = 26;
-    key[1] = 43;
-    key[2] = 60;
-    key[3] = 77;
+        key[0] = 0x1a;
+        key[1] = 0x2b;
+        key[2] = 0x3c;
+        key[3] = 0x4d;
+
 
     return 4;   /* length of key in octets or 0 for error */
 }
-
-
-static INLINE unsigned int my_psk_server_cb(WOLFSSL* ssl, const char* identity,
+    else {
+        int i;
+        int b = 0x01;
+
+        for (i = 0; i < 32; i++, b += 0x22) {
+            if (b >= 0x100)
+                b = 0x01;
+            key[i] = b;
+        }
+
+        return 32;   /* length of key in octets or 0 for error */
+    }
+}
+
+
+static WC_INLINE unsigned int my_psk_server_cb(WOLFSSL* ssl, const char* identity,
         unsigned char* key, unsigned int key_max_len)
 {
@@ -1069,12 +1221,79 @@
         return 0;
 
+    if (wolfSSL_GetVersion(ssl) < WOLFSSL_TLSV1_3) {
     /* test key in hex is 0x1a2b3c4d , in decimal 439,041,101 , we're using
        unsigned binary */
-    key[0] = 26;
-    key[1] = 43;
-    key[2] = 60;
-    key[3] = 77;
+        key[0] = 0x1a;
+        key[1] = 0x2b;
+        key[2] = 0x3c;
+        key[3] = 0x4d;
+
 
     return 4;   /* length of key in octets or 0 for error */
+}
+    else {
+        int i;
+        int b = 0x01;
+
+        for (i = 0; i < 32; i++, b += 0x22) {
+            if (b >= 0x100)
+                b = 0x01;
+            key[i] = b;
+        }
+
+        return 32;   /* length of key in octets or 0 for error */
+    }
+}
+
+
+static WC_INLINE unsigned int my_psk_client_tls13_cb(WOLFSSL* ssl,
+        const char* hint, char* identity, unsigned int id_max_len,
+        unsigned char* key, unsigned int key_max_len, const char** ciphersuite)
+{
+    int i;
+    int b = 0x01;
+
+    (void)ssl;
+    (void)hint;
+    (void)key_max_len;
+
+    /* see internal.h MAX_PSK_ID_LEN for PSK identity limit */
+    strncpy(identity, kIdentityStr, id_max_len);
+
+    for (i = 0; i < 32; i++, b += 0x22) {
+        if (b >= 0x100)
+            b = 0x01;
+        key[i] = b;
+    }
+
+    *ciphersuite = "TLS13-AES128-GCM-SHA256";
+
+    return 32;   /* length of key in octets or 0 for error */
+}
+
+
+static WC_INLINE unsigned int my_psk_server_tls13_cb(WOLFSSL* ssl,
+        const char* identity, unsigned char* key, unsigned int key_max_len,
+        const char** ciphersuite)
+{
+    int i;
+    int b = 0x01;
+
+    (void)ssl;
+    (void)key_max_len;
+
+    /* see internal.h MAX_PSK_ID_LEN for PSK identity limit */
+    if (strncmp(identity, kIdentityStr, strlen(kIdentityStr)) != 0)
+        return 0;
+
+    for (i = 0; i < 32; i++, b += 0x22) {
+        if (b >= 0x100)
+            b = 0x01;
+        key[i] = b;
+    }
+
+    *ciphersuite = "TLS13-AES128-GCM-SHA256";
+
+    return 32;   /* length of key in octets or 0 for error */
 }
 
@@ -1090,5 +1309,5 @@
     #include <windows.h>
 
-    static INLINE double current_time(int reset)
+    static WC_INLINE double current_time(int reset)
     {
         static int init = 0;
@@ -1112,8 +1331,8 @@
 #else
 
-#if !defined(WOLFSSL_MDK_ARM) && !defined(WOLFSSL_KEIL_TCP_NET)
+#if !defined(WOLFSSL_MDK_ARM) && !defined(WOLFSSL_KEIL_TCP_NET) && !defined(WOLFSSL_CHIBIOS)
     #include <sys/time.h>
 
-    static INLINE double current_time(int reset)
+    static WC_INLINE double current_time(int reset)
     {
         struct timeval tv;
@@ -1129,4 +1348,40 @@
 
 
+#if defined(HAVE_OCSP) && defined(WOLFSSL_NONBLOCK_OCSP)
+static WC_INLINE int OCSPIOCb(void* ioCtx, const char* url, int urlSz,
+    unsigned char* request, int requestSz, unsigned char** response)
+{
+#ifdef TEST_NONBLOCK_CERTS
+    static int ioCbCnt = 0;
+#endif
+
+    (void)ioCtx;
+    (void)url;
+    (void)urlSz;
+    (void)request;
+    (void)requestSz;
+    (void)response;
+
+#ifdef TEST_NONBLOCK_CERTS
+    if (ioCbCnt) {
+        ioCbCnt = 0;
+        return EmbedOcspLookup(ioCtx, url, urlSz, request, requestSz, response);
+    }
+    else {
+        ioCbCnt = 1;
+        return WOLFSSL_CBIO_ERR_WANT_READ;
+    }
+#else
+    return EmbedOcspLookup(ioCtx, url, urlSz, request, requestSz, response);
+#endif
+}
+
+static WC_INLINE void OCSPRespFreeCb(void* ioCtx, unsigned char* response)
+{
+    (void)ioCtx;
+    (void)response;
+}
+#endif
+
 #if !defined(NO_CERTS)
     #if !defined(NO_FILESYSTEM) || \
@@ -1134,9 +1389,9 @@
 
     /* reads file size, allocates buffer, reads into buffer, returns buffer */
-    static INLINE int load_file(const char* fname, byte** buf, size_t* bufLen)
+    static WC_INLINE int load_file(const char* fname, byte** buf, size_t* bufLen)
     {
         int ret;
         long int fileSz;
-        FILE* file;
+        XFILE file;
 
         if (fname == NULL || buf == NULL || bufLen == NULL)
@@ -1186,5 +1441,5 @@
     };
 
-    static INLINE void load_buffer(WOLFSSL_CTX* ctx, const char* fname, int type)
+    static WC_INLINE void load_buffer(WOLFSSL_CTX* ctx, const char* fname, int type)
     {
         int format = WOLFSSL_FILETYPE_PEM;
@@ -1225,18 +1480,107 @@
             free(buff);
     }
+
+    static WC_INLINE void load_ssl_buffer(WOLFSSL* ssl, const char* fname, int type)
+    {
+        int format = WOLFSSL_FILETYPE_PEM;
+        byte* buff = NULL;
+        size_t sz = 0;
+
+        if (load_file(fname, &buff, &sz) != 0) {
+            err_sys("can't open file for buffer load "
+                    "Please run from wolfSSL home directory if not");
+        }
+
+        /* determine format */
+        if (strstr(fname, ".der"))
+            format = WOLFSSL_FILETYPE_ASN1;
+
+        if (type == WOLFSSL_CA) {
+            /* verify certs (CA's) use the shared ctx->cm (WOLFSSL_CERT_MANAGER) */
+            WOLFSSL_CTX* ctx = wolfSSL_get_SSL_CTX(ssl);
+            if (wolfSSL_CTX_load_verify_buffer(ctx, buff, (long)sz, format)
+                                              != WOLFSSL_SUCCESS)
+                err_sys("can't load buffer ca file");
+        }
+        else if (type == WOLFSSL_CERT) {
+            if (wolfSSL_use_certificate_buffer(ssl, buff, (long)sz,
+                        format) != WOLFSSL_SUCCESS)
+                err_sys("can't load buffer cert file");
+        }
+        else if (type == WOLFSSL_KEY) {
+            if (wolfSSL_use_PrivateKey_buffer(ssl, buff, (long)sz,
+                        format) != WOLFSSL_SUCCESS)
+                err_sys("can't load buffer key file");
+        }
+        else if (type == WOLFSSL_CERT_CHAIN) {
+            if (wolfSSL_use_certificate_chain_buffer_format(ssl, buff,
+                    (long)sz, format) != WOLFSSL_SUCCESS)
+                err_sys("can't load cert chain buffer");
+        }
+
+        if (buff)
+            free(buff);
+    }
+
+    #ifdef TEST_PK_PRIVKEY
+    static WC_INLINE int load_key_file(const char* fname, byte** derBuf, word32* derLen)
+    {
+        int ret;
+        byte* buf = NULL;
+        size_t bufLen;
+
+        ret = load_file(fname, &buf, &bufLen);
+        if (ret != 0)
+            return ret;
+
+        *derBuf = (byte*)malloc(bufLen);
+        if (*derBuf == NULL) {
+            free(buf);
+            return MEMORY_E;
+        }
+
+        ret = wc_KeyPemToDer(buf, (word32)bufLen, *derBuf, (word32)bufLen, NULL);
+        if (ret < 0) {
+            free(buf);
+            free(*derBuf);
+            return ret;
+        }
+        *derLen = ret;
+        free(buf);
+
+        return 0;
+    }
+    #endif /* TEST_PK_PRIVKEY */
+
     #endif /* !NO_FILESYSTEM || (NO_FILESYSTEM && FORCE_BUFFER_TEST) */
 #endif /* !NO_CERTS */
 
-static INLINE int myVerify(int preverify, WOLFSSL_X509_STORE_CTX* store)
+static int myVerifyFail = 0;
+static WC_INLINE int myVerify(int preverify, WOLFSSL_X509_STORE_CTX* store)
 {
     char buffer[WOLFSSL_MAX_ERROR_SZ];
-#ifdef OPENSSL_EXTRA
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
     WOLFSSL_X509* peer;
 #endif
     (void)preverify;
+
+    /* Verify Callback Arguments:
+     * preverify:           1=Verify Okay, 0=Failure
+     * store->error:        Failure error code (0 indicates no failure)
+     * store->current_cert: Current WOLFSSL_X509 object (only with OPENSSL_EXTRA)
+     * store->error_depth:  Current Index
+     * store->domain:       Subject CN as string (null term)
+     * store->totalCerts:   Number of certs presented by peer
+     * store->certs[i]:     A `WOLFSSL_BUFFER_INFO` with plain DER for each cert
+     * store->store:        WOLFSSL_X509_STORE with CA cert chain
+     * store->store->cm:    WOLFSSL_CERT_MANAGER
+     * store->ex_data:      The WOLFSSL object pointer
+     * store->discardSessionCerts: When set to non-zero value session certs
+        will be discarded (only with SESSION_CERTS)
+     */
 
     printf("In verification callback, error = %d, %s\n", store->error,
                                  wolfSSL_ERR_error_string(store->error, buffer));
-#ifdef OPENSSL_EXTRA
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
     peer = store->current_cert;
     if (peer) {
@@ -1264,12 +1608,23 @@
 #endif
 
-    printf("\tSubject's domain name is %s\n", store->domain);
-
-    printf("\tAllowing to continue anyway (shouldn't do this, EVER!!!)\n");
+    printf("\tSubject's domain name at %d is %s\n", store->error_depth, store->domain);
+
+    /* Testing forced fail case by return zero */
+    if (myVerifyFail) {
+        return 0; /* test failure case */
+    }
+
+    /* If error indicate we are overriding it for testing purposes */
+    if (store->error != 0) {
+        printf("\tAllowing failed certificate check, testing only "
+            "(shouldn't do this in production)\n");
+    }
+
+    /* A non-zero return code indicates failure override */
     return 1;
 }
 
 
-static INLINE int myDateCb(int preverify, WOLFSSL_X509_STORE_CTX* store)
+static WC_INLINE int myDateCb(int preverify, WOLFSSL_X509_STORE_CTX* store)
 {
     char buffer[WOLFSSL_MAX_ERROR_SZ];
@@ -1290,7 +1645,41 @@
 
 
+#ifdef HAVE_EXT_CACHE
+
+static WC_INLINE WOLFSSL_SESSION* mySessGetCb(WOLFSSL* ssl, unsigned char* id,
+    int id_len, int* copy)
+{
+    (void)ssl;
+    (void)id;
+    (void)id_len;
+    (void)copy;
+
+    /* using internal cache, this is for testing only */
+    return NULL;
+}
+
+static WC_INLINE int mySessNewCb(WOLFSSL* ssl, WOLFSSL_SESSION* session)
+{
+    (void)ssl;
+    (void)session;
+
+    /* using internal cache, this is for testing only */
+    return 0;
+}
+
+static WC_INLINE void mySessRemCb(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* session)
+{
+    (void)ctx;
+    (void)session;
+
+    /* using internal cache, this is for testing only */
+}
+
+#endif /* HAVE_EXT_CACHE */
+
+
 #ifdef HAVE_CRL
 
-static INLINE void CRL_CallBack(const char* url)
+static WC_INLINE void CRL_CallBack(const char* url)
 {
     printf("CRL callback url = %s\n", url);
@@ -1300,8 +1689,8 @@
 
 #ifndef NO_DH
-static INLINE void SetDH(WOLFSSL* ssl)
+static WC_INLINE void SetDH(WOLFSSL* ssl)
 {
     /* dh1024 p */
-    static unsigned char p[] =
+    static const unsigned char p[] =
     {
         0xE6, 0x96, 0x9D, 0x3D, 0x49, 0x5B, 0xE3, 0x2C, 0x7C, 0xF1, 0x80, 0xC3,
@@ -1319,5 +1708,5 @@
 
     /* dh1024 g */
-    static unsigned char g[] =
+    static const unsigned char g[] =
     {
       0x02,
@@ -1327,8 +1716,8 @@
 }
 
-static INLINE void SetDHCtx(WOLFSSL_CTX* ctx)
+static WC_INLINE void SetDHCtx(WOLFSSL_CTX* ctx)
 {
     /* dh1024 p */
-    static unsigned char p[] =
+    static const unsigned char p[] =
     {
         0xE6, 0x96, 0x9D, 0x3D, 0x49, 0x5B, 0xE3, 0x2C, 0x7C, 0xF1, 0x80, 0xC3,
@@ -1346,5 +1735,5 @@
 
     /* dh1024 g */
-    static unsigned char g[] =
+    static const unsigned char g[] =
     {
       0x02,
@@ -1357,5 +1746,5 @@
 #ifndef NO_CERTS
 
-static INLINE void CaCb(unsigned char* der, int sz, int type)
+static WC_INLINE void CaCb(unsigned char* der, int sz, int type)
 {
     (void)der;
@@ -1372,9 +1761,9 @@
     #define MAX_WOLF_ROOT_DEPTH 5
 
-    static INLINE int ChangeToWolfRoot(void)
+    static WC_INLINE int ChangeToWolfRoot(void)
     {
         #if !defined(NO_FILESYSTEM) || defined(FORCE_BUFFER_TEST)
             int depth, res;
-            FILE* file;
+            XFILE file;
             for(depth = 0; depth <= MAX_WOLF_ROOT_DEPTH; depth++) {
                 file = fopen(ntruKeyFile, "rb");
@@ -1407,5 +1796,5 @@
 #define STACK_CHECK_VAL 0x01
 
-static INLINE int StackSizeCheck(func_args* args, thread_func tf)
+static WC_INLINE int StackSizeCheck(func_args* args, thread_func tf)
 {
     int            ret, i, used;
@@ -1476,5 +1865,5 @@
 #endif /* HAVE_STACK_SIZE */
 
-static INLINE void StackTrap(void)
+static WC_INLINE void StackTrap(void)
 {
     struct rlimit  rl;
@@ -1491,5 +1880,5 @@
 #else /* STACK_TRAP */
 
-static INLINE void StackTrap(void)
+static WC_INLINE void StackTrap(void)
 {
 }
@@ -1514,5 +1903,5 @@
 
 
-static INLINE int myMacEncryptCb(WOLFSSL* ssl, unsigned char* macOut,
+static WC_INLINE int myMacEncryptCb(WOLFSSL* ssl, unsigned char* macOut,
        const unsigned char* macIn, unsigned int macInSz, int macContent,
        int macVerify, unsigned char* encOut, const unsigned char* encIn,
@@ -1582,5 +1971,5 @@
 
 
-static INLINE int myDecryptVerifyCb(WOLFSSL* ssl,
+static WC_INLINE int myDecryptVerifyCb(WOLFSSL* ssl,
        unsigned char* decOut, const unsigned char* decIn,
        unsigned int decSz, int macContent, int macVerify,
@@ -1596,5 +1985,5 @@
     Hmac hmac;
     byte myInner[WOLFSSL_TLS_HMAC_INNER_SZ];
-    byte verify[MAX_DIGEST_SIZE];
+    byte verify[WC_MAX_DIGEST_SIZE];
     const char* tlsStr = "TLS";
 
@@ -1680,5 +2069,5 @@
 
 
-static INLINE void SetupAtomicUser(WOLFSSL_CTX* ctx, WOLFSSL* ssl)
+static WC_INLINE void SetupAtomicUser(WOLFSSL_CTX* ctx, WOLFSSL* ssl)
 {
     AtomicEncCtx* encCtx;
@@ -1688,5 +2077,5 @@
     if (encCtx == NULL)
         err_sys("AtomicEncCtx malloc failed");
-    memset(encCtx, 0, sizeof(AtomicEncCtx));
+    XMEMSET(encCtx, 0, sizeof(AtomicEncCtx));
 
     decCtx = (AtomicDecCtx*)malloc(sizeof(AtomicDecCtx));
@@ -1695,5 +2084,5 @@
         err_sys("AtomicDecCtx malloc failed");
     }
-    memset(decCtx, 0, sizeof(AtomicDecCtx));
+    XMEMSET(decCtx, 0, sizeof(AtomicDecCtx));
 
     wolfSSL_CTX_SetMacEncryptCb(ctx, myMacEncryptCb);
@@ -1705,5 +2094,5 @@
 
 
-static INLINE void FreeAtomicUser(WOLFSSL* ssl)
+static WC_INLINE void FreeAtomicUser(WOLFSSL* ssl)
 {
     AtomicEncCtx* encCtx = (AtomicEncCtx*)wolfSSL_GetMacEncryptCtx(ssl);
@@ -1717,5 +2106,5 @@
 
 #ifdef WOLFSSL_STATIC_MEMORY
-static INLINE int wolfSSL_PrintStats(WOLFSSL_MEM_STATS* stats)
+static WC_INLINE int wolfSSL_PrintStats(WOLFSSL_MEM_STATS* stats)
 {
     word16 i;
@@ -1744,16 +2133,43 @@
 #ifdef HAVE_PK_CALLBACKS
 
+typedef struct PkCbInfo {
+    const char* ourKey;
+#ifdef TEST_PK_PRIVKEY
+    union {
 #ifdef HAVE_ECC
-
-static INLINE int myEccSign(WOLFSSL* ssl, const byte* in, word32 inSz,
-        byte* out, word32* outSz, const byte* key, word32 keySz, void* ctx)
-{
+        ecc_key ecc;
+    #endif
+    #ifdef HAVE_CURVE25519
+        curve25519_key curve;
+    #endif
+    } keyGen;
+#endif
+} PkCbInfo;
+
+#if defined(DEBUG_PK_CB) || defined(TEST_PK_PRIVKEY)
+    #define WOLFSSL_PKMSG(_f_, ...) printf(_f_, ##__VA_ARGS__)
+#else
+    #define WOLFSSL_PKMSG(_f_, ...)
+#endif
+
+#ifdef HAVE_ECC
+
+static WC_INLINE int myEccKeyGen(WOLFSSL* ssl, ecc_key* key, word32 keySz,
+    int ecc_curve, void* ctx)
+{
+    int       ret;
     WC_RNG  rng;
-    int     ret;
-    word32  idx = 0;
-    ecc_key myKey;
+    PkCbInfo* cbInfo = (PkCbInfo*)ctx;
+    ecc_key*  new_key = key;
+#ifdef TEST_PK_PRIVKEY
+    byte qx[MAX_ECC_BYTES], qy[MAX_ECC_BYTES];
+    word32 qxLen = sizeof(qx), qyLen = sizeof(qy);
+    new_key = &cbInfo->keyGen.ecc;
+#endif
 
     (void)ssl;
-    (void)ctx;
+    (void)cbInfo;
+
+    WOLFSSL_PKMSG("PK ECC KeyGen: keySz %d, Curve ID %d\n", keySz, ecc_curve);
 
     ret = wc_InitRng(&rng);
@@ -1761,30 +2177,93 @@
         return ret;
 
+    ret = wc_ecc_init(new_key);
+    if (ret == 0) {
+        /* create new key */
+        ret = wc_ecc_make_key_ex(&rng, keySz, new_key, ecc_curve);
+
+    #ifdef TEST_PK_PRIVKEY
+        if (ret == 0) {
+            /* extract public portion from new key into `key` arg */
+            ret = wc_ecc_export_public_raw(new_key, qx, &qxLen, qy, &qyLen);
+            if (ret == 0) {
+                /* load public portion only into key */
+                ret = wc_ecc_import_unsigned(key, qx, qy, NULL, ecc_curve);
+            }
+            (void)qxLen;
+            (void)qyLen;
+        }
+    #endif
+    }
+
+    WOLFSSL_PKMSG("PK ECC KeyGen: ret %d\n", ret);
+
+    wc_FreeRng(&rng);
+
+    return ret;
+}
+
+static WC_INLINE int myEccSign(WOLFSSL* ssl, const byte* in, word32 inSz,
+        byte* out, word32* outSz, const byte* key, word32 keySz, void* ctx)
+{
+    int     ret;
+    WC_RNG    rng;
+    word32  idx = 0;
+    ecc_key myKey;
+    byte*     keyBuf = (byte*)key;
+    PkCbInfo* cbInfo = (PkCbInfo*)ctx;
+
+    (void)ssl;
+    (void)cbInfo;
+
+    WOLFSSL_PKMSG("PK ECC Sign: inSz %d, keySz %d\n", inSz, keySz);
+
+#ifdef TEST_PK_PRIVKEY
+    ret = load_key_file(cbInfo->ourKey, &keyBuf, &keySz);
+    if (ret != 0)
+        return ret;
+#endif
+
+    ret = wc_InitRng(&rng);
+    if (ret != 0)
+        return ret;
+
     ret = wc_ecc_init(&myKey);
     if (ret == 0) {
-        ret = wc_EccPrivateKeyDecode(key, &idx, &myKey, keySz);
-        if (ret == 0)
+        ret = wc_EccPrivateKeyDecode(keyBuf, &idx, &myKey, keySz);
+        if (ret == 0) {
+            WOLFSSL_PKMSG("PK ECC Sign: Curve ID %d\n", myKey.dp->id);
             ret = wc_ecc_sign_hash(in, inSz, out, outSz, &rng, &myKey);
+        }
         wc_ecc_free(&myKey);
     }
     wc_FreeRng(&rng);
 
+#ifdef TEST_PK_PRIVKEY
+    free(keyBuf);
+#endif
+
+    WOLFSSL_PKMSG("PK ECC Sign: ret %d outSz %d\n", ret, *outSz);
+
     return ret;
 }
 
 
-static INLINE int myEccVerify(WOLFSSL* ssl, const byte* sig, word32 sigSz,
+static WC_INLINE int myEccVerify(WOLFSSL* ssl, const byte* sig, word32 sigSz,
         const byte* hash, word32 hashSz, const byte* key, word32 keySz,
         int* result, void* ctx)
 {
     int     ret;
+    word32    idx = 0;
     ecc_key myKey;
+    PkCbInfo* cbInfo = (PkCbInfo*)ctx;
 
     (void)ssl;
-    (void)ctx;
+    (void)cbInfo;
+
+    WOLFSSL_PKMSG("PK ECC Verify: sigSz %d, hashSz %d, keySz %d\n", sigSz, hashSz, keySz);
 
     ret = wc_ecc_init(&myKey);
     if (ret == 0) {
-        ret = wc_ecc_import_x963(key, keySz, &myKey);
+        ret = wc_EccPublicKeyDecode(key, &idx, &myKey, keySz);
         if (ret == 0)
             ret = wc_ecc_verify_hash(sig, sigSz, hash, hashSz, result, &myKey);
@@ -1792,8 +2271,10 @@
     }
 
+    WOLFSSL_PKMSG("PK ECC Verify: ret %d, result %d\n", ret, *result);
+
     return ret;
 }
 
-static INLINE int myEccSharedSecret(WOLFSSL* ssl, ecc_key* otherKey,
+static WC_INLINE int myEccSharedSecret(WOLFSSL* ssl, ecc_key* otherKey,
         unsigned char* pubKeyDer, unsigned int* pubKeySz,
         unsigned char* out, unsigned int* outlen,
@@ -1804,7 +2285,11 @@
     ecc_key* pubKey = NULL;
     ecc_key  tmpKey;
+    PkCbInfo* cbInfo = (PkCbInfo*)ctx;
 
     (void)ssl;
-    (void)ctx;
+    (void)cbInfo;
+
+    WOLFSSL_PKMSG("PK ECC PMS: Side %s, Peer Curve %d\n",
+        side == WOLFSSL_CLIENT_END ? "client" : "server", otherKey->dp->id);
 
     ret = wc_ecc_init(&tmpKey);
@@ -1836,5 +2321,9 @@
     /* for server: import public key */
     else if (side == WOLFSSL_SERVER_END) {
+    #ifdef TEST_PK_PRIVKEY
+        privKey = &cbInfo->keyGen.ecc;
+    #else
         privKey = otherKey;
+    #endif
         pubKey = &tmpKey;
 
@@ -1857,11 +2346,19 @@
     }
 
+#ifdef TEST_PK_PRIVKEY
+    if (side == WOLFSSL_SERVER_END) {
+        wc_ecc_free(&cbInfo->keyGen.ecc);
+    }
+#endif
+
     wc_ecc_free(&tmpKey);
 
+    WOLFSSL_PKMSG("PK ECC PMS: ret %d, PubKeySz %d, OutLen %d\n", ret, *pubKeySz, *outlen);
+
     return ret;
 }
 
 #ifdef HAVE_ED25519
-static INLINE int myEd25519Sign(WOLFSSL* ssl, const byte* in, word32 inSz,
+static WC_INLINE int myEd25519Sign(WOLFSSL* ssl, const byte* in, word32 inSz,
         byte* out, word32* outSz, const byte* key, word32 keySz, void* ctx)
 {
@@ -1869,11 +2366,21 @@
     word32      idx = 0;
     ed25519_key myKey;
+    byte*       keyBuf = (byte*)key;
+    PkCbInfo*   cbInfo = (PkCbInfo*)ctx;
 
     (void)ssl;
-    (void)ctx;
+    (void)cbInfo;
+
+    WOLFSSL_PKMSG("PK 25519 Sign: inSz %d, keySz %d\n", inSz, keySz);
+
+#ifdef TEST_PK_PRIVKEY
+    ret = load_key_file(cbInfo->ourKey, &keyBuf, &keySz);
+    if (ret != 0)
+        return ret;
+#endif
 
     ret = wc_ed25519_init(&myKey);
     if (ret == 0) {
-        ret = wc_Ed25519PrivateKeyDecode(key, &idx, &myKey, keySz);
+        ret = wc_Ed25519PrivateKeyDecode(keyBuf, &idx, &myKey, keySz);
         if (ret == 0)
             ret = wc_ed25519_sign_msg(in, inSz, out, outSz, &myKey);
@@ -1881,9 +2388,15 @@
     }
 
+#ifdef TEST_PK_PRIVKEY
+    free(keyBuf);
+#endif
+
+    WOLFSSL_PKMSG("PK 25519 Sign: ret %d, outSz %d\n", ret, *outSz);
+
     return ret;
 }
 
 
-static INLINE int myEd25519Verify(WOLFSSL* ssl, const byte* sig, word32 sigSz,
+static WC_INLINE int myEd25519Verify(WOLFSSL* ssl, const byte* sig, word32 sigSz,
         const byte* msg, word32 msgSz, const byte* key, word32 keySz,
         int* result, void* ctx)
@@ -1891,7 +2404,10 @@
     int         ret;
     ed25519_key myKey;
+    PkCbInfo* cbInfo = (PkCbInfo*)ctx;
 
     (void)ssl;
-    (void)ctx;
+    (void)cbInfo;
+
+    WOLFSSL_PKMSG("PK 25519 Verify: sigSz %d, msgSz %d, keySz %d\n", sigSz, msgSz, keySz);
 
     ret = wc_ed25519_init(&myKey);
@@ -1904,4 +2420,6 @@
     }
 
+    WOLFSSL_PKMSG("PK 25519 Verify: ret %d, result %d\n", ret, *result);
+
     return ret;
 }
@@ -1909,5 +2427,30 @@
 
 #ifdef HAVE_CURVE25519
-static INLINE int myX25519SharedSecret(WOLFSSL* ssl, curve25519_key* otherKey,
+static WC_INLINE int myX25519KeyGen(WOLFSSL* ssl, curve25519_key* key,
+    unsigned int keySz, void* ctx)
+{
+    int       ret;
+    WC_RNG    rng;
+    PkCbInfo* cbInfo = (PkCbInfo*)ctx;
+
+    (void)ssl;
+    (void)cbInfo;
+
+    WOLFSSL_PKMSG("PK 25519 KeyGen: keySz %d\n", keySz);
+
+    ret = wc_InitRng(&rng);
+    if (ret != 0)
+        return ret;
+
+    ret = wc_curve25519_make_key(&rng, keySz, key);
+
+    wc_FreeRng(&rng);
+
+    WOLFSSL_PKMSG("PK 25519 KeyGen: ret %d\n", ret);
+
+    return ret;
+}
+
+static WC_INLINE int myX25519SharedSecret(WOLFSSL* ssl, curve25519_key* otherKey,
         unsigned char* pubKeyDer, unsigned int* pubKeySz,
         unsigned char* out, unsigned int* outlen,
@@ -1918,7 +2461,11 @@
     curve25519_key* pubKey = NULL;
     curve25519_key  tmpKey;
+    PkCbInfo* cbInfo = (PkCbInfo*)ctx;
 
     (void)ssl;
-    (void)ctx;
+    (void)cbInfo;
+
+    WOLFSSL_PKMSG("PK 25519 PMS: side %s\n",
+        side == WOLFSSL_CLIENT_END ? "client" : "server");
 
     ret = wc_curve25519_init(&tmpKey);
@@ -1965,4 +2512,7 @@
     wc_curve25519_free(&tmpKey);
 
+    WOLFSSL_PKMSG("PK 25519 PMS: ret %d, pubKeySz %d, outLen %d\n",
+        ret, *pubKeySz, *outlen);
+
     return ret;
 }
@@ -1971,7 +2521,31 @@
 #endif /* HAVE_ECC */
 
+#ifndef NO_DH
+static WC_INLINE int myDhCallback(WOLFSSL* ssl, struct DhKey* key,
+        const unsigned char* priv, unsigned int privSz,
+        const unsigned char* pubKeyDer, unsigned int pubKeySz,
+        unsigned char* out, unsigned int* outlen,
+        void* ctx)
+{
+    int ret;
+    PkCbInfo* cbInfo = (PkCbInfo*)ctx;
+
+    (void)ssl;
+    (void)cbInfo;
+
+    /* return 0 on success */
+    ret = wc_DhAgree(key, out, outlen, priv, privSz, pubKeyDer, pubKeySz);
+
+    WOLFSSL_PKMSG("PK ED Agree: ret %d, privSz %d, pubKeySz %d, outlen %d\n",
+        ret, privSz, pubKeySz, *outlen);
+
+    return ret;
+};
+
+#endif /* !NO_DH */
+
 #ifndef NO_RSA
 
-static INLINE int myRsaSign(WOLFSSL* ssl, const byte* in, word32 inSz,
+static WC_INLINE int myRsaSign(WOLFSSL* ssl, const byte* in, word32 inSz,
         byte* out, word32* outSz, const byte* key, word32 keySz, void* ctx)
 {
@@ -1980,7 +2554,17 @@
     word32  idx = 0;
     RsaKey  myKey;
+    byte*   keyBuf = (byte*)key;
+    PkCbInfo* cbInfo = (PkCbInfo*)ctx;
 
     (void)ssl;
-    (void)ctx;
+    (void)cbInfo;
+
+    WOLFSSL_PKMSG("PK RSA Sign: inSz %d, keySz %d\n", inSz, keySz);
+
+#ifdef TEST_PK_PRIVKEY
+    ret = load_key_file(cbInfo->ourKey, &keyBuf, &keySz);
+    if (ret != 0)
+        return ret;
+#endif
 
     ret = wc_InitRng(&rng);
@@ -1990,5 +2574,5 @@
     ret = wc_InitRsaKey(&myKey, NULL);
     if (ret == 0) {
-        ret = wc_RsaPrivateKeyDecode(key, &idx, &myKey, keySz);
+        ret = wc_RsaPrivateKeyDecode(keyBuf, &idx, &myKey, keySz);
         if (ret == 0)
             ret = wc_RsaSSL_Sign(in, inSz, out, *outSz, &myKey, &rng);
@@ -2001,19 +2585,26 @@
     wc_FreeRng(&rng);
 
+#ifdef TEST_PK_PRIVKEY
+    free(keyBuf);
+#endif
+
+    WOLFSSL_PKMSG("PK RSA Sign: ret %d, outSz %d\n", ret, *outSz);
+
     return ret;
 }
 
 
-static INLINE int myRsaVerify(WOLFSSL* ssl, byte* sig, word32 sigSz,
-        byte** out,
-        const byte* key, word32 keySz,
-        void* ctx)
+static WC_INLINE int myRsaVerify(WOLFSSL* ssl, byte* sig, word32 sigSz,
+        byte** out, const byte* key, word32 keySz, void* ctx)
 {
     int     ret;
     word32  idx = 0;
     RsaKey  myKey;
+    PkCbInfo* cbInfo = (PkCbInfo*)ctx;
 
     (void)ssl;
-    (void)ctx;
+    (void)cbInfo;
+
+    WOLFSSL_PKMSG("PK RSA Verify: sigSz %d, keySz %d\n", sigSz, keySz);
 
     ret = wc_InitRsaKey(&myKey, NULL);
@@ -2025,9 +2616,47 @@
     }
 
+    WOLFSSL_PKMSG("PK RSA Verify: ret %d\n", ret);
+
     return ret;
 }
 
+static WC_INLINE int myRsaSignCheck(WOLFSSL* ssl, byte* sig, word32 sigSz,
+        byte** out, const byte* key, word32 keySz, void* ctx)
+{
+    int     ret;
+    word32  idx = 0;
+    RsaKey  myKey;
+    byte*   keyBuf = (byte*)key;
+    PkCbInfo* cbInfo = (PkCbInfo*)ctx;
+
+    (void)ssl;
+    (void)cbInfo;
+
+    WOLFSSL_PKMSG("PK RSA SignCheck: sigSz %d, keySz %d\n", sigSz, keySz);
+
+#ifdef TEST_PK_PRIVKEY
+    ret = load_key_file(cbInfo->ourKey, &keyBuf, &keySz);
+    if (ret != 0)
+        return ret;
+#endif
+
+    ret = wc_InitRsaKey(&myKey, NULL);
+    if (ret == 0) {
+        ret = wc_RsaPrivateKeyDecode(keyBuf, &idx, &myKey, keySz);
+        if (ret == 0)
+            ret = wc_RsaSSL_VerifyInline(sig, sigSz, out, &myKey);
+        wc_FreeRsaKey(&myKey);
+    }
+#ifdef TEST_PK_PRIVKEY
+    free(keyBuf);
+#endif
+
+    WOLFSSL_PKMSG("PK RSA SignCheck: ret %d\n", ret);
+
+    return ret;
+}
+
 #ifdef WC_RSA_PSS
-static INLINE int myRsaPssSign(WOLFSSL* ssl, const byte* in, word32 inSz,
+static WC_INLINE int myRsaPssSign(WOLFSSL* ssl, const byte* in, word32 inSz,
         byte* out, word32* outSz, int hash, int mgf, const byte* key,
         word32 keySz, void* ctx)
@@ -2038,7 +2667,18 @@
     word32           idx = 0;
     RsaKey           myKey;
+    byte*            keyBuf = (byte*)key;
+    PkCbInfo* cbInfo = (PkCbInfo*)ctx;
 
     (void)ssl;
-    (void)ctx;
+    (void)cbInfo;
+
+    WOLFSSL_PKMSG("PK RSA PSS Sign: inSz %d, hash %d, mgf %d, keySz %d\n",
+        inSz, hash, mgf, keySz);
+
+#ifdef TEST_PK_PRIVKEY
+    ret = load_key_file(cbInfo->ourKey, &keyBuf, &keySz);
+    if (ret != 0)
+        return ret;
+#endif
 
     switch (hash) {
@@ -2066,5 +2706,5 @@
     ret = wc_InitRsaKey(&myKey, NULL);
     if (ret == 0) {
-        ret = wc_RsaPrivateKeyDecode(key, &idx, &myKey, keySz);
+        ret = wc_RsaPrivateKeyDecode(keyBuf, &idx, &myKey, keySz);
         if (ret == 0) {
             ret = wc_RsaPSS_Sign(in, inSz, out, *outSz, hashType, mgf, &myKey,
@@ -2079,18 +2719,28 @@
     wc_FreeRng(&rng);
 
+#ifdef TEST_PK_PRIVKEY
+    free(keyBuf);
+#endif
+
+    WOLFSSL_PKMSG("PK RSA PSS Sign: ret %d, outSz %d\n", ret, *outSz);
+
     return ret;
 }
 
 
-static INLINE int myRsaPssVerify(WOLFSSL* ssl, byte* sig, word32 sigSz,
+static WC_INLINE int myRsaPssVerify(WOLFSSL* ssl, byte* sig, word32 sigSz,
         byte** out, int hash, int mgf, const byte* key, word32 keySz, void* ctx)
 {
-    enum wc_HashType hashType = WC_HASH_TYPE_NONE;
     int              ret;
     word32           idx = 0;
     RsaKey           myKey;
+    PkCbInfo* cbInfo = (PkCbInfo*)ctx;
+    enum wc_HashType hashType = WC_HASH_TYPE_NONE;
 
     (void)ssl;
-    (void)ctx;
+    (void)cbInfo;
+
+    WOLFSSL_PKMSG("PK RSA PSS Verify: sigSz %d, hash %d, mgf %d, keySz %d\n",
+        sigSz, hash, mgf, keySz);
 
     switch (hash) {
@@ -2122,10 +2772,71 @@
     }
 
+    WOLFSSL_PKMSG("PK RSA PSS Verify: ret %d\n", ret);
+
     return ret;
 }
-#endif
-
-
-static INLINE int myRsaEnc(WOLFSSL* ssl, const byte* in, word32 inSz,
+
+static WC_INLINE int myRsaPssSignCheck(WOLFSSL* ssl, byte* sig, word32 sigSz,
+        byte** out, int hash, int mgf, const byte* key, word32 keySz, void* ctx)
+{
+    int       ret;
+    word32    idx = 0;
+    RsaKey    myKey;
+    byte*     keyBuf = (byte*)key;
+    PkCbInfo* cbInfo = (PkCbInfo*)ctx;
+    enum wc_HashType hashType = WC_HASH_TYPE_NONE;
+
+    (void)ssl;
+    (void)cbInfo;
+
+    WOLFSSL_PKMSG("PK RSA PSS SignCheck: sigSz %d, hash %d, mgf %d, keySz %d\n",
+        sigSz, hash, mgf, keySz);
+
+#ifdef TEST_PK_PRIVKEY
+    ret = load_key_file(cbInfo->ourKey, &keyBuf, &keySz);
+    if (ret != 0)
+        return ret;
+#endif
+
+    switch (hash) {
+#ifndef NO_SHA256
+        case SHA256h:
+            hashType = WC_HASH_TYPE_SHA256;
+            break;
+#endif
+#ifdef WOLFSSL_SHA384
+        case SHA384h:
+            hashType = WC_HASH_TYPE_SHA384;
+            break;
+#endif
+#ifdef WOLFSSL_SHA512
+        case SHA512h:
+            hashType = WC_HASH_TYPE_SHA512;
+            break;
+#endif
+    }
+
+    ret = wc_InitRsaKey(&myKey, NULL);
+    if (ret == 0) {
+        ret = wc_RsaPrivateKeyDecode(keyBuf, &idx, &myKey, keySz);
+        if (ret == 0) {
+            ret = wc_RsaPSS_VerifyInline(sig, sigSz, out, hashType, mgf,
+                                         &myKey);
+            }
+        wc_FreeRsaKey(&myKey);
+    }
+
+#ifdef TEST_PK_PRIVKEY
+    free(keyBuf);
+#endif
+
+    WOLFSSL_PKMSG("PK RSA PSS SignCheck: ret %d\n", ret);
+
+    return ret;
+}
+#endif
+
+
+static WC_INLINE int myRsaEnc(WOLFSSL* ssl, const byte* in, word32 inSz,
                            byte* out, word32* outSz, const byte* key,
                            word32 keySz, void* ctx)
@@ -2135,7 +2846,10 @@
     RsaKey  myKey;
     WC_RNG  rng;
+    PkCbInfo* cbInfo = (PkCbInfo*)ctx;
 
     (void)ssl;
-    (void)ctx;
+    (void)cbInfo;
+
+    WOLFSSL_PKMSG("PK RSA Enc: inSz %d, keySz %d\n", inSz, keySz);
 
     ret = wc_InitRng(&rng);
@@ -2157,8 +2871,10 @@
     wc_FreeRng(&rng);
 
+    WOLFSSL_PKMSG("PK RSA Enc: ret %d, outSz %d\n", ret, *outSz);
+
     return ret;
 }
 
-static INLINE int myRsaDec(WOLFSSL* ssl, byte* in, word32 inSz,
+static WC_INLINE int myRsaDec(WOLFSSL* ssl, byte* in, word32 inSz,
                            byte** out,
                            const byte* key, word32 keySz, void* ctx)
@@ -2167,11 +2883,21 @@
     word32  idx = 0;
     RsaKey  myKey;
+    byte*     keyBuf = (byte*)key;
+    PkCbInfo* cbInfo = (PkCbInfo*)ctx;
 
     (void)ssl;
-    (void)ctx;
+    (void)cbInfo;
+
+    WOLFSSL_PKMSG("PK RSA Dec: inSz %d, keySz %d\n", inSz, keySz);
+
+#ifdef TEST_PK_PRIVKEY
+    ret = load_key_file(cbInfo->ourKey, &keyBuf, &keySz);
+    if (ret != 0)
+        return ret;
+#endif
 
     ret = wc_InitRsaKey(&myKey, NULL);
     if (ret == 0) {
-        ret = wc_RsaPrivateKeyDecode(key, &idx, &myKey, keySz);
+        ret = wc_RsaPrivateKeyDecode(keyBuf, &idx, &myKey, keySz);
         if (ret == 0) {
             #ifdef WC_RSA_BLINDING
@@ -2187,4 +2913,10 @@
     }
 
+#ifdef TEST_PK_PRIVKEY
+    free(keyBuf);
+#endif
+
+    WOLFSSL_PKMSG("PK RSA Dec: ret %d\n", ret);
+
     return ret;
 }
@@ -2192,14 +2924,17 @@
 #endif /* NO_RSA */
 
-static INLINE void SetupPkCallbacks(WOLFSSL_CTX* ctx, WOLFSSL* ssl)
+static WC_INLINE void SetupPkCallbacks(WOLFSSL_CTX* ctx)
 {
     (void)ctx;
-    (void)ssl;
 
     #ifdef HAVE_ECC
+        wolfSSL_CTX_SetEccKeyGenCb(ctx, myEccKeyGen);
         wolfSSL_CTX_SetEccSignCb(ctx, myEccSign);
         wolfSSL_CTX_SetEccVerifyCb(ctx, myEccVerify);
         wolfSSL_CTX_SetEccSharedSecretCb(ctx, myEccSharedSecret);
     #endif /* HAVE_ECC */
+    #ifndef NO_DH
+        wolfSSL_CTX_SetDhAgreeCb(ctx, myDhCallback);
+    #endif
     #ifdef HAVE_ED25519
         wolfSSL_CTX_SetEd25519SignCb(ctx, myEd25519Sign);
@@ -2207,4 +2942,5 @@
     #endif
     #ifdef HAVE_CURVE25519
+        wolfSSL_CTX_SetX25519KeyGenCb(ctx, myX25519KeyGen);
         wolfSSL_CTX_SetX25519SharedSecretCb(ctx, myX25519SharedSecret);
     #endif
@@ -2212,7 +2948,9 @@
         wolfSSL_CTX_SetRsaSignCb(ctx, myRsaSign);
         wolfSSL_CTX_SetRsaVerifyCb(ctx, myRsaVerify);
+        wolfSSL_CTX_SetRsaSignCheckCb(ctx, myRsaSignCheck);
         #ifdef WC_RSA_PSS
             wolfSSL_CTX_SetRsaPssSignCb(ctx, myRsaPssSign);
             wolfSSL_CTX_SetRsaPssVerifyCb(ctx, myRsaPssVerify);
+            wolfSSL_CTX_SetRsaPssSignCheckCb(ctx, myRsaPssSignCheck);
         #endif
         wolfSSL_CTX_SetRsaEncCb(ctx, myRsaEnc);
@@ -2221,6 +2959,36 @@
 }
 
+static WC_INLINE void SetupPkCallbackContexts(WOLFSSL* ssl, void* myCtx)
+{
+    #ifdef HAVE_ECC
+        wolfSSL_SetEccKeyGenCtx(ssl, myCtx);
+        wolfSSL_SetEccSignCtx(ssl, myCtx);
+        wolfSSL_SetEccVerifyCtx(ssl, myCtx);
+        wolfSSL_SetEccSharedSecretCtx(ssl, myCtx);
+    #endif /* HAVE_ECC */
+    #ifndef NO_DH
+        wolfSSL_SetDhAgreeCtx(ssl, myCtx);
+    #endif
+    #ifdef HAVE_ED25519
+        wolfSSL_SetEd25519SignCtx(ssl, myCtx);
+        wolfSSL_SetEd25519VerifyCtx(ssl, myCtx);
+    #endif
+    #ifdef HAVE_CURVE25519
+        wolfSSL_SetX25519KeyGenCtx(ssl, myCtx);
+        wolfSSL_SetX25519SharedSecretCtx(ssl, myCtx);
+    #endif
+    #ifndef NO_RSA
+        wolfSSL_SetRsaSignCtx(ssl, myCtx);
+        wolfSSL_SetRsaVerifyCtx(ssl, myCtx);
+        #ifdef WC_RSA_PSS
+            wolfSSL_SetRsaPssSignCtx(ssl, myCtx);
+            wolfSSL_SetRsaPssVerifyCtx(ssl, myCtx);
+        #endif
+        wolfSSL_SetRsaEncCtx(ssl, myCtx);
+        wolfSSL_SetRsaDecCtx(ssl, myCtx);
+    #endif /* NO_RSA */
+}
+
 #endif /* HAVE_PK_CALLBACKS */
-
 
 
@@ -2231,5 +2999,5 @@
 
 /* HP/UX doesn't have strsep, needed by test/suites.c */
-static INLINE char* strsep(char **stringp, const char *delim)
+static WC_INLINE char* strsep(char **stringp, const char *delim)
 {
     char* start;
@@ -2255,5 +3023,5 @@
    len does not include null terminating character,
    num is number of characters in tempfn name to randomize */
-static INLINE const char* mymktemp(char *tempfn, int len, int num)
+static WC_INLINE const char* mymktemp(char *tempfn, int len, int num)
 {
     int x, size;
@@ -2285,4 +3053,5 @@
 
     wc_FreeRng(&rng);
+    (void)rng; /* for WC_NO_RNG case */
 
     return tempfn;
@@ -2301,8 +3070,8 @@
     } key_ctx;
 
-    static key_ctx myKey_ctx;
-    static WC_RNG myKey_rng;
-
-    static INLINE int TicketInit(void)
+    static THREAD_LS_T key_ctx myKey_ctx;
+    static THREAD_LS_T WC_RNG myKey_rng;
+
+    static WC_INLINE int TicketInit(void)
     {
         int ret = wc_InitRng(&myKey_rng);
@@ -2318,10 +3087,10 @@
     }
 
-    static INLINE void TicketCleanup(void)
+    static WC_INLINE void TicketCleanup(void)
     {
         wc_FreeRng(&myKey_rng);
     }
 
-    static INLINE int myTicketEncCb(WOLFSSL* ssl,
+    static WC_INLINE int myTicketEncCb(WOLFSSL* ssl,
                              byte key_name[WOLFSSL_TICKET_NAME_SZ],
                              byte iv[WOLFSSL_TICKET_IV_SZ],
@@ -2389,5 +3158,5 @@
 #endif  /* HAVE_SESSION_TICKET && CHACHA20 && POLY1305 */
 
-static INLINE word16 GetRandomPort(void)
+static WC_INLINE word16 GetRandomPort(void)
 {
     word16 port = 0;
@@ -2396,8 +3165,10 @@
     WC_RNG rng;
     if (wc_InitRng(&rng) == 0) {
-        wc_RNG_GenerateBlock(&rng, (byte*)&port, sizeof(port));
+        if (wc_RNG_GenerateBlock(&rng, (byte*)&port, sizeof(port)) == 0) {
         port |= 0xC000; /* Make sure its in the 49152 - 65535 range */
+        }
         wc_FreeRng(&rng);
     }
+    (void)rng; /* for WC_NO_RNG case */
     return port;
 }
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/version.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/version.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/version.h	(revision 372)
@@ -29,6 +29,6 @@
 #endif
 
-#define LIBWOLFSSL_VERSION_STRING "3.12.2"
-#define LIBWOLFSSL_VERSION_HEX 0x03012002
+#define LIBWOLFSSL_VERSION_STRING "3.15.7"
+#define LIBWOLFSSL_VERSION_HEX 0x03015007
 
 #ifdef __cplusplus
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/aes.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/aes.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/aes.h	(revision 372)
@@ -20,4 +20,8 @@
  */
 
+/*!
+    \file wolfssl/wolfcrypt/aes.h
+*/
+
 
 #ifndef WOLF_CRYPT_AES_H
@@ -28,6 +32,12 @@
 #ifndef NO_AES
 
+#if defined(HAVE_FIPS) && \
+    defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+    #include <wolfssl/wolfcrypt/fips.h>
+#endif /* HAVE_FIPS_VERSION >= 2 */
+
 /* included for fips @wc_fips */
-#ifdef HAVE_FIPS
+#if defined(HAVE_FIPS) && \
+    (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))
 #include <cyassl/ctaocrypt/aes.h>
 #if defined(CYASSL_AES_COUNTER) && !defined(WOLFSSL_AES_COUNTER)
@@ -39,5 +49,10 @@
 #endif
 
-#ifndef HAVE_FIPS /* to avoid redefinition of macros */
+#ifndef WC_NO_RNG
+    #include <wolfssl/wolfcrypt/random.h>
+#endif
+#ifdef STM32_CRYPTO
+    #include <wolfssl/wolfcrypt/port/st/stm32.h>
+#endif
 
 #ifdef WOLFSSL_AESNI
@@ -49,9 +64,22 @@
 #endif /* WOLFSSL_AESNI */
 
+
 #ifdef WOLFSSL_XILINX_CRYPT
 #include "xsecure_aes.h"
 #endif
 
-#endif /* HAVE_FIPS */
+#ifdef WOLFSSL_AFALG
+/* included for struct msghdr */
+#include <sys/socket.h>
+#endif
+
+#if defined(WOLFSSL_DEVCRYPTO_AES) || defined(WOLFSSL_DEVCRYPTO_CBC)
+#include <wolfssl/wolfcrypt/port/devcrypto/wc_devcrypto.h>
+#endif
+
+#if defined(HAVE_AESGCM) && !defined(WC_NO_RNG)
+    #include <wolfssl/wolfcrypt/random.h>
+#endif
+
 
 #ifdef __cplusplus
@@ -59,5 +87,17 @@
 #endif
 
-#ifndef HAVE_FIPS /* to avoid redefinition of structures */
+/* these are required for FIPS and non-FIPS */
+enum {
+    AES_128_KEY_SIZE    = 16,  /* for 128 bit             */
+    AES_192_KEY_SIZE    = 24,  /* for 192 bit             */
+    AES_256_KEY_SIZE    = 32,  /* for 256 bit             */
+
+    AES_IV_SIZE         = 16,  /* always block size       */
+};
+
+
+/* avoid redefinition of structs */
+#if !defined(HAVE_FIPS) || \
+    (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))
 
 #ifdef WOLFSSL_ASYNC_CRYPT
@@ -66,9 +106,23 @@
 
 enum {
-    AES_ENC_TYPE   = 1,   /* cipher unique type */
+    AES_ENC_TYPE   = WC_CIPHER_AES,   /* cipher unique type */
     AES_ENCRYPTION = 0,
     AES_DECRYPTION = 1,
+
+    AES_BLOCK_SIZE      = 16,
+
     KEYWRAP_BLOCK_SIZE = 8,
-    AES_BLOCK_SIZE = 16
+
+    GCM_NONCE_MAX_SZ = 16, /* wolfCrypt's maximum nonce size allowed. */
+    GCM_NONCE_MID_SZ = 12, /* The usual default nonce size for AES-GCM. */
+    GCM_NONCE_MIN_SZ = 8,  /* wolfCrypt's minimum nonce size allowed. */
+    CCM_NONCE_MIN_SZ = 7,
+    CCM_NONCE_MAX_SZ = 13,
+    CTR_SZ   = 4,
+    AES_IV_FIXED_SZ = 4,
+
+#ifdef HAVE_PKCS11
+    AES_MAX_ID_LEN   = 32,
+#endif
 };
 
@@ -83,4 +137,8 @@
     ALIGN16 word32 tmp[AES_BLOCK_SIZE / sizeof(word32)];      /* same         */
 
+#if defined(HAVE_AESGCM) || defined(HAVE_AESCCM)
+    word32 invokeCtr[2];
+    word32 nonceSz;
+#endif
 #ifdef HAVE_AESGCM
     ALIGN16 byte H[AES_BLOCK_SIZE];
@@ -93,4 +151,11 @@
     byte use_aesni;
 #endif /* WOLFSSL_AESNI */
+#ifdef WOLF_CRYPTO_DEV
+    int   devId;
+#endif
+#ifdef HAVE_PKCS11
+    byte id[AES_MAX_ID_LEN];
+    int  idLen;
+#endif
 #ifdef WOLFSSL_ASYNC_CRYPT
     word32 asyncKey[AES_MAX_KEY_SIZE/8/sizeof(word32)]; /* raw key */
@@ -98,5 +163,5 @@
     WC_ASYNC_DEV asyncDev;
 #endif /* WOLFSSL_ASYNC_CRYPT */
-#ifdef WOLFSSL_AES_COUNTER
+#if defined(WOLFSSL_AES_COUNTER) || defined(WOLFSSL_AES_CFB)
     word32  left;            /* unused bytes left from last call */
 #endif
@@ -106,4 +171,15 @@
     word32      key_init[8];
     word32      kup;
+#endif
+#ifdef WOLFSSL_AFALG
+    int alFd; /* server socket to bind to */
+    int rdFd; /* socket to read from */
+    struct msghdr msg;
+    int dir;  /* flag for encrpyt or decrypt */
+#endif
+#if defined(WOLFSSL_DEVCRYPTO) && \
+    (defined(WOLFSSL_DEVCRYPTO_AES) || defined(WOLFSSL_DEVCRYPTO_CBC))
+    word32       devKey[AES_MAX_KEY_SIZE/WOLFSSL_BIT_SIZE/sizeof(word32)]; /* raw key */
+    WC_CRYPTODEV ctx;
 #endif
     void*  heap; /* memory hint to use */
@@ -141,8 +217,20 @@
                               const byte* iv, int dir);
 WOLFSSL_API int  wc_AesSetIV(Aes* aes, const byte* iv);
+
+#ifdef HAVE_AES_CBC
 WOLFSSL_API int  wc_AesCbcEncrypt(Aes* aes, byte* out,
                                   const byte* in, word32 sz);
 WOLFSSL_API int  wc_AesCbcDecrypt(Aes* aes, byte* out,
                                   const byte* in, word32 sz);
+#endif
+
+#ifdef WOLFSSL_AES_CFB
+WOLFSSL_API int wc_AesCfbEncrypt(Aes* aes, byte* out,
+                                    const byte* in, word32 sz);
+#ifdef HAVE_AES_DECRYPT
+WOLFSSL_API int wc_AesCfbDecrypt(Aes* aes, byte* out,
+                                    const byte* in, word32 sz);
+#endif /* HAVE_AES_DECRYPT */
+#endif /* WOLFSSL_AES_CFB */
 
 #ifdef HAVE_AES_ECB
@@ -165,4 +253,5 @@
                                 const byte* iv, int dir);
 #endif
+
 #ifdef HAVE_AESGCM
 #ifdef WOLFSSL_XILINX_CRYPT
@@ -182,8 +271,29 @@
                                    const byte* authIn, word32 authInSz);
 
+#ifndef WC_NO_RNG
+ WOLFSSL_API int  wc_AesGcmSetExtIV(Aes* aes, const byte* iv, word32 ivSz);
+ WOLFSSL_API int  wc_AesGcmSetIV(Aes* aes, word32 ivSz,
+                                   const byte* ivFixed, word32 ivFixedSz,
+                                   WC_RNG* rng);
+ WOLFSSL_API int  wc_AesGcmEncrypt_ex(Aes* aes, byte* out,
+                                   const byte* in, word32 sz,
+                                   byte* ivOut, word32 ivOutSz,
+                                   byte* authTag, word32 authTagSz,
+                                   const byte* authIn, word32 authInSz);
+#endif /* WC_NO_RNG */
+
  WOLFSSL_API int wc_GmacSetKey(Gmac* gmac, const byte* key, word32 len);
  WOLFSSL_API int wc_GmacUpdate(Gmac* gmac, const byte* iv, word32 ivSz,
                                const byte* authIn, word32 authInSz,
                                byte* authTag, word32 authTagSz);
+#ifndef WC_NO_RNG
+ WOLFSSL_API int wc_Gmac(const byte* key, word32 keySz, byte* iv, word32 ivSz,
+                               const byte* authIn, word32 authInSz,
+                               byte* authTag, word32 authTagSz, WC_RNG* rng);
+ WOLFSSL_API int wc_GmacVerify(const byte* key, word32 keySz,
+                               const byte* iv, word32 ivSz,
+                               const byte* authIn, word32 authInSz,
+                               const byte* authTag, word32 authTagSz);
+#endif /* WC_NO_RNG */
  WOLFSSL_LOCAL void GHASH(Aes* aes, const byte* a, word32 aSz, const byte* c,
                                word32 cSz, byte* s, word32 sSz);
@@ -200,4 +310,11 @@
                                    const byte* nonce, word32 nonceSz,
                                    const byte* authTag, word32 authTagSz,
+                                   const byte* authIn, word32 authInSz);
+ WOLFSSL_API int  wc_AesCcmSetNonce(Aes* aes,
+                                   const byte* nonce, word32 nonceSz);
+ WOLFSSL_API int  wc_AesCcmEncrypt_ex(Aes* aes, byte* out,
+                                   const byte* in, word32 sz,
+                                   byte* ivOut, word32 ivOutSz,
+                                   byte* authTag, word32 authTagSz,
                                    const byte* authIn, word32 authInSz);
 #endif /* HAVE_AESCCM */
@@ -214,224 +331,20 @@
 
 #ifdef WOLFSSL_AES_XTS
-/*!
-    \ingroup AES
-
-    \brief This is to help with setting keys to correct encrypt or decrypt type.
-
-    \note Is up to user to call wc_AesXtsFree on aes key when done.
-
-    \return 0 Success
-
-    \param aes   AES keys for encrypt/decrypt process
-    \param key   buffer holding aes key | tweak key
-    \param len   length of key buffer in bytes. Should be twice that of key size.
-                 i.e. 32 for a 16 byte key.
-    \param dir   direction, either AES_ENCRYPTION or AES_DECRYPTION
-    \param heap  heap hint to use for memory. Can be NULL
-    \param devId id to use with async crypto. Can be 0
-
-    _Example_
-    \code
-    XtsAes aes;
-
-    if(wc_AesXtsSetKey(&aes, key, sizeof(key), AES_ENCRYPTION, NULL, 0) != 0)
-    {
-        // Handle error
-    }
-    wc_AesXtsFree(&aes);
-    \endcode
-
-    \sa wc_AesXtsEncrypt
-    \sa wc_AesXtsDecrypt
-    \sa wc_AesXtsFree
-*/
+
 WOLFSSL_API int wc_AesXtsSetKey(XtsAes* aes, const byte* key,
          word32 len, int dir, void* heap, int devId);
 
-
-/*!
-    \ingroup AES
-
-    \brief Same process as wc_AesXtsEncrypt but uses a word64 type as the tweak
-           value instead of a byte array. This just converts the word64 to a
-           byte array and calls wc_AesXtsEncrypt.
-
-    \return 0 Success
-
-    \param aes    AES keys to use for block encrypt/decrypt
-    \param out    output buffer to hold cipher text
-    \param in     input plain text buffer to encrypt
-    \param sz     size of both out and in buffers
-    \param sector value to use for tweak
-
-    _Example_
-    \code
-    XtsAes aes;
-    unsigned char plain[SIZE];
-    unsigned char cipher[SIZE];
-    word64 s = VALUE;
-
-    //set up keys with AES_ENCRYPTION as dir
-
-    if(wc_AesXtsEncryptSector(&aes, cipher, plain, SIZE, s) != 0)
-    {
-        // Handle error
-    }
-    wc_AesXtsFree(&aes);
-    \endcode
-
-    \sa wc_AesXtsEncrypt
-    \sa wc_AesXtsDecrypt
-    \sa wc_AesXtsSetKey
-    \sa wc_AesXtsFree
-*/
 WOLFSSL_API int wc_AesXtsEncryptSector(XtsAes* aes, byte* out,
          const byte* in, word32 sz, word64 sector);
 
-
-/*!
-    \ingroup AES
-
-    \brief Same process as wc_AesXtsDecrypt but uses a word64 type as the tweak
-           value instead of a byte array. This just converts the word64 to a
-           byte array.
-
-    \return 0 Success
-
-    \param aes    AES keys to use for block encrypt/decrypt
-    \param out    output buffer to hold plain text
-    \param in     input cipher text buffer to decrypt
-    \param sz     size of both out and in buffers
-    \param sector value to use for tweak
-
-    _Example_
-    \code
-    XtsAes aes;
-    unsigned char plain[SIZE];
-    unsigned char cipher[SIZE];
-    word64 s = VALUE;
-
-    //set up aes key with AES_DECRYPTION as dir and tweak with AES_ENCRYPTION
-
-    if(wc_AesXtsDecryptSector(&aes, plain, cipher, SIZE, s) != 0)
-    {
-        // Handle error
-    }
-    wc_AesXtsFree(&aes);
-    \endcode
-
-    \sa wc_AesXtsEncrypt
-    \sa wc_AesXtsDecrypt
-    \sa wc_AesXtsSetKey
-    \sa wc_AesXtsFree
-*/
 WOLFSSL_API int wc_AesXtsDecryptSector(XtsAes* aes, byte* out,
          const byte* in, word32 sz, word64 sector);
 
-
-/*!
-    \ingroup AES
-
-    \brief AES with XTS mode. (XTS) XEX encryption with Tweak and cipher text
-           Stealing.
-
-    \return 0 Success
-
-    \param aes   AES keys to use for block encrypt/decrypt
-    \param out   output buffer to hold cipher text
-    \param in    input plain text buffer to encrypt
-    \param sz    size of both out and in buffers
-    \param i     value to use for tweak
-    \param iSz   size of i buffer, should always be AES_BLOCK_SIZE but having
-                 this input adds a sanity check on how the user calls the
-                 function.
-
-    _Example_
-    \code
-    XtsAes aes;
-    unsigned char plain[SIZE];
-    unsigned char cipher[SIZE];
-    unsigned char i[AES_BLOCK_SIZE];
-
-    //set up key with AES_ENCRYPTION as dir
-
-    if(wc_AesXtsEncrypt(&aes, cipher, plain, SIZE, i, sizeof(i)) != 0)
-    {
-        // Handle error
-    }
-    wc_AesXtsFree(&aes);
-    \endcode
-
-    \sa wc_AesXtsDecrypt
-    \sa wc_AesXtsSetKey
-    \sa wc_AesXtsFree
-*/
 WOLFSSL_API int wc_AesXtsEncrypt(XtsAes* aes, byte* out,
          const byte* in, word32 sz, const byte* i, word32 iSz);
 
-
-/*!
-    \ingroup AES
-
-    \brief Same process as encryption but Aes key is AES_DECRYPTION type.
-
-    \return 0 Success
-
-    \param aes   AES keys to use for block encrypt/decrypt
-    \param out   output buffer to hold plain text
-    \param in    input cipher text buffer to decrypt
-    \param sz    size of both out and in buffers
-    \param i     value to use for tweak
-    \param iSz   size of i buffer, should always be AES_BLOCK_SIZE but having
-                 this input adds a sanity check on how the user calls the
-                 function.
-    _Example_
-    \code
-    XtsAes aes;
-    unsigned char plain[SIZE];
-    unsigned char cipher[SIZE];
-    unsigned char i[AES_BLOCK_SIZE];
-
-    //set up key with AES_DECRYPTION as dir and tweak with AES_ENCRYPTION
-
-    if(wc_AesXtsDecrypt(&aes, plain, cipher, SIZE, i, sizeof(i)) != 0)
-    {
-        // Handle error
-    }
-    wc_AesXtsFree(&aes);
-    \endcode
-
-    \sa wc_AesXtsEncrypt
-    \sa wc_AesXtsSetKey
-    \sa wc_AesXtsFree
-*/
 WOLFSSL_API int wc_AesXtsDecrypt(XtsAes* aes, byte* out,
         const byte* in, word32 sz, const byte* i, word32 iSz);
 
-
-/*!
-    \ingroup AES
-
-    \brief This is to free up any resources used by the XtsAes structure
-
-    \return 0 Success
-
-    \param aes AES keys to free
-
-    _Example_
-    \code
-    XtsAes aes;
-
-    if(wc_AesXtsSetKey(&aes, key, sizeof(key), AES_ENCRYPTION, NULL, 0) != 0)
-    {
-        // Handle error
-    }
-    wc_AesXtsFree(&aes);
-    \endcode
-
-    \sa wc_AesXtsEncrypt
-    \sa wc_AesXtsDecrypt
-    \sa wc_AesXtsSetKey
-*/
 WOLFSSL_API int wc_AesXtsFree(XtsAes* aes);
 #endif
@@ -439,6 +352,10 @@
 WOLFSSL_API int wc_AesGetKeySize(Aes* aes, word32* keySize);
 
-WOLFSSL_API int  wc_AesInit(Aes*, void*, int);
-WOLFSSL_API void wc_AesFree(Aes*);
+WOLFSSL_API int  wc_AesInit(Aes* aes, void* heap, int devId);
+#ifdef HAVE_PKCS11
+WOLFSSL_API int  wc_AesInit_Id(Aes* aes, unsigned char* id, int len, void* heap,
+        int devId);
+#endif
+WOLFSSL_API void wc_AesFree(Aes* aes);
 
 #ifdef __cplusplus
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/arc4.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/arc4.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/arc4.h	(revision 372)
@@ -20,5 +20,7 @@
  */
 
-
+/*!
+    \file wolfssl/wolfcrypt/arc4.h
+*/
 
 #ifndef WOLF_CRYPT_ARC4_H
@@ -37,5 +39,6 @@
 enum {
 	ARC4_ENC_TYPE   = 4,    /* cipher unique type */
-    ARC4_STATE_SIZE = 256
+    ARC4_STATE_SIZE = 256,
+    RC4_KEY_SIZE    = 16,   /* always 128bit           */
 };
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/asn.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/asn.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/asn.h	(revision 372)
@@ -20,4 +20,7 @@
  */
 
+/*!
+    \file wolfssl/wolfcrypt/asn.h
+*/
 
 #ifndef WOLF_CRYPT_ASN_H
@@ -28,8 +31,14 @@
 #ifndef NO_ASN
 
+
+#if !defined(NO_ASN_TIME) && defined(NO_TIME_H)
+    #define NO_ASN_TIME /* backwards compatibility with NO_TIME_H */
+#endif
+
 #include <wolfssl/wolfcrypt/integer.h>
 
 /* fips declare of RsaPrivateKeyDecode @wc_fips */
-#if defined(HAVE_FIPS) && !defined(NO_RSA)
+#if defined(HAVE_FIPS) && !defined(NO_RSA) && \
+	(!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))
     #include <cyassl/ctaocrypt/rsa.h>
 #endif
@@ -50,4 +59,7 @@
 #include <wolfssl/wolfcrypt/asn_public.h>   /* public interface */
 
+#if defined(NO_SHA) && defined(NO_SHA256)
+    #define WC_SHA256_DIGEST_SIZE 32
+#endif
 
 #ifdef __cplusplus
@@ -77,4 +89,5 @@
     ASN_SEQUENCE          = 0x10,
     ASN_SET               = 0x11,
+    ASN_PRINTABLE_STRING  = 0x13,
     ASN_UTC_TIME          = 0x17,
     ASN_OTHER_TYPE        = 0x00,
@@ -82,14 +95,20 @@
     ASN_DNS_TYPE          = 0x02,
     ASN_DIR_TYPE          = 0x04,
+    ASN_URI_TYPE          = 0x06, /* the value 6 is from GeneralName OID */
     ASN_GENERALIZED_TIME  = 0x18,
     CRL_EXTENSIONS        = 0xa0,
     ASN_EXTENSIONS        = 0xa3,
-    ASN_LONG_LENGTH       = 0x80
-};
-
-enum ASN_Flags {
+    ASN_LONG_LENGTH       = 0x80,
+    ASN_INDEF_LENGTH      = 0x80,
+
+    /* ASN_Flags - Bitmask */
     ASN_CONSTRUCTED       = 0x20,
-    ASN_CONTEXT_SPECIFIC  = 0x80
-};
+    ASN_APPLICATION       = 0x40,
+    ASN_CONTEXT_SPECIFIC  = 0x80,
+};
+
+#define ASN_UTC_TIME_SIZE 14
+#define ASN_GENERALIZED_TIME_SIZE 16
+#define ASN_GENERALIZED_TIME_MAX 68
 
 enum DN_Tags {
@@ -101,36 +120,106 @@
     ASN_STATE_NAME    = 0x08,   /* ST */
     ASN_ORG_NAME      = 0x0a,   /* O  */
-    ASN_ORGUNIT_NAME  = 0x0b    /* OU */
-};
-
-enum PBES {
-    PBE_MD5_DES      = 0,
-    PBE_SHA1_DES     = 1,
-    PBE_SHA1_DES3    = 2,
-    PBE_SHA1_RC4_128 = 3,
-    PBES2            = 13       /* algo ID */
-};
-
-enum ENCRYPTION_TYPES {
-    DES_TYPE  = 0,
-    DES3_TYPE = 1,
-    RC4_TYPE  = 2
-};
-
-enum ECC_TYPES {
+    ASN_ORGUNIT_NAME  = 0x0b,   /* OU */
+    ASN_BUS_CAT       = 0x0f,   /* businessCategory */
+    ASN_EMAIL_NAME    = 0x98,   /* not oid number there is 97 in 2.5.4.0-97 */
+
+    /* pilot attribute types
+     * OID values of 0.9.2342.19200300.100.1.* */
+    ASN_USER_ID          = 0x01, /* UID */
+    ASN_DOMAIN_COMPONENT = 0x19  /* DC */
+};
+
+/* DN Tag Strings */
+#define WOLFSSL_COMMON_NAME      "/CN="
+#define WOLFSSL_SUR_NAME         "/SN="
+#define WOLFSSL_SERIAL_NUMBER    "/serialNumber="
+#define WOLFSSL_COUNTRY_NAME     "/C="
+#define WOLFSSL_LOCALITY_NAME    "/L="
+#define WOLFSSL_STATE_NAME       "/ST="
+#define WOLFSSL_ORG_NAME         "/O="
+#define WOLFSSL_ORGUNIT_NAME     "/OU="
+#define WOLFSSL_DOMAIN_COMPONENT "/DC="
+#define WOLFSSL_BUS_CAT          "/businessCategory="
+#define WOLFSSL_JOI_C            "/jurisdictionC="
+#define WOLFSSL_JOI_ST           "/jurisdictionST="
+#define WOLFSSL_EMAIL_ADDR       "/emailAddress="
+
+/* NIDs */
+enum
+{
+    NID_undef = 0,
+    NID_des = 66,
+    NID_des3 = 67,
+    NID_sha256 = 672,
+    NID_sha384 = 673,
+    NID_sha512 = 674,
+    NID_hw_name_oid = 73,
+    NID_id_pkix_OCSP_basic = 74,
+    NID_any_policy = 75,
+    NID_anyExtendedKeyUsage = 76,
+    NID_basic_constraints = 133,
+    NID_key_usage = 129,     /* 2.5.29.15 */
+    NID_ext_key_usage = 151, /* 2.5.29.37 */
+    NID_subject_key_identifier = 128,
+    NID_authority_key_identifier = 149,
+    NID_private_key_usage_period = 130, /* 2.5.29.16 */
+    NID_subject_alt_name = 131,
+    NID_issuer_alt_name = 132,
+    NID_info_access = 69,
+    NID_sinfo_access = 79,      /* id-pe 11 */
+    NID_name_constraints = 144, /* 2.5.29.30 */
+    NID_certificate_policies = 146,
+    NID_policy_mappings = 147,
+    NID_policy_constraints = 150,
+    NID_inhibit_any_policy = 168,      /* 2.5.29.54 */
+    NID_tlsfeature = 92,               /* id-pe 24 */
+    NID_commonName = 0x03,             /* matchs ASN_COMMON_NAME in asn.h */
+    NID_surname = 0x04,                /* SN */
+    NID_serialNumber = 0x05,           /* serialNumber */
+    NID_countryName = 0x06,            /* C  */
+    NID_localityName = 0x07,           /* L  */
+    NID_stateOrProvinceName = 0x08,    /* ST */
+    NID_organizationName = 0x0a,       /* O  */
+    NID_organizationalUnitName = 0x0b, /* OU */
+    NID_domainComponent = 0x19,        /* matchs ASN_DOMAIN_COMPONENT in asn.h */
+    NID_emailAddress = 0x30,           /* emailAddress */
+};
+
+enum ECC_TYPES
+{
     ECC_PREFIX_0 = 160,
     ECC_PREFIX_1 = 161
 };
 
+#ifdef WOLFSSL_CERT_PIV
+    enum PIV_Tags {
+        ASN_PIV_CERT          = 0x0A,
+        ASN_PIV_NONCE         = 0x0B,
+        ASN_PIV_SIGNED_NONCE  = 0x0C,
+            
+        ASN_PIV_TAG_CERT      = 0x70,
+        ASN_PIV_TAG_CERT_INFO = 0x71,
+        ASN_PIV_TAG_MSCUID    = 0x72,
+        ASN_PIV_TAG_ERR_DET   = 0xFE,
+            
+        /* certificate info masks */
+        ASN_PIV_CERT_INFO_COMPRESSED = 0x03,
+        ASN_PIV_CERT_INFO_ISX509     = 0x04,
+    };
+#endif /* WOLFSSL_CERT_PIV */
+
+
+#define ASN_JOI_PREFIX "\x2b\x06\x01\x04\x01\x82\x37\x3c\x02\x01"
+#define ASN_JOI_C      0x3
+#define ASN_JOI_ST     0x2
+
+#ifndef WC_ASN_NAME_MAX
+    #define WC_ASN_NAME_MAX 256
+#endif
+
 enum Misc_ASN {
-    ASN_NAME_MAX        = 256,
+    ASN_NAME_MAX        = WC_ASN_NAME_MAX,
     MAX_SALT_SIZE       =  64,     /* MAX PKCS Salt length */
     MAX_IV_SIZE         =  64,     /* MAX PKCS Iv length */
-    MAX_KEY_SIZE        =  64,     /* MAX PKCS Key  length */
-    PKCS5               =   5,     /* PKCS oid tag */
-    PKCS5v2             =   6,     /* PKCS #5 v2.0 */
-    PKCS8v0             =   0,     /* default PKCS#8 version */
-    PKCS12v1            =  12,     /* PKCS #12 */
-    MAX_UNICODE_SZ      = 256,
     ASN_BOOL_SIZE       =   2,     /* including type */
     ASN_ECC_HEADER_SZ   =   2,     /* String type + 1 byte len */
@@ -146,7 +235,14 @@
     MAX_DATE_SIZE       =  32,
     ASN_GEN_TIME_SZ     =  15,     /* 7 numbers * 2 + Zulu tag */
+#ifndef NO_RSA
     MAX_ENCODED_SIG_SZ  = 512,
+#elif defined(HAVE_ECC)
+    MAX_ENCODED_SIG_SZ  = 140,
+#else
+    MAX_ENCODED_SIG_SZ  =  64,
+#endif
     MAX_SIG_SZ          = 256,
     MAX_ALGO_SZ         =  20,
+    MAX_SHORT_SZ        =   6,     /* asn int + byte len + 4 byte length */
     MAX_SEQ_SZ          =   5,     /* enum(seq | con) + length(4) */
     MAX_SET_SZ          =   5,     /* enum(set | con) + length(4) */
@@ -155,5 +251,6 @@
     MAX_PRSTR_SZ        =   5,     /* enum(prstr) + length(4) */
     MAX_VERSION_SZ      =   5,     /* enum + id + version(byte) + (header(2))*/
-    MAX_ENCODED_DIG_SZ  =  73,     /* sha512 + enum(bit or octet) + length(4) */
+    MAX_ENCODED_DIG_ASN_SZ= 9,     /* enum(bit or octet) + length(4) */
+    MAX_ENCODED_DIG_SZ  =  64 + MAX_ENCODED_DIG_ASN_SZ, /* asn header + sha512 */
     MAX_RSA_INT_SZ      = 517,     /* RSA raw sz 4096 for bits + tag + len(4) */
     MAX_NTRU_KEY_SZ     = 610,     /* NTRU 112 bit public key */
@@ -163,5 +260,8 @@
     MAX_CA_SZ           =  32,     /* Max encoded CA basic constraint length */
     MAX_SN_SZ           =  35,     /* Max encoded serial number (INT) length */
-    MAX_DER_DIGEST_SZ   = MAX_ENCODED_DIG_SZ + MAX_ALGO_SZ + MAX_SEQ_SZ, /* Maximum DER digest size */
+    MAX_DER_DIGEST_SZ     = MAX_ENCODED_DIG_SZ + MAX_ALGO_SZ + MAX_SEQ_SZ,
+                            /* Maximum DER digest size */
+    MAX_DER_DIGEST_ASN_SZ = MAX_ENCODED_DIG_ASN_SZ + MAX_ALGO_SZ + MAX_SEQ_SZ,
+                            /* Maximum DER digest ASN header size */
 #ifdef WOLFSSL_CERT_GEN
     #ifdef WOLFSSL_CERT_REQ
@@ -177,14 +277,19 @@
                                    /* Max total extensions, id + len + others */
 #endif
+#if defined(WOLFSSL_CERT_EXT) || defined(OPENSSL_EXTRA) || defined(HAVE_PKCS7)
+    MAX_OID_SZ          = 32,      /* Max DER length of OID*/
+    MAX_OID_STRING_SZ   = 64,      /* Max string length representation of OID*/
+#endif
 #ifdef WOLFSSL_CERT_EXT
     MAX_KID_SZ			= 45,	   /* Max encoded KID length (SHA-256 case) */
     MAX_KEYUSAGE_SZ     = 18,      /* Max encoded Key Usage length */
-    MAX_EXTKEYUSAGE_SZ  = 12 + (6 * (8 + 2)), /* Max encoded ExtKeyUsage
-                        (SEQ/LEN + OBJID + OCTSTR/LEN + SEQ + (6 * (SEQ + OID))) */
-    MAX_OID_SZ          = 32,      /* Max DER length of OID*/
-    MAX_OID_STRING_SZ   = 64,      /* Max string length representation of OID*/
+    MAX_EXTKEYUSAGE_SZ  = 12 + (6 * (8 + 2)) +
+                          CTC_MAX_EKU_OID_SZ, /* Max encoded ExtKeyUsage
+                          (SEQ/LEN + OBJID + OCTSTR/LEN + SEQ +
+                          (6 * (SEQ + OID))) */
     MAX_CERTPOL_NB      = CTC_MAX_CERTPOL_NB,/* Max number of Cert Policy */
     MAX_CERTPOL_SZ      = CTC_MAX_CERTPOL_SZ,
 #endif
+    MAX_NAME_ENTRIES    = 5,       /* extra entries added to x509 name struct */
     OCSP_NONCE_EXT_SZ   = 35,      /* OCSP Nonce Extension size */
     MAX_OCSP_EXT_SZ     = 58,      /* Max OCSP Extension length */
@@ -193,10 +298,21 @@
     MAX_PUBLIC_KEY_SZ   = MAX_NTRU_ENC_SZ + MAX_ALGO_SZ + MAX_SEQ_SZ * 2,
                                    /* use bigger NTRU size */
+#ifdef WOLFSSL_ENCRYPTED_KEYS
     HEADER_ENCRYPTED_KEY_SIZE = 88,/* Extra header size for encrypted key */
+#else
+    HEADER_ENCRYPTED_KEY_SIZE = 0,
+#endif
     TRAILING_ZERO       = 1,       /* Used for size of zero pad */
+    ASN_TAG_SZ          = 1,       /* single byte ASN.1 tag */
     MIN_VERSION_SZ      = 3,       /* Min bytes needed for GetMyVersion */
-#if defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+#if defined(OPENSSL_ALL)  || defined(WOLFSSL_MYSQL_COMPATIBLE) || \
+    defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \
+    defined(OPENSSL_EXTRA) || defined(HAVE_PKCS7)
     MAX_TIME_STRING_SZ  = 25,      /* Max length of formatted time string */
 #endif
+
+    PKCS5_SALT_SZ       = 8,
+
+    PEM_LINE_LEN       = 80,       /* PEM line max + fudge */
 };
 
@@ -217,4 +333,8 @@
     oidKeyWrapType      = 12,
     oidCmsKeyAgreeType  = 13,
+    oidPBEType          = 14,
+    oidHmacType         = 15,
+    oidCompressType     = 16,
+    oidCertNameType     = 17,
     oidIgnoreType
 };
@@ -232,11 +352,27 @@
 
 
+#if !defined(NO_DES3) || !defined(NO_AES)
 enum Block_Sum {
+#ifdef WOLFSSL_AES_128
     AES128CBCb = 414,
+    AES128GCMb = 418,
+    AES128CCMb = 419,
+#endif
+#ifdef WOLFSSL_AES_192
     AES192CBCb = 434,
+    AES192GCMb = 438,
+    AES192CCMb = 439,
+#endif
+#ifdef WOLFSSL_AES_256
     AES256CBCb = 454,
+    AES256GCMb = 458,
+    AES256CCMb = 459,
+#endif
+#ifndef NO_DES3
     DESb       = 69,
     DES3b      = 652
-};
+#endif
+};
+#endif /* !NO_DES3 || !NO_AES */
 
 
@@ -250,10 +386,20 @@
 
 
+#if !defined(NO_AES) || defined(HAVE_PKCS7)
 enum KeyWrap_Sum {
+#ifdef WOLFSSL_AES_128
     AES128_WRAP = 417,
+#endif
+#ifdef WOLFSSL_AES_192
     AES192_WRAP = 437,
-    AES256_WRAP = 457
-};
-
+#endif
+#ifdef WOLFSSL_AES_256
+    AES256_WRAP  = 457,
+#endif
+#ifdef HAVE_PKCS7
+    PWRI_KEK_WRAP = 680  /*id-alg-PWRI-KEK, 1.2.840.113549.1.9.16.3.9 */
+#endif
+};
+#endif /* !NO_AES || PKCS7 */
 
 enum Key_Agree {
@@ -304,4 +450,12 @@
 
 
+enum HMAC_Sum {
+    HMAC_SHA224_OID = 652,
+    HMAC_SHA256_OID = 653,
+    HMAC_SHA384_OID = 654,
+    HMAC_SHA512_OID = 655
+};
+
+
 enum Extensions_Sum {
     BASIC_CA_OID    = 133,
@@ -347,4 +501,9 @@
 };
 
+#ifdef HAVE_LIBZ
+enum CompressAlg_Sum {
+    ZLIBc = 679  /* 1.2.840.113549.1.9.16.3.8, id-alg-zlibCompress */
+};
+#endif
 
 enum VerifyType {
@@ -352,5 +511,6 @@
     VERIFY      = 1,
     VERIFY_CRL  = 2,
-    VERIFY_OCSP = 3
+    VERIFY_OCSP = 3,
+    VERIFY_NAME = 4
 };
 
@@ -374,4 +534,5 @@
 
 /* Extended Key Usage bits (internal mapping only) */
+#define EXTKEYUSE_USER        0x80
 #define EXTKEYUSE_OCSP_SIGN   0x40
 #define EXTKEYUSE_TIMESTAMP   0x20
@@ -386,4 +547,6 @@
 struct DNS_entry {
     DNS_entry* next;   /* next on DNS list */
+    int        type;   /* i.e. ASN_DNS_TYPE */
+    int        len;    /* actual DNS len */
     char*      name;   /* actual DNS name */
 };
@@ -399,4 +562,5 @@
 };
 
+#define DOMAIN_COMPONENT_MAX 10
 
 struct DecodedName {
@@ -406,22 +570,44 @@
     int     cnIdx;
     int     cnLen;
+    int     cnNid;
     int     snIdx;
     int     snLen;
+    int     snNid;
     int     cIdx;
     int     cLen;
+    int     cNid;
     int     lIdx;
     int     lLen;
+    int     lNid;
     int     stIdx;
     int     stLen;
+    int     stNid;
     int     oIdx;
     int     oLen;
+    int     oNid;
     int     ouIdx;
     int     ouLen;
+#ifdef WOLFSSL_CERT_EXT
+    int     bcIdx;
+    int     bcLen;
+    int     jcIdx;
+    int     jcLen;
+    int     jsIdx;
+    int     jsLen;
+#endif
+    int     ouNid;
     int     emailIdx;
     int     emailLen;
+    int     emailNid;
     int     uidIdx;
     int     uidLen;
+    int     uidNid;
     int     serialIdx;
     int     serialLen;
+    int     serialNid;
+    int     dcIdx[DOMAIN_COMPONENT_MAX];
+    int     dcLen[DOMAIN_COMPONENT_MAX];
+    int     dcNum;
+    int     dcMode;
 };
 
@@ -433,4 +619,22 @@
     SIG_STATE_CHECK,
 };
+
+
+#ifdef HAVE_PK_CALLBACKS
+#ifdef HAVE_ECC
+    typedef int (*wc_CallbackEccVerify)(
+           const unsigned char* sig, unsigned int sigSz,
+           const unsigned char* hash, unsigned int hashSz,
+           const unsigned char* keyDer, unsigned int keySz,
+           int* result, void* ctx);
+#endif
+#ifndef NO_RSA
+    typedef int (*wc_CallbackRsaVerify)(
+           unsigned char* sig, unsigned int sigSz,
+           unsigned char** out,
+           const unsigned char* keyDer, unsigned int keySz,
+           void* ctx);
+#endif
+#endif /* HAVE_PK_CALLBACKS */
 
 struct SignatureCtx {
@@ -465,4 +669,15 @@
     void* asyncCtx;
 #endif
+
+#ifdef HAVE_PK_CALLBACKS
+#ifdef HAVE_ECC
+    wc_CallbackEccVerify pkCbEcc;
+    void* pkCtxEcc;
+#endif
+#ifndef NO_RSA
+    wc_CallbackRsaVerify pkCbRsa;
+    void* pkCtxRsa;
+#endif
+#endif /* HAVE_PK_CALLBACKS */
 };
 
@@ -496,5 +711,5 @@
 
 struct DecodedCert {
-    byte*   publicKey;
+    const byte* publicKey;
     word32  pubKeySize;
     int     pubKeyStored;
@@ -516,13 +731,12 @@
     byte    issuerKeyHash[KEYID_SIZE]; /* hash of the public Key         */
 #endif /* HAVE_OCSP */
-    byte*   signature;               /* not owned, points into raw cert  */
+    const byte* signature;           /* not owned, points into raw cert  */
     char*   subjectCN;               /* CommonName                       */
     int     subjectCNLen;            /* CommonName Length                */
     char    subjectCNEnc;            /* CommonName Encoding              */
-    int     subjectCNStored;         /* have we saved a copy we own      */
     char    issuer[ASN_NAME_MAX];    /* full name including common name  */
     char    subject[ASN_NAME_MAX];   /* full name including common name  */
     int     verify;                  /* Default to yes, but could be off */
-    byte*   source;                  /* byte buffer holder cert, NOT owner */
+    const byte* source;              /* byte buffer holder cert, NOT owner */
     word32  srcIdx;                  /* current offset into buffer       */
     word32  maxIdx;                  /* max offset based on init size    */
@@ -530,66 +744,43 @@
     byte    serial[EXTERNAL_SERIAL_SIZE];  /* raw serial number          */
     int     serialSz;                /* raw serial bytes stored */
-    byte*   extensions;              /* not owned, points into raw cert  */
+    const byte* extensions;          /* not owned, points into raw cert  */
     int     extensionsSz;            /* length of cert extensions */
     word32  extensionsIdx;           /* if want to go back and parse later */
-    byte*   extAuthInfo;             /* Authority Information Access URI */
+    const byte* extAuthInfo;         /* Authority Information Access URI */
     int     extAuthInfoSz;           /* length of the URI                */
-    byte*   extCrlInfo;              /* CRL Distribution Points          */
+    const byte* extCrlInfo;          /* CRL Distribution Points          */
     int     extCrlInfoSz;            /* length of the URI                */
     byte    extSubjKeyId[KEYID_SIZE]; /* Subject Key ID                  */
-    byte    extSubjKeyIdSet;         /* Set when the SKID was read from cert */
     byte    extAuthKeyId[KEYID_SIZE]; /* Authority Key ID                */
-    byte    extAuthKeyIdSet;         /* Set when the AKID was read from cert */
-#ifndef IGNORE_NAME_CONSTRAINTS
-    byte    extNameConstraintSet;
-#endif /* IGNORE_NAME_CONSTRAINTS */
-    byte    isCA;                    /* CA basic constraint true         */
-    byte    pathLengthSet;           /* CA basic const path length set   */
     byte    pathLength;              /* CA basic constraint path length  */
-    byte    weOwnAltNames;           /* altNames haven't been given to copy */
-    byte    extKeyUsageSet;
     word16  extKeyUsage;             /* Key usage bitfield               */
-    byte    extExtKeyUsageSet;       /* Extended Key Usage               */
     byte    extExtKeyUsage;          /* Extended Key usage bitfield      */
-#ifdef OPENSSL_EXTRA
-    byte    extCRLdistSet;
-    byte    extCRLdistCrit;
-    byte    extAuthInfoSet;
-    byte    extAuthInfoCrit;
-    byte    extBasicConstSet;
-    byte    extBasicConstCrit;
-    byte    extSubjAltNameSet;
-    byte    extSubjAltNameCrit;
-    byte    extAuthKeyIdCrit;
-#ifndef IGNORE_NAME_CONSTRAINTS
-    byte    extNameConstraintCrit;
-#endif /* IGNORE_NAME_CONSTRAINTS */
-    byte    extSubjKeyIdCrit;
-    byte    extKeyUsageCrit;
-    byte    extExtKeyUsageCrit;
-    byte*   extExtKeyUsageSrc;
+
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+    const byte* extExtKeyUsageSrc;
     word32  extExtKeyUsageSz;
     word32  extExtKeyUsageCount;
-    byte*   extAuthKeyIdSrc;
+    const byte* extAuthKeyIdSrc;
     word32  extAuthKeyIdSz;
-    byte*   extSubjKeyIdSrc;
+    const byte* extSubjKeyIdSrc;
     word32  extSubjKeyIdSz;
 #endif
+
 #if defined(HAVE_ECC) || defined(HAVE_ED25519)
     word32  pkCurveOID;           /* Public Key's curve OID */
 #endif /* HAVE_ECC */
-    byte*   beforeDate;
+    const byte* beforeDate;
     int     beforeDateLen;
-    byte*   afterDate;
+    const byte* afterDate;
     int     afterDateLen;
-#ifdef HAVE_PKCS7
-    byte*   issuerRaw;               /* pointer to issuer inside source */
+#if defined(HAVE_PKCS7) || defined(WOLFSSL_CERT_EXT)
+    const byte* issuerRaw;           /* pointer to issuer inside source */
     int     issuerRawLen;
 #endif
 #ifndef IGNORE_NAME_CONSTRAINT
-    byte*   subjectRaw;               /* pointer to subject inside source */
+    const byte* subjectRaw;          /* pointer to subject inside source */
     int     subjectRawLen;
 #endif
-#if defined(WOLFSSL_CERT_GEN)
+#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT)
     /* easy access to subject info for other sign */
     char*   subjectSN;
@@ -611,8 +802,22 @@
     int     subjectOULen;
     char    subjectOUEnc;
+    char*   subjectSND;
+    int     subjectSNDLen;
+    char    subjectSNDEnc;
+#ifdef WOLFSSL_CERT_EXT
+    char*   subjectBC;
+    int     subjectBCLen;
+    char    subjectBCEnc;
+    char*   subjectJC;
+    int     subjectJCLen;
+    char    subjectJCEnc;
+    char*   subjectJS;
+    int     subjectJSLen;
+    char    subjectJSEnc;
+#endif
     char*   subjectEmail;
     int     subjectEmailLen;
 #endif /* WOLFSSL_CERT_GEN */
-#ifdef OPENSSL_EXTRA
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
     DecodedName issuerName;
     DecodedName subjectName;
@@ -625,52 +830,52 @@
     int     hwSerialNumSz;
     byte*   hwSerialNum;
-    #ifdef OPENSSL_EXTRA
-        byte    extCertPolicySet;
-        byte    extCertPolicyCrit;
-    #endif /* OPENSSL_EXTRA */
 #endif /* WOLFSSL_SEP */
 #ifdef WOLFSSL_CERT_EXT
     char    extCertPolicies[MAX_CERTPOL_NB][MAX_CERTPOL_SZ];
     int     extCertPoliciesNb;
-#endif /* WOLFSSL_CERT_EXT */
+#endif /* defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT) */
 
     Signer* ca;
     SignatureCtx sigCtx;
-};
-
-
-struct WOLFSSL_ASN1_OBJECT {
-    void*  heap;
-    byte*  obj;
-    int    type; /* oid */
-    word32 objSz;
-    byte   dynamic; /* if 1 then obj was dynamiclly created, 0 otherwise */
-};
-
-
-extern const char* BEGIN_CERT;
-extern const char* END_CERT;
-extern const char* BEGIN_CERT_REQ;
-extern const char* END_CERT_REQ;
-extern const char* BEGIN_DSA_PARAM;
-extern const char* END_DSA_PARAM;
-extern const char* BEGIN_DH_PARAM;
-extern const char* END_DH_PARAM;
-extern const char* BEGIN_X509_CRL;
-extern const char* END_X509_CRL;
-extern const char* BEGIN_RSA_PRIV;
-extern const char* END_RSA_PRIV;
-extern const char* BEGIN_PRIV_KEY;
-extern const char* END_PRIV_KEY;
-extern const char* BEGIN_ENC_PRIV_KEY;
-extern const char* END_ENC_PRIV_KEY;
-extern const char* BEGIN_EC_PRIV;
-extern const char* END_EC_PRIV;
-extern const char* BEGIN_DSA_PRIV;
-extern const char* END_DSA_PRIV;
-extern const char* BEGIN_PUB_KEY;
-extern const char* END_PUB_KEY;
-extern const char* BEGIN_EDDSA_PRIV;
-extern const char* END_EDDSA_PRIV;
+
+    /* Option Bits */
+    byte subjectCNStored : 1;      /* have we saved a copy we own */
+    byte extSubjKeyIdSet : 1;      /* Set when the SKID was read from cert */
+    byte extAuthKeyIdSet : 1;      /* Set when the AKID was read from cert */
+#ifndef IGNORE_NAME_CONSTRAINTS
+    byte extNameConstraintSet : 1;
+#endif
+    byte isCA : 1;                 /* CA basic constraint true */
+    byte pathLengthSet : 1;        /* CA basic const path length set */
+    byte weOwnAltNames : 1;        /* altNames haven't been given to copy */
+    byte extKeyUsageSet : 1;
+    byte extExtKeyUsageSet : 1;    /* Extended Key Usage set */
+    byte extCRLdistSet : 1;
+    byte extAuthInfoSet : 1;
+    byte extBasicConstSet : 1;
+    byte extSubjAltNameSet : 1;
+    byte inhibitAnyOidSet : 1;
+#ifdef WOLFSSL_SEP
+    byte extCertPolicySet : 1;
+#endif
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+    byte extCRLdistCrit : 1;
+    byte extAuthInfoCrit : 1;
+    byte extBasicConstCrit : 1;
+    byte extSubjAltNameCrit : 1;
+    byte extAuthKeyIdCrit : 1;
+    #ifndef IGNORE_NAME_CONSTRAINTS
+        byte extNameConstraintCrit : 1;
+    #endif
+    byte extSubjKeyIdCrit : 1;
+    byte extKeyUsageCrit : 1;
+    byte extExtKeyUsageCrit : 1;
+#endif /* OPENSSL_EXTRA */
+#ifdef WOLFSSL_SEP
+    byte extCertPolicyCrit : 1;
+#endif
+
+};
+
 
 #ifdef NO_SHA
@@ -688,5 +893,5 @@
     byte    pathLength;
     byte    pathLengthSet;
-    byte*   publicKey;
+    const byte* publicKey;
     int     nameLen;
     char*   name;                    /* common name */
@@ -701,4 +906,7 @@
                                      /* sha hash of names in certificate */
     #endif
+#ifdef WOLFSSL_SIGNER_DER_CERT
+    DerBuffer* derCert;
+#endif
     Signer* next;
 };
@@ -728,9 +936,27 @@
 
 /* for testing or custom openssl wrappers */
-#if defined(WOLFSSL_TEST_CERT) || defined(OPENSSL_EXTRA)
+#if defined(WOLFSSL_TEST_CERT) || defined(OPENSSL_EXTRA) || \
+    defined(OPENSSL_EXTRA_X509_SMALL)
     #define WOLFSSL_ASN_API WOLFSSL_API
 #else
     #define WOLFSSL_ASN_API WOLFSSL_LOCAL
 #endif
+
+/* Macro for calculating hashId */
+#if defined(NO_SHA) && defined(NO_SHA256)
+    #ifdef WOLF_CRYPTO_DEV
+        #define CalcHashId(data, len, hash) wc_CryptoDevSha256Hash(data, len, hash)
+    #else
+        #define CalcHashId(data, len, hash) NOT_COMPILED_IN
+    #endif
+#elif defined(NO_SHA)
+    #define CalcHashId(data, len, hash)     wc_Sha256Hash(data, len, hash)
+#else
+    #define CalcHashId(data, len, hash)     wc_ShaHash(data, len, hash)
+#endif
+
+
+WOLFSSL_ASN_API int wc_BerToDer(const byte* ber, word32 berSz, byte* der,
+                                word32* derSz);
 
 WOLFSSL_ASN_API void FreeAltNames(DNS_entry*, void*);
@@ -738,11 +964,15 @@
     WOLFSSL_ASN_API void FreeNameSubtrees(Base_entry*, void*);
 #endif /* IGNORE_NAME_CONSTRAINTS */
-WOLFSSL_ASN_API void InitDecodedCert(DecodedCert*, byte*, word32, void*);
+WOLFSSL_ASN_API void InitDecodedCert(DecodedCert*, const byte*, word32, void*);
 WOLFSSL_ASN_API void FreeDecodedCert(DecodedCert*);
 WOLFSSL_ASN_API int  ParseCert(DecodedCert*, int type, int verify, void* cm);
 
+WOLFSSL_LOCAL int DecodePolicyOID(char *o, word32 oSz,
+                                  const byte *in, word32 inSz);
+WOLFSSL_API int CheckCertSignature(const byte*,word32,void*,void* cm);
 WOLFSSL_LOCAL int ParseCertRelative(DecodedCert*,int type,int verify,void* cm);
 WOLFSSL_LOCAL int DecodeToKey(DecodedCert*, int verify);
 
+WOLFSSL_LOCAL const byte* OidFromId(word32 id, word32 type, word32* oidSz);
 WOLFSSL_LOCAL Signer* MakeSigner(void*);
 WOLFSSL_LOCAL void    FreeSigner(Signer*, void*);
@@ -754,18 +984,38 @@
 
 WOLFSSL_ASN_API int ToTraditional(byte* buffer, word32 length);
+WOLFSSL_ASN_API int ToTraditional_ex(byte* buffer, word32 length,
+                                     word32* algId);
 WOLFSSL_LOCAL int ToTraditionalInline(const byte* input, word32* inOutIdx,
                                       word32 length);
-WOLFSSL_LOCAL int ToTraditionalEnc(byte* buffer, word32 length,const char*,int);
+WOLFSSL_LOCAL int ToTraditionalInline_ex(const byte* input, word32* inOutIdx,
+                                         word32 length, word32* algId);
+WOLFSSL_LOCAL int ToTraditionalEnc(byte* buffer, word32 length,const char*,int,
+                                   word32* algId);
+WOLFSSL_ASN_API int UnTraditionalEnc(byte* key, word32 keySz, byte* out,
+        word32* outSz, const char* password, int passwordSz, int vPKCS,
+        int vAlgo, byte* salt, word32 saltSz, int itt, WC_RNG* rng, void* heap);
+WOLFSSL_ASN_API int TraditionalEnc(byte* key, word32 keySz, byte* out,
+        word32* outSz, const char* password, int passwordSz, int vPKCS,
+        int vAlgo, int encAlgId, byte* salt, word32 saltSz, int itt,
+        WC_RNG* rng, void* heap);
 WOLFSSL_LOCAL int DecryptContent(byte* input, word32 sz,const char* psw,int pswSz);
+WOLFSSL_LOCAL int EncryptContent(byte* input, word32 sz, byte* out, word32* outSz,
+        const char* password,int passwordSz, int vPKCS, int vAlgo,
+        byte* salt, word32 saltSz, int itt, WC_RNG* rng, void* heap);
 WOLFSSL_LOCAL int wc_GetKeyOID(byte* key, word32 keySz, const byte** curveOID,
         word32* oidSz, int* algoID, void* heap);
 
 typedef struct tm wolfssl_tm;
-#if defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(OPENSSL_EXTRA) || \
+    defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
 WOLFSSL_LOCAL int GetTimeString(byte* date, int format, char* buf, int len);
+#endif
+#if !defined(NO_ASN_TIME) && defined(HAVE_PKCS7)
+WOLFSSL_LOCAL int GetAsnTimeString(void* currTime, byte* buf, word32 len);
 #endif
 WOLFSSL_LOCAL int ExtractDate(const unsigned char* date, unsigned char format,
                                                  wolfssl_tm* certTime, int* idx);
 WOLFSSL_LOCAL int ValidateDate(const byte* date, byte format, int dateType);
+WOLFSSL_LOCAL int OBJ_sn2nid(const char *sn);
 
 /* ASN.1 helper functions */
@@ -775,8 +1025,13 @@
 WOLFSSL_LOCAL int GetShortInt(const byte* input, word32* inOutIdx, int* number,
                               word32 maxIdx);
+WOLFSSL_LOCAL char* GetSigName(int oid);
 WOLFSSL_LOCAL int GetLength(const byte* input, word32* inOutIdx, int* len,
                            word32 maxIdx);
+WOLFSSL_LOCAL int GetLength_ex(const byte* input, word32* inOutIdx, int* len,
+                           word32 maxIdx, int check);
 WOLFSSL_LOCAL int GetSequence(const byte* input, word32* inOutIdx, int* len,
                              word32 maxIdx);
+WOLFSSL_LOCAL int GetSequence_ex(const byte* input, word32* inOutIdx, int* len,
+                           word32 maxIdx, int check);
 WOLFSSL_LOCAL int GetSet(const byte* input, word32* inOutIdx, int* len,
                         word32 maxIdx);
@@ -793,4 +1048,7 @@
         word16* out, word32* outSz);
 #endif
+WOLFSSL_LOCAL int GetASNObjectId(const byte* input, word32* inOutIdx, int* len,
+                                 word32 maxIdx);
+WOLFSSL_LOCAL int SetObjectId(int len, byte* output);
 WOLFSSL_LOCAL int GetObjectId(const byte* input, word32* inOutIdx, word32* oid,
                               word32 oidType, word32 maxIdx);
@@ -812,4 +1070,5 @@
                              int maxIdx);
 WOLFSSL_LOCAL int wc_CheckPrivateKey(byte* key, word32 keySz, DecodedCert* der);
+WOLFSSL_LOCAL int RsaPublicKeyDerSize(RsaKey* key, int with_header);
 
 #ifdef HAVE_ECC
@@ -824,11 +1083,28 @@
 WOLFSSL_LOCAL void FreeSignatureCtx(SignatureCtx* sigCtx);
 
+#ifndef NO_CERTS
+
+WOLFSSL_LOCAL int wc_EncryptedInfoParse(EncryptedInfo* info, char** pBuffer,
+                                        size_t bufSz);
+
+WOLFSSL_LOCAL int PemToDer(const unsigned char* buff, long sz, int type,
+                          DerBuffer** pDer, void* heap, EncryptedInfo* info,
+                          int* eccKey);
+WOLFSSL_LOCAL int AllocDer(DerBuffer** der, word32 length, int type, void* heap);
+WOLFSSL_LOCAL void FreeDer(DerBuffer** der);
+
+#endif /* !NO_CERTS */
 
 #ifdef WOLFSSL_CERT_GEN
 
 enum cert_enums {
-    NAME_ENTRIES    =  8,
+#ifdef WOLFSSL_CERT_EXT
+    NAME_ENTRIES    =  10,
+#else
+    NAME_ENTRIES    =  9,
+#endif
     JOINT_LEN       =  2,
     EMAIL_JOINT_LEN =  9,
+    PILOT_JOINT_LEN =  10,
     RSA_KEY         = 10,
     NTRU_KEY        = 11,
@@ -836,13 +1112,4 @@
     ED25519_KEY     = 13
 };
-
-#ifndef WOLFSSL_PEMCERT_TODER_DEFINED
-#ifndef NO_FILESYSTEM
-/* forward from wolfSSL */
-WOLFSSL_API
-int wolfSSL_PemCertToDer(const char* fileName,unsigned char* derBuf,int derSz);
-#define WOLFSSL_PEMCERT_TODER_DEFINED
-#endif
-#endif
 
 #endif /* WOLFSSL_CERT_GEN */
@@ -877,4 +1144,11 @@
 };
 
+#ifdef OPENSSL_EXTRA
+enum Ocsp_Verify_Error {
+    OCSP_VERIFY_ERROR_NONE = 0,
+    OCSP_BAD_ISSUER = 1
+};
+#endif
+
 
 typedef struct OcspRequest  OcspRequest;
@@ -894,5 +1168,5 @@
     byte thisDateFormat;
     byte nextDateFormat;
-#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
     byte* thisDateAsn;
     byte* nextDateAsn;
@@ -930,4 +1204,8 @@
     byte*   source;          /* pointer to source buffer, not owned */
     word32  maxIdx;          /* max offset based on init size */
+
+#ifdef OPENSSL_EXTRA
+    int     verifyError;
+#endif
 };
 
@@ -1011,3 +1289,35 @@
 
 #endif /* !NO_ASN */
+
+
+#if !defined(NO_ASN) || !defined(NO_PWDBASED)
+
+#ifndef MAX_KEY_SIZE
+    #define MAX_KEY_SIZE    64  /* MAX PKCS Key length */
+#endif
+#ifndef MAX_UNICODE_SZ
+    #define MAX_UNICODE_SZ  256
+#endif
+
+enum PBESTypes {
+    PBE_MD5_DES      = 0,
+    PBE_SHA1_RC4_128 = 1,
+    PBE_SHA1_DES     = 2,
+    PBE_SHA1_DES3    = 3,
+    PBE_AES256_CBC   = 4,
+
+    PBE_SHA1_RC4_128_SUM = 657,
+    PBE_SHA1_DES3_SUM    = 659,
+    PBES2            = 13       /* algo ID */
+};
+
+enum PKCSTypes {
+    PKCS5v2             =   6,     /* PKCS #5 v2.0 */
+    PKCS12v1            =  12,     /* PKCS #12 */
+    PKCS5               =   5,     /* PKCS oid tag */
+    PKCS8v0             =   0,     /* default PKCS#8 version */
+};
+
+#endif /* !NO_ASN || !NO_PWDBASED */
+
 #endif /* WOLF_CRYPT_ASN_H */
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/asn_public.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/asn_public.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/asn_public.h	(revision 372)
@@ -20,5 +20,7 @@
  */
 
-
+/*!
+    \file wolfssl/wolfcrypt/asn_public.h
+*/
 
 #ifndef WOLF_CRYPT_ASN_PUBLIC_H
@@ -48,4 +50,5 @@
     #define WC_RNG_TYPE_DEFINED
 #endif
+
 
 /* Certificate file Type */
@@ -68,5 +71,8 @@
     TRUSTED_PEER_TYPE,
     EDDSA_PRIVATEKEY_TYPE,
-    ED25519_TYPE
+    ED25519_TYPE,
+    PKCS12_TYPE,
+    PKCS8_PRIVATEKEY_TYPE,
+    PKCS8_ENC_PRIVATEKEY_TYPE
 };
 
@@ -80,5 +86,5 @@
     CTC_SHAwECDSA    = 520,
     CTC_SHA224wRSA   = 658,
-    CTC_SHA224wECDSA = 527,
+    CTC_SHA224wECDSA = 523,
     CTC_SHA256wRSA   = 655,
     CTC_SHA256wECDSA = 524,
@@ -95,9 +101,16 @@
 };
 
+#ifndef WC_CTC_NAME_SIZE
+    #define WC_CTC_NAME_SIZE 64
+#endif
+#ifndef WC_CTC_MAX_ALT_SIZE
+    #define WC_CTC_MAX_ALT_SIZE 16384
+#endif
+
 enum Ctc_Misc {
     CTC_COUNTRY_SIZE  =     2,
-    CTC_NAME_SIZE     =    64,
+    CTC_NAME_SIZE     = WC_CTC_NAME_SIZE,
     CTC_DATE_SIZE     =    32,
-    CTC_MAX_ALT_SIZE  = 16384,   /* may be huge */
+    CTC_MAX_ALT_SIZE  = WC_CTC_MAX_ALT_SIZE, /* may be huge, default: 16384 */
     CTC_SERIAL_SIZE   =    16,
 #ifdef WOLFSSL_CERT_EXT
@@ -111,6 +124,71 @@
 };
 
+/* DER buffer */
+typedef struct DerBuffer {
+    byte*  buffer;
+    void*  heap;
+    word32 length;
+    int    type;    /* enum CertType */
+    int    dynType; /* DYNAMIC_TYPE_* */
+} DerBuffer;
+
+enum {
+    IV_SZ   = 32,                   /* max iv sz */
+    NAME_SZ = 80,                   /* max one line */
+
+    PEM_PASS_READ  = 0,
+    PEM_PASS_WRITE = 1,
+};
+
+
+typedef int (pem_password_cb)(char* passwd, int sz, int rw, void* userdata);
+
+typedef struct EncryptedInfo {
+    pem_password_cb* passwd_cb;
+    void*            passwd_userdata;
+
+    long     consumed;         /* tracks PEM bytes consumed */
+
+    int      cipherType;
+    word32   keySz;
+    word32   ivSz;             /* salt or encrypted IV size */
+
+    char     name[NAME_SZ];    /* cipher name, such as "DES-CBC" */
+    byte     iv[IV_SZ];        /* salt or encrypted IV */
+
+    word16   set:1;            /* if encryption set */
+} EncryptedInfo;
+
+
+#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT)
+#ifdef WOLFSSL_EKU_OID
+    #ifndef CTC_MAX_EKU_NB
+        #define CTC_MAX_EKU_NB 1
+    #endif
+    #ifndef CTC_MAX_EKU_OID_SZ
+        #define CTC_MAX_EKU_OID_SZ 30
+    #endif
+#else
+    #undef CTC_MAX_EKU_OID_SZ
+    #define CTC_MAX_EKU_OID_SZ 0
+#endif
+#endif /* WOLFSSL_CERT_GEN || WOLFSSL_CERT_EXT */
 
 #ifdef WOLFSSL_CERT_GEN
+
+#ifdef WOLFSSL_MULTI_ATTRIB
+#ifndef CTC_MAX_ATTRIB
+    #define CTC_MAX_ATTRIB 4
+#endif
+
+/* ASN Encoded Name field */
+typedef struct NameAttrib {
+    int  sz;                     /* actual string value length */
+    int  id;                     /* id of name */
+    int  type;                   /* enc of name */
+    char value[CTC_NAME_SIZE];   /* name */
+} NameAttrib;
+#endif /* WOLFSSL_MULTI_ATTRIB */
+
 
 typedef struct CertName {
@@ -129,5 +207,18 @@
     char commonName[CTC_NAME_SIZE];
     char commonNameEnc;
+    char serialDev[CTC_NAME_SIZE];
+    char serialDevEnc;
+#ifdef WOLFSSL_CERT_EXT
+    char busCat[CTC_NAME_SIZE];
+    char busCatEnc;
+    char joiC[CTC_NAME_SIZE];
+    char joiCEnc;
+    char joiSt[CTC_NAME_SIZE];
+    char joiStEnc;
+#endif
     char email[CTC_NAME_SIZE];  /* !!!! email has to be last !!!! */
+#ifdef WOLFSSL_MULTI_ATTRIB
+    NameAttrib name[CTC_MAX_ATTRIB];
+#endif
 } CertName;
 
@@ -162,6 +253,13 @@
     word16  keyUsage;                    /* Key Usage */
     byte    extKeyUsage;                 /* Extended Key Usage */
+#ifdef WOLFSSL_EKU_OID
+    /* Extended Key Usage OIDs */
+    byte    extKeyUsageOID[CTC_MAX_EKU_NB][CTC_MAX_EKU_OID_SZ];
+    byte    extKeyUsageOIDSz[CTC_MAX_EKU_NB];
+#endif
     char    certPolicies[CTC_MAX_CERTPOL_NB][CTC_MAX_CERTPOL_SZ];
     word16  certPoliciesNb;              /* Number of Cert Policy */
+    byte     issRaw[sizeof(CertName)];   /* raw issuer info */
+    byte     sbjRaw[sizeof(CertName)];   /* raw subject info */
 #endif
 #ifdef WOLFSSL_CERT_REQ
@@ -170,4 +268,5 @@
     void*   heap; /* heap hint */
 } Cert;
+
 
 
@@ -211,4 +310,9 @@
 WOLFSSL_API int  wc_SetDatesBuffer(Cert*, const byte*, int);
 
+#ifndef NO_ASN_TIME
+WOLFSSL_API int wc_GetCertDates(Cert* cert, struct tm* before, 
+    struct tm* after);
+#endif
+
 #ifdef WOLFSSL_CERT_EXT
 WOLFSSL_API int wc_SetAuthKeyIdFromPublicKey_ex(Cert *cert, int keyType,
@@ -223,4 +327,7 @@
                                                 ecc_key *eckey);
 WOLFSSL_API int wc_SetSubjectKeyId(Cert *cert, const char* file);
+WOLFSSL_API int wc_GetSubjectRaw(byte **subjectRaw, Cert *cert);
+WOLFSSL_API int wc_SetSubjectRaw(Cert* cert, const byte* der, int derSz);
+WOLFSSL_API int wc_SetIssuerRaw(Cert* cert, const byte* der, int derSz);
 
 #ifdef HAVE_NTRU
@@ -244,4 +351,12 @@
 WOLFSSL_API int wc_SetExtKeyUsage(Cert *cert, const char *value);
 
+
+#ifdef WOLFSSL_EKU_OID
+/* Set ExtendedKeyUsage with unique OID
+ * oid is expected to be in byte representation
+ */
+WOLFSSL_API int wc_SetExtKeyUsageOID(Cert *cert, const char *oid, word32 sz,
+                                     byte idx, void* heap);
+#endif /* WOLFSSL_EKU_OID */
 #endif /* WOLFSSL_CERT_EXT */
 
@@ -254,25 +369,58 @@
 #endif /* WOLFSSL_CERT_GEN */
 
+WOLFSSL_API int wc_GetDateInfo(const byte* certDate, int certDateSz, 
+    const byte** date, byte* format, int* length);
+#ifndef NO_ASN_TIME
+WOLFSSL_API int wc_GetDateAsCalendarTime(const byte* date, int length,
+    byte format, struct tm* time);
+#endif
+
+#if defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM)
+
+    WOLFSSL_API int wc_PemGetHeaderFooter(int type, const char** header, 
+        const char** footer);
+
+#endif
+
+WOLFSSL_API  int wc_AllocDer(DerBuffer** pDer, word32 length, int type, void* heap);
+WOLFSSL_API void wc_FreeDer(DerBuffer** pDer);
+
+#ifdef WOLFSSL_PEM_TO_DER
+    WOLFSSL_API int wc_PemToDer(const unsigned char* buff, long longSz, int type,
+              DerBuffer** pDer, void* heap, EncryptedInfo* info, int* eccKey);
+
+    WOLFSSL_API int wc_KeyPemToDer(const unsigned char*, int,
+                                   unsigned char*, int, const char*);
+    WOLFSSL_API int wc_CertPemToDer(const unsigned char*, int,
+                                    unsigned char*, int, int);
+#endif /* WOLFSSL_PEM_TO_DER */
+
 #if defined(WOLFSSL_CERT_EXT) || defined(WOLFSSL_PUB_PEM_TO_DER)
-    #ifndef WOLFSSL_PEMPUBKEY_TODER_DEFINED
         #ifndef NO_FILESYSTEM
-        /* forward from wolfssl */
-        WOLFSSL_API int wolfSSL_PemPubKeyToDer(const char* fileName,
+        WOLFSSL_API int wc_PemPubKeyToDer(const char* fileName,
                                                unsigned char* derBuf, int derSz);
         #endif
 
-        /* forward from wolfssl */
-        WOLFSSL_API int wolfSSL_PubKeyPemToDer(const unsigned char*, int,
+    WOLFSSL_API int wc_PubKeyPemToDer(const unsigned char*, int,
                                                unsigned char*, int);
-        #define WOLFSSL_PEMPUBKEY_TODER_DEFINED
-    #endif /* WOLFSSL_PEMPUBKEY_TODER_DEFINED */
 #endif /* WOLFSSL_CERT_EXT || WOLFSSL_PUB_PEM_TO_DER */
 
-#if defined(WOLFSSL_KEY_GEN) || defined(WOLFSSL_CERT_GEN) || !defined(NO_DSA) \
-                             || defined(OPENSSL_EXTRA)
+#ifdef WOLFSSL_CERT_GEN
+    #ifndef NO_FILESYSTEM
+        WOLFSSL_API int wc_PemCertToDer(const char* fileName,
+                                        unsigned char* derBuf, int derSz);
+    #endif
+#endif /* WOLFSSL_CERT_GEN */
+
+#ifdef WOLFSSL_DER_TO_PEM
     WOLFSSL_API int wc_DerToPem(const byte* der, word32 derSz, byte* output,
                                 word32 outputSz, int type);
     WOLFSSL_API int wc_DerToPemEx(const byte* der, word32 derSz, byte* output,
                                 word32 outputSz, byte *cipherIno, int type);
+#endif
+
+#if !defined(NO_RSA) && !defined(HAVE_USER_RSA)
+    WOLFSSL_API int wc_RsaPublicKeyDecode_ex(const byte* input, word32* inOutIdx,
+        word32 inSz, const byte** n, word32* nSz, const byte** e, word32* eSz);
 #endif
 
@@ -284,13 +432,13 @@
     WOLFSSL_API int wc_EccPrivateKeyToDer(ecc_key* key, byte* output,
                                           word32 inLen);
+    WOLFSSL_API int wc_EccPrivateKeyToPKCS8(ecc_key* key, byte* output,
+                                            word32* outLen);
 
     /* public key helper */
     WOLFSSL_API int wc_EccPublicKeyDecode(const byte*, word32*,
                                               ecc_key*, word32);
-    #if (defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_GEN))
         WOLFSSL_API int wc_EccPublicKeyToDer(ecc_key*, byte* output,
                                                word32 inLen, int with_AlgCurve);
     #endif
-#endif
 
 #ifdef HAVE_ED25519
@@ -322,4 +470,5 @@
        byte* key, word32 keySz, int algoID, const byte* curveOID, word32 oidSz);
 
+#ifndef NO_ASN_TIME
 /* Time */
 /* Returns seconds (Epoch/UTC)
@@ -330,4 +479,33 @@
 */
 WOLFSSL_API int wc_GetTime(void* timePtr, word32 timeSize);
+#endif
+
+#ifdef WOLFSSL_ENCRYPTED_KEYS
+    WOLFSSL_API int wc_EncryptedInfoGet(EncryptedInfo* info,
+        const char* cipherInfo);
+#endif
+
+
+#ifdef WOLFSSL_CERT_PIV
+
+typedef struct _wc_CertPIV {
+    const byte*  cert;
+    word32       certSz;
+    const byte*  certErrDet;
+    word32       certErrDetSz;
+    const byte*  nonce;         /* Identiv Only */
+    word32       nonceSz;       /* Identiv Only */
+    const byte*  signedNonce;   /* Identiv Only */
+    word32       signedNonceSz; /* Identiv Only */
+
+    /* flags */
+    word16       compression:2;
+    word16       isX509:1;
+    word16       isIdentiv:1;
+} wc_CertPIV;
+
+WOLFSSL_API int wc_ParseCertPIV(wc_CertPIV* cert, const byte* buf, word32 totalSz);
+#endif /* WOLFSSL_CERT_PIV */
+
 
 #ifdef __cplusplus
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/chacha.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/chacha.h	(revision 372)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/chacha.h	(revision 372)
@@ -0,0 +1,82 @@
+/* chacha.h
+ *
+ * Copyright (C) 2006-2017 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
+/*!
+    \file wolfssl/wolfcrypt/chacha.h
+*/
+
+
+#ifndef WOLF_CRYPT_CHACHA_H
+#define WOLF_CRYPT_CHACHA_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifdef HAVE_CHACHA
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+/* Size of the IV */
+#define CHACHA_IV_WORDS    3
+#define CHACHA_IV_BYTES    (CHACHA_IV_WORDS * sizeof(word32))
+
+/* Size of ChaCha chunks */
+#define CHACHA_CHUNK_WORDS 16
+#define CHACHA_CHUNK_BYTES (CHACHA_CHUNK_WORDS * sizeof(word32))
+
+#ifdef WOLFSSL_X86_64_BUILD
+#if defined(USE_INTEL_SPEEDUP) && !defined(NO_CHACHA_ASM)
+    #define USE_INTEL_CHACHA_SPEEDUP
+    #define HAVE_INTEL_AVX1
+#endif
+#endif
+
+enum {
+	CHACHA_ENC_TYPE = WC_CIPHER_CHACHA,    /* cipher unique type */
+    CHACHA_MAX_KEY_SZ = 32,
+};
+
+typedef struct ChaCha {
+    word32 X[CHACHA_CHUNK_WORDS];           /* state of cipher */
+#ifdef HAVE_INTEL_AVX1
+    /* vpshufd reads 16 bytes but we only use bottom 4. */
+    byte extra[12];
+#endif
+} ChaCha;
+
+/**
+  * IV(nonce) changes with each record
+  * counter is for what value the block counter should start ... usually 0
+  */
+WOLFSSL_API int wc_Chacha_SetIV(ChaCha* ctx, const byte* inIv, word32 counter);
+
+WOLFSSL_API int wc_Chacha_Process(ChaCha* ctx, byte* cipher, const byte* plain,
+                              word32 msglen);
+WOLFSSL_API int wc_Chacha_SetKey(ChaCha* ctx, const byte* key, word32 keySz);
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* HAVE_CHACHA */
+#endif /* WOLF_CRYPT_CHACHA_H */
+
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/coding.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/coding.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/coding.h	(revision 372)
@@ -20,5 +20,7 @@
  */
 
-
+/*!
+    \file wolfssl/wolfcrypt/coding.h
+*/
 
 #ifndef WOLF_CRYPT_CODING_H
@@ -62,6 +64,14 @@
 #endif
 
-#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) || defined(HAVE_FIPS) \
-                           || defined(HAVE_ECC_CDH)
+#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \
+    defined(HAVE_WEBSERVER) || defined(HAVE_FIPS) || \
+    defined(HAVE_ECC_CDH) || defined(HAVE_SELFTEST) || \
+    defined(WOLFSSL_ENCRYPTED_KEYS)
+    #ifndef WOLFSSL_BASE16
+        #define WOLFSSL_BASE16
+    #endif
+#endif
+
+#ifdef WOLFSSL_BASE16
     WOLFSSL_API
     int Base16_Decode(const byte* in, word32 inLen, byte* out, word32* outLen);
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/curve25519.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/curve25519.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/curve25519.h	(revision 372)
@@ -19,4 +19,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
  */
+
+/*!
+    \file wolfssl/wolfcrypt/curve25519.h
+*/
 
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/des3.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/des3.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/des3.h	(revision 372)
@@ -20,4 +20,7 @@
  */
 
+/*!
+    \file wolfssl/wolfcrypt/des3.h
+*/
 
 #ifndef WOLF_CRYPT_DES3_H
@@ -28,5 +31,11 @@
 #ifndef NO_DES3
 
-#ifdef HAVE_FIPS
+#if defined(HAVE_FIPS) && \
+    defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+    #include <wolfssl/wolfcrypt/fips.h>
+#endif /* HAVE_FIPS_VERSION >= 2 */
+
+#if defined(HAVE_FIPS) && \
+	(!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))
 /* included for fips @wc_fips */
 #include <cyassl/ctaocrypt/des3.h>
@@ -37,5 +46,15 @@
 #endif
 
-#ifndef HAVE_FIPS /* to avoid redefinition of macros */
+/* these are required for FIPS and non-FIPS */
+enum {
+    DES_KEY_SIZE        =  8,  /* des                     */
+    DES3_KEY_SIZE       = 24,  /* 3 des ede               */
+    DES_IV_SIZE         =  8,  /* should be the same as DES_BLOCK_SIZE */
+};
+
+
+/* avoid redefinition of structs */
+#if !defined(HAVE_FIPS) || \
+    (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))
 
 #ifdef WOLFSSL_ASYNC_CRYPT
@@ -44,8 +63,9 @@
 
 enum {
-    DES_ENC_TYPE    = 2,     /* cipher unique type */
-    DES3_ENC_TYPE   = 3,     /* cipher unique type */
+    DES_ENC_TYPE    = WC_CIPHER_DES,     /* cipher unique type */
+    DES3_ENC_TYPE   = WC_CIPHER_DES3,    /* cipher unique type */
+
     DES_BLOCK_SIZE  = 8,
-    DES_KS_SIZE     = 32,
+    DES_KS_SIZE     = 32,    /* internal DES key buffer size */
 
     DES_ENCRYPTION  = 0,
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/dh.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/dh.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/dh.h	(revision 372)
@@ -20,4 +20,7 @@
  */
 
+/*!
+    \file wolfssl/wolfcrypt/dh.h
+*/
 
 #ifndef WOLF_CRYPT_DH_H
@@ -27,4 +30,9 @@
 
 #ifndef NO_DH
+
+#if defined(HAVE_FIPS) && \
+    defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+    #include <wolfssl/wolfcrypt/fips.h>
+#endif /* HAVE_FIPS_VERSION >= 2 */
 
 #include <wolfssl/wolfcrypt/integer.h>
@@ -39,4 +47,8 @@
 #endif
 typedef struct DhParams {
+    #ifdef HAVE_FFDHE_Q
+    const byte* q;
+    word32      q_len;
+    #endif /* HAVE_FFDHE_Q */
     const byte* p;
     word32      p_len;
@@ -47,5 +59,5 @@
 /* Diffie-Hellman Key */
 typedef struct DhKey {
-    mp_int p, g;                            /* group parameters  */
+    mp_int p, g, q;                         /* group parameters  */
     void* heap;
 #ifdef WOLFSSL_ASYNC_CRYPT
@@ -73,5 +85,5 @@
 WOLFSSL_API int wc_InitDhKey(DhKey* key);
 WOLFSSL_API int wc_InitDhKey_ex(DhKey* key, void* heap, int devId);
-WOLFSSL_API void wc_FreeDhKey(DhKey* key);
+WOLFSSL_API int wc_FreeDhKey(DhKey* key);
 
 WOLFSSL_API int wc_DhGenerateKeyPair(DhKey* key, WC_RNG* rng, byte* priv,
@@ -85,7 +97,23 @@
 WOLFSSL_API int wc_DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g,
                         word32 gSz);
+WOLFSSL_API int wc_DhSetKey_ex(DhKey* key, const byte* p, word32 pSz,
+                        const byte* g, word32 gSz, const byte* q, word32 qSz);
+WOLFSSL_API int wc_DhSetCheckKey(DhKey* key, const byte* p, word32 pSz,
+                        const byte* g, word32 gSz, const byte* q, word32 qSz,
+                        int trusted, WC_RNG* rng);
 WOLFSSL_API int wc_DhParamsLoad(const byte* input, word32 inSz, byte* p,
                             word32* pInOutSz, byte* g, word32* gInOutSz);
 WOLFSSL_API int wc_DhCheckPubKey(DhKey* key, const byte* pub, word32 pubSz);
+WOLFSSL_API int wc_DhCheckPubKey_ex(DhKey* key, const byte* pub, word32 pubSz,
+                            const byte* prime, word32 primeSz);
+WOLFSSL_API int wc_DhCheckPrivKey(DhKey* key, const byte* priv, word32 pubSz);
+WOLFSSL_API int wc_DhCheckPrivKey_ex(DhKey* key, const byte* priv, word32 pubSz,
+                            const byte* prime, word32 primeSz);
+WOLFSSL_API int wc_DhCheckKeyPair(DhKey* key, const byte* pub, word32 pubSz,
+                        const byte* priv, word32 privSz);
+WOLFSSL_API int wc_DhGenerateParams(WC_RNG *rng, int modSz, DhKey *dh);
+WOLFSSL_API int wc_DhExportParamsRaw(DhKey* dh, byte* p, word32* pSz,
+                       byte* q, word32* qSz, byte* g, word32* gSz);
+
 
 #ifdef __cplusplus
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/dsa.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/dsa.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/dsa.h	(revision 372)
@@ -20,4 +20,7 @@
  */
 
+/*!
+    \file wolfssl/wolfcrypt/dsa.h
+*/
 
 #ifndef WOLF_CRYPT_DSA_H
@@ -75,4 +78,15 @@
 #endif
 
+/* raw export functions */
+WOLFSSL_API int wc_DsaImportParamsRaw(DsaKey* dsa, const char* p,
+                                      const char* q, const char* g);
+WOLFSSL_API int wc_DsaImportParamsRawCheck(DsaKey* dsa, const char* p,
+                                      const char* q, const char* g,
+                                      int trusted, WC_RNG* rng);
+WOLFSSL_API int wc_DsaExportParamsRaw(DsaKey* dsa, byte* p, word32* pSz,
+                                      byte* q, word32* qSz, byte* g,
+                                      word32* gSz);
+WOLFSSL_API int wc_DsaExportKeyRaw(DsaKey* dsa, byte* x, word32* xSz, byte* y,
+                                   word32* ySz);
 #ifdef __cplusplus
     } /* extern "C" */
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/ecc.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/ecc.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/ecc.h	(revision 372)
@@ -20,4 +20,8 @@
  */
 
+/*!
+    \file wolfssl/wolfcrypt/ecc.h
+*/
+
 
 #ifndef WOLF_CRYPT_ECC_H
@@ -27,4 +31,8 @@
 
 #ifdef HAVE_ECC
+
+#if defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+    #include <wolfssl/wolfcrypt/fips.h>
+#endif /* HAVE_FIPS_VERSION >= 2 */
 
 #include <wolfssl/wolfcrypt/integer.h>
@@ -73,10 +81,10 @@
 #elif defined(HAVE_ECC320)
     #define MAX_ECC_BITS    320
+#elif !defined(NO_ECC256)
+    #define MAX_ECC_BITS    256
 #elif defined(HAVE_ECC239)
     #define MAX_ECC_BITS    239
 #elif defined(HAVE_ECC224)
     #define MAX_ECC_BITS    224
-#elif !defined(NO_ECC256)
-    #define MAX_ECC_BITS    256
 #elif defined(HAVE_ECC192)
     #define MAX_ECC_BITS    192
@@ -110,5 +118,25 @@
     ECC_MAX_PAD_SZ  = 4,    /* ECC maximum padding size */
     ECC_MAX_OID_LEN = 16,
-    ECC_MAX_SIG_SIZE= ((MAX_ECC_BYTES * 2) + ECC_MAX_PAD_SZ + SIG_HEADER_SZ)
+    ECC_MAX_SIG_SIZE= ((MAX_ECC_BYTES * 2) + ECC_MAX_PAD_SZ + SIG_HEADER_SZ),
+
+    /* max crypto hardware size */
+#ifdef WOLFSSL_ATECC508A
+    ECC_MAX_CRYPTO_HW_SIZE = ATECC_KEY_SIZE, /* from port/atmel/atmel.h */
+    ECC_MAX_CRYPTO_HW_PUBKEY_SIZE = (ATECC_KEY_SIZE*2),
+#elif defined(PLUTON_CRYPTO_ECC)
+    ECC_MAX_CRYPTO_HW_SIZE = 32,
+#endif
+
+    /* point compression type */
+    ECC_POINT_COMP_EVEN = 0x02,
+    ECC_POINT_COMP_ODD = 0x03,
+    ECC_POINT_UNCOMP = 0x04,
+
+    /* Shamir's dual add constants */
+    SHAMIR_PRECOMP_SZ = 16,
+
+#ifdef HAVE_PKCS11
+    ECC_MAX_ID_LEN    = 32,
+#endif
 };
 
@@ -176,4 +204,5 @@
 
 /* ECC set type defined a GF(p) curve */
+#ifndef USE_WINDOWS_API
 typedef struct ecc_set_type {
     int size;             /* The size of the curve in octets */
@@ -191,4 +220,29 @@
     int         cofactor;
 } ecc_set_type;
+#else
+/* MSC does something different with the pointers to the arrays than GCC,
+ * and it causes the FIPS checksum to fail. In the case of windows builds,
+ * store everything as arrays instead of pointers to strings. */
+
+#define MAX_ECC_NAME 16
+#define MAX_ECC_STRING ((MAX_ECC_BYTES * 2) + 1)
+    /* The values are stored as text strings. */
+
+typedef struct ecc_set_type {
+    int size;             /* The size of the curve in octets */
+    int id;               /* id of this curve */
+    const char name[MAX_ECC_NAME];     /* name of this curve */
+    const char prime[MAX_ECC_STRING];    /* prime that defines the field, curve is in (hex) */
+    const char Af[MAX_ECC_STRING];       /* fields A param (hex) */
+    const char Bf[MAX_ECC_STRING];       /* fields B param (hex) */
+    const char order[MAX_ECC_STRING];    /* order of the curve (hex) */
+    const char Gx[MAX_ECC_STRING];       /* x coordinate of the base point on curve (hex) */
+    const char Gy[MAX_ECC_STRING];       /* y coordinate of the base point on curve (hex) */
+    const ecc_oid_t oid[10];
+    word32      oidSz;
+    word32      oidSum;    /* sum of encoded OID bytes */
+    int         cofactor;
+} ecc_set_type;
+#endif
 
 
@@ -247,7 +301,12 @@
 typedef struct alt_fp_int {
     int used, sign, size;
-    fp_digit dp[FP_SIZE_ECC];
+    mp_digit dp[FP_SIZE_ECC];
 } alt_fp_int;
 #endif /* ALT_ECC_SIZE */
+
+#ifndef WC_ECCKEY_TYPE_DEFINED
+    typedef struct ecc_key ecc_key;
+    #define WC_ECCKEY_TYPE_DEFINED
+#endif
 
 
@@ -265,4 +324,7 @@
     alt_fp_int xyz[3];
 #endif
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+    ecc_key* key;
+#endif
 } ecc_point;
 
@@ -285,11 +347,16 @@
     const ecc_set_type* dp;     /* domain parameters, either points to NIST
                                    curves (idx >= 0) or user supplied */
+#ifdef WOLFSSL_CUSTOM_CURVES
+    int deallocSet;
+#endif
     void* heap;         /* heap hint */
+    ecc_point pubkey;   /* public key */
+    mp_int    k;        /* private key */
 #ifdef WOLFSSL_ATECC508A
     int  slot;        /* Key Slot Number (-1 unknown) */
-    byte pubkey[PUB_KEY_SIZE];
-#else
-    ecc_point pubkey;   /* public key */
-    mp_int    k;        /* private key */
+    byte pubkey_raw[ECC_MAX_CRYPTO_HW_PUBKEY_SIZE];
+#endif
+#if defined(PLUTON_CRYPTO_ECC) || defined(WOLF_CRYPTO_DEV)
+    int devId;
 #endif
 #ifdef WOLFSSL_ASYNC_CRYPT
@@ -297,14 +364,26 @@
     mp_int* s;
     WC_ASYNC_DEV asyncDev;
+    #ifdef HAVE_CAVIUM_V
+        mp_int* e;      /* Sign, Verify and Shared Secret */
+        mp_int* signK;
+    #endif
     #ifdef WOLFSSL_CERT_GEN
         CertSignCtx certSignCtx; /* context info for cert sign (MakeSignature) */
     #endif
 #endif /* WOLFSSL_ASYNC_CRYPT */
-};
-
-#ifndef WC_ECCKEY_TYPE_DEFINED
-    typedef struct ecc_key ecc_key;
-    #define WC_ECCKEY_TYPE_DEFINED
-#endif
+#ifdef HAVE_PKCS11
+    byte id[ECC_MAX_ID_LEN];
+    int  idLen;
+#endif
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+    mp_int* t1;
+    mp_int* t2;
+#ifdef ALT_ECC_SIZE
+    mp_int* x;
+    mp_int* y;
+    mp_int* z;
+#endif
+#endif
+};
 
 
@@ -322,4 +401,8 @@
     #define ECC_API    WOLFSSL_LOCAL
 #endif
+
+ECC_API int ecc_mul2add(ecc_point* A, mp_int* kA,
+                ecc_point* B, mp_int* kB,
+                ecc_point* C, mp_int* a, mp_int* modulus, void* heap);
 
 ECC_API int ecc_map(ecc_point*, mp_int*, mp_digit);
@@ -378,6 +461,15 @@
 WOLFSSL_API
 int wc_ecc_init_ex(ecc_key* key, void* heap, int devId);
-WOLFSSL_API
-void wc_ecc_free(ecc_key* key);
+#ifdef HAVE_PKCS11
+WOLFSSL_API
+int wc_ecc_init_id(ecc_key* key, unsigned char* id, int len, void* heap,
+                   int devId);
+#endif
+#ifdef WOLFSSL_CUSTOM_CURVES
+WOLFSSL_LOCAL
+void wc_ecc_free_curve(const ecc_set_type* curve, void* heap);
+#endif
+WOLFSSL_API
+int wc_ecc_free(ecc_key* key);
 WOLFSSL_API
 int wc_ecc_set_flags(ecc_key* key, word32 flags);
@@ -410,20 +502,23 @@
         const byte* Gx, word32 GxSz, const byte* Gy, word32 GySz, int cofactor);
 
+WOLFSSL_API
+int wc_ecc_get_curve_id_from_oid(const byte* oid, word32 len);
+
+WOLFSSL_API
+ecc_point* wc_ecc_new_point(void);
+WOLFSSL_API
+ecc_point* wc_ecc_new_point_h(void* h);
+WOLFSSL_API
+void wc_ecc_del_point(ecc_point* p);
+WOLFSSL_API
+void wc_ecc_del_point_h(ecc_point* p, void* h);
+WOLFSSL_API
+int wc_ecc_copy_point(ecc_point* p, ecc_point *r);
+WOLFSSL_API
+int wc_ecc_cmp_point(ecc_point* a, ecc_point *b);
+WOLFSSL_API
+int wc_ecc_point_is_at_infinity(ecc_point *p);
+
 #ifndef WOLFSSL_ATECC508A
-
-WOLFSSL_API
-ecc_point* wc_ecc_new_point(void);
-WOLFSSL_API
-ecc_point* wc_ecc_new_point_h(void* h);
-WOLFSSL_API
-void wc_ecc_del_point(ecc_point* p);
-WOLFSSL_API
-void wc_ecc_del_point_h(ecc_point* p, void* h);
-WOLFSSL_API
-int wc_ecc_copy_point(ecc_point* p, ecc_point *r);
-WOLFSSL_API
-int wc_ecc_cmp_point(ecc_point* a, ecc_point *b);
-WOLFSSL_API
-int wc_ecc_point_is_at_infinity(ecc_point *p);
 WOLFSSL_API
 int wc_ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R,
@@ -459,4 +554,7 @@
 int wc_ecc_rs_to_sig(const char* r, const char* s, byte* out, word32* outlen);
 WOLFSSL_API
+int wc_ecc_rs_raw_to_sig(const byte* r, word32 rSz, const byte* s, word32 sSz,
+    byte* out, word32* outlen);
+WOLFSSL_API
 int wc_ecc_sig_to_rs(const byte* sig, word32 sigLen, byte* r, word32* rLen,
                    byte* s, word32* sLen);
@@ -467,7 +565,14 @@
 int wc_ecc_import_raw_ex(ecc_key* key, const char* qx, const char* qy,
                    const char* d, int curve_id);
+WOLFSSL_API
+int wc_ecc_import_unsigned(ecc_key* key, byte* qx, byte* qy,
+                   byte* d, int curve_id);
 #endif /* HAVE_ECC_KEY_IMPORT */
 
 #ifdef HAVE_ECC_KEY_EXPORT
+WOLFSSL_API
+int wc_ecc_export_ex(ecc_key* key, byte* qx, word32* qxLen,
+                     byte* qy, word32* qyLen, byte* d, word32* dLen,
+                     int encType);
 WOLFSSL_API
 int wc_ecc_export_private_only(ecc_key* key, byte* out, word32* outLen);
@@ -497,4 +602,6 @@
 WOLFSSL_API
 int wc_ecc_size(ecc_key* key);
+WOLFSSL_API
+int wc_ecc_sig_size_calc(int sz);
 WOLFSSL_API
 int wc_ecc_sig_size(ecc_key* key);
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/ed25519.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/ed25519.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/ed25519.h	(revision 372)
@@ -19,4 +19,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
  */
+
+/*!
+    \file wolfssl/wolfcrypt/ed25519.h
+*/
 
 
@@ -74,4 +78,5 @@
     byte pointY[ED25519_KEY_SIZE]; /* Y coordinate is the public key with The most significant bit of the final octet always zero. */
 #endif
+    word16 pubKeySet:1;
 #ifdef WOLFSSL_ASYNC_CRYPT
     WC_ASYNC_DEV asyncDev;
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/error-crypt.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/error-crypt.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/error-crypt.h	(revision 372)
@@ -20,5 +20,7 @@
  */
 
-
+/*!
+    \file wolfssl/wolfcrypt/error-crypt.h
+*/
 
 #ifndef WOLF_CRYPT_ERROR_H
@@ -98,4 +100,6 @@
     ASN_NTRU_KEY_E     = -159,  /* ASN ntru key decode error, invalid input */
     ASN_CRIT_EXT_E     = -160,  /* ASN unsupported critical extension */
+    ASN_ALT_NAME_E     = -161,  /* ASN alternate name error */
+    ASN_NO_PEM_HEADER  = -162,  /* ASN no PEM header found */
 
     ECC_BAD_ARG_E      = -170,  /* ECC input argument of wrong type */
@@ -192,6 +196,33 @@
     ECC_PRIVATEONLY_E   = -246,  /* Invalid use of private only ECC key*/
     EXTKEYUSAGE_E       = -247,  /* Bad Extended Key Usage value */
-
-    WC_LAST_E           = -247,  /* Update this to indicate last error */
+    WC_HW_E             = -248,  /* Error with hardware crypto use */
+    WC_HW_WAIT_E        = -249,  /* Hardware waiting on resource */
+
+    PSS_SALTLEN_E       = -250,  /* PSS length of salt is to long for hash */
+    PRIME_GEN_E         = -251,  /* Failure finding a prime. */
+    BER_INDEF_E         = -252,  /* Cannot decode indefinite length BER. */
+    RSA_OUT_OF_RANGE_E  = -253,  /* Ciphertext to decrypt out of range. */
+    RSAPSS_PAT_FIPS_E   = -254,  /* RSA-PSS PAT failure */
+    ECDSA_PAT_FIPS_E    = -255,  /* ECDSA PAT failure */
+    DH_KAT_FIPS_E       = -256,  /* DH KAT failure */
+    AESCCM_KAT_FIPS_E   = -257,  /* AESCCM KAT failure */
+    SHA3_KAT_FIPS_E     = -258,  /* SHA-3 KAT failure */
+    ECDHE_KAT_FIPS_E    = -259,  /* ECDHE KAT failure */
+    AES_GCM_OVERFLOW_E  = -260,  /* AES-GCM invocation counter overflow. */
+    AES_CCM_OVERFLOW_E  = -261,  /* AES-CCM invocation counter overflow. */
+    RSA_KEY_PAIR_E      = -262,  /* RSA Key Pair-Wise Consistency check fail. */
+    DH_CHECK_PRIV_E     = -263,  /* DH Check Priv Key error */
+
+    WC_AFALG_SOCK_E     = -264,  /* AF_ALG socket error */
+    WC_DEVCRYPTO_E      = -265,  /* /dev/crypto error */
+
+    ZLIB_INIT_ERROR     = -266,   /* zlib init error  */
+    ZLIB_COMPRESS_ERROR = -267,   /* zlib compression error  */
+    ZLIB_DECOMPRESS_ERROR = -268,  /* zlib decompression error  */
+
+    PKCS7_NO_SIGNER_E   = -269,  /* No signer in PKCS#7 signed data msg */
+    WC_PKCS7_WANT_READ_E= -270,  /* PKCS7 operations wants more input */
+
+    WC_LAST_E           = -270,  /* Update this to indicate last error */
     MIN_CODE_E          = -300   /* errors -101 - -299 */
 
@@ -201,7 +232,14 @@
 
 
+#ifdef NO_ERROR_STRINGS
+    #define wc_GetErrorString(error) "no support for error strings built in"
+    #define wc_ErrorString(err, buf) \
+        (void)err; XSTRNCPY((buf), wc_GetErrorString((err)), \
+        WOLFSSL_MAX_ERROR_SZ);
+
+#else
 WOLFSSL_API void wc_ErrorString(int err, char* buff);
 WOLFSSL_API const char* wc_GetErrorString(int error);
-
+#endif
 
 #ifdef __cplusplus
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/hash.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/hash.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/hash.h	(revision 372)
@@ -20,4 +20,7 @@
  */
 
+/*!
+    \file wolfssl/wolfcrypt/hash.h
+*/
 
 #ifndef WOLF_CRYPT_HASH_H
@@ -38,4 +41,17 @@
     #include <wolfssl/wolfcrypt/sha512.h>
 #endif
+#ifdef HAVE_BLAKE2
+    #include <wolfssl/wolfcrypt/blake2.h>
+#endif
+#ifdef WOLFSSL_SHA3
+    #include <wolfssl/wolfcrypt/sha3.h>
+#endif
+#ifndef NO_MD4
+    #include <wolfssl/wolfcrypt/md4.h>
+#endif
+#ifdef WOLFSSL_MD2
+    #include <wolfssl/wolfcrypt/md2.h>
+#endif
+
 
 #ifdef __cplusplus
@@ -43,17 +59,8 @@
 #endif
 
-/* Hash types */
-enum wc_HashType {
-    WC_HASH_TYPE_NONE = 0,
-    WC_HASH_TYPE_MD2 = 1,
-    WC_HASH_TYPE_MD4 = 2,
-    WC_HASH_TYPE_MD5 = 3,
-    WC_HASH_TYPE_SHA = 4, /* SHA-1 (not old SHA-0) */
-    WC_HASH_TYPE_SHA224 = 9,
-    WC_HASH_TYPE_SHA256 = 5,
-    WC_HASH_TYPE_SHA384 = 6,
-    WC_HASH_TYPE_SHA512 = 7,
-    WC_HASH_TYPE_MD5_SHA = 8,
-};
+#if !defined(HAVE_FIPS) && !defined(NO_OLD_WC_NAMES)
+    #define MAX_DIGEST_SIZE WC_MAX_DIGEST_SIZE
+#endif
+
 
 typedef union {
@@ -80,25 +87,42 @@
 /* Find largest possible digest size
    Note if this gets up to the size of 80 or over check smallstack build */
-#if defined(WOLFSSL_SHA512)
+#if defined(WOLFSSL_SHA3)
+    #define WC_MAX_DIGEST_SIZE WC_SHA3_512_DIGEST_SIZE
+    #define WC_MAX_BLOCK_SIZE  WC_SHA3_224_BLOCK_SIZE /* 224 is the largest block size */
+#elif defined(WOLFSSL_SHA512)
     #define WC_MAX_DIGEST_SIZE WC_SHA512_DIGEST_SIZE
+    #define WC_MAX_BLOCK_SIZE  WC_SHA512_BLOCK_SIZE
+#elif defined(HAVE_BLAKE2)
+    #define WC_MAX_DIGEST_SIZE BLAKE2B_OUTBYTES
+    #define WC_MAX_BLOCK_SIZE  BLAKE2B_BLOCKBYTES
 #elif defined(WOLFSSL_SHA384)
     #define WC_MAX_DIGEST_SIZE WC_SHA384_DIGEST_SIZE
+    #define WC_MAX_BLOCK_SIZE  WC_SHA384_BLOCK_SIZE
 #elif !defined(NO_SHA256)
     #define WC_MAX_DIGEST_SIZE WC_SHA256_DIGEST_SIZE
+    #define WC_MAX_BLOCK_SIZE  WC_SHA256_BLOCK_SIZE
 #elif defined(WOLFSSL_SHA224)
     #define WC_MAX_DIGEST_SIZE WC_SHA224_DIGEST_SIZE
+    #define WC_MAX_BLOCK_SIZE  WC_SHA224_BLOCK_SIZE
 #elif !defined(NO_SHA)
     #define WC_MAX_DIGEST_SIZE WC_SHA_DIGEST_SIZE
+    #define WC_MAX_BLOCK_SIZE  WC_SHA_BLOCK_SIZE
 #elif !defined(NO_MD5)
     #define WC_MAX_DIGEST_SIZE WC_MD5_DIGEST_SIZE
+    #define WC_MAX_BLOCK_SIZE  WC_MD5_BLOCK_SIZE
 #else
     #define WC_MAX_DIGEST_SIZE 64 /* default to max size of 64 */
+    #define WC_MAX_BLOCK_SIZE  128
 #endif
 
 #if !defined(NO_ASN) || !defined(NO_DH) || defined(HAVE_ECC)
 WOLFSSL_API int wc_HashGetOID(enum wc_HashType hash_type);
+WOLFSSL_API enum wc_HashType wc_OidGetHash(int oid);
 #endif
 
+WOLFSSL_API enum wc_HashType wc_HashTypeConvert(int hashType);
+
 WOLFSSL_API int wc_HashGetDigestSize(enum wc_HashType hash_type);
+WOLFSSL_API int wc_HashGetBlockSize(enum wc_HashType hash_type);
 WOLFSSL_API int wc_Hash(enum wc_HashType hash_type,
     const byte* data, word32 data_len,
@@ -111,5 +135,5 @@
 WOLFSSL_API int wc_HashFinal(wc_HashAlg* hash, enum wc_HashType type,
     byte* out);
-
+WOLFSSL_API int wc_HashFree(wc_HashAlg* hash, enum wc_HashType type);
 
 #ifndef NO_MD5
@@ -123,20 +147,22 @@
 #endif
 
+#ifdef WOLFSSL_SHA224
+#include <wolfssl/wolfcrypt/sha256.h>
+        WOLFSSL_API int wc_Sha224Hash(const byte*, word32, byte*);
+    #endif /* defined(WOLFSSL_SHA224) */
+
 #ifndef NO_SHA256
 #include <wolfssl/wolfcrypt/sha256.h>
 WOLFSSL_API int wc_Sha256Hash(const byte*, word32, byte*);
+#endif
 
-    #if defined(WOLFSSL_SHA224)
-        WOLFSSL_API int wc_Sha224Hash(const byte*, word32, byte*);
-    #endif /* defined(WOLFSSL_SHA224) */
-#endif
+#ifdef WOLFSSL_SHA384
+#include <wolfssl/wolfcrypt/sha512.h>
+        WOLFSSL_API int wc_Sha384Hash(const byte*, word32, byte*);
+    #endif /* defined(WOLFSSL_SHA384) */
 
 #ifdef WOLFSSL_SHA512
 #include <wolfssl/wolfcrypt/sha512.h>
 WOLFSSL_API int wc_Sha512Hash(const byte*, word32, byte*);
-
-    #if defined(WOLFSSL_SHA384)
-        WOLFSSL_API int wc_Sha384Hash(const byte*, word32, byte*);
-    #endif /* defined(WOLFSSL_SHA384) */
 #endif /* WOLFSSL_SHA512 */
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/hc128.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/hc128.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/hc128.h	(revision 372)
@@ -20,4 +20,8 @@
  */
 
+/*!
+    \file wolfssl/wolfcrypt/hc128.h
+*/
+
 
 #ifndef WOLF_CRYPT_HC128_H
@@ -33,5 +37,5 @@
 
 enum {
-	HC128_ENC_TYPE    =  6    /* cipher unique type */
+	HC128_ENC_TYPE =  WC_CIPHER_HC128,     /* cipher unique type */
 };
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/hmac.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/hmac.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/hmac.h	(revision 372)
@@ -20,5 +20,7 @@
  */
 
-
+/*!
+    \file wolfssl/wolfcrypt/hmac.h
+*/
 
 #ifndef NO_HMAC
@@ -27,39 +29,33 @@
 #define WOLF_CRYPT_HMAC_H
 
-#include <wolfssl/wolfcrypt/types.h>
+#include <wolfssl/wolfcrypt/hash.h>
 
-#ifndef NO_MD5
-    #include <wolfssl/wolfcrypt/md5.h>
+#if defined(HAVE_FIPS) && \
+	(!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))
+/* for fips @wc_fips */
+    #include <cyassl/ctaocrypt/hmac.h>
+    #define WC_HMAC_BLOCK_SIZE HMAC_BLOCK_SIZE
 #endif
 
-#ifndef NO_SHA
-    #include <wolfssl/wolfcrypt/sha.h>
+
+#if defined(HAVE_FIPS) && \
+	defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+	#include <wolfssl/wolfcrypt/fips.h>
 #endif
-
-#if !defined(NO_SHA256) || defined(WOLFSSL_SHA224)
-    #include <wolfssl/wolfcrypt/sha256.h>
-#endif
-
-#ifdef WOLFSSL_SHA512
-    #include <wolfssl/wolfcrypt/sha512.h>
-#endif
-
-#ifdef HAVE_BLAKE2
-    #include <wolfssl/wolfcrypt/blake2.h>
-#endif
-
-#ifdef HAVE_FIPS
-/* for fips */
-    #include <cyassl/ctaocrypt/hmac.h>
-#endif
-
 
 #ifdef __cplusplus
     extern "C" {
 #endif
-#ifndef HAVE_FIPS
+
+/* avoid redefinition of structs */
+#if !defined(HAVE_FIPS) || \
+    (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))
 
 #ifdef WOLFSSL_ASYNC_CRYPT
     #include <wolfssl/wolfcrypt/async.h>
+#endif
+
+#ifndef NO_OLD_WC_NAMES
+    #define HMAC_BLOCK_SIZE WC_HMAC_BLOCK_SIZE
 #endif
 
@@ -72,52 +68,40 @@
 /* If any hash is not enabled, add the ID here. */
 #ifdef NO_MD5
-    WC_MD5     = 0,
+    WC_MD5     = WC_HASH_TYPE_MD5,
 #endif
 #ifdef NO_SHA
-    WC_SHA     = 1,
+    WC_SHA     = WC_HASH_TYPE_SHA,
 #endif
 #ifdef NO_SHA256
-    WC_SHA256  = 2,
+    WC_SHA256  = WC_HASH_TYPE_SHA256,
 #endif
 #ifndef WOLFSSL_SHA512
-    WC_SHA512  = 4,
+    WC_SHA512  = WC_HASH_TYPE_SHA512,
 #endif
 #ifndef WOLFSSL_SHA384
-    WC_SHA384  = 5,
+    WC_SHA384  = WC_HASH_TYPE_SHA384,
 #endif
 #ifndef HAVE_BLAKE2
-    BLAKE2B_ID = 7,
+    BLAKE2B_ID = WC_HASH_TYPE_BLAKE2B,
 #endif
 #ifndef WOLFSSL_SHA224
-    WC_SHA224  = 8,
+    WC_SHA224  = WC_HASH_TYPE_SHA224,
 #endif
-
+#ifndef WOLFSSL_SHA3
+    WC_SHA3_224 = WC_HASH_TYPE_SHA3_224,
+    WC_SHA3_256 = WC_HASH_TYPE_SHA3_256,
+    WC_SHA3_384 = WC_HASH_TYPE_SHA3_384,
+    WC_SHA3_512 = WC_HASH_TYPE_SHA3_512,
+#endif
+};
 
 /* Select the largest available hash for the buffer size. */
-#if defined(WOLFSSL_SHA512)
-    MAX_DIGEST_SIZE = WC_SHA512_DIGEST_SIZE,
-    HMAC_BLOCK_SIZE = WC_SHA512_BLOCK_SIZE,
-#elif defined(HAVE_BLAKE2)
-    MAX_DIGEST_SIZE = BLAKE2B_OUTBYTES,
-    HMAC_BLOCK_SIZE = BLAKE2B_BLOCKBYTES,
-#elif defined(WOLFSSL_SHA384)
-    MAX_DIGEST_SIZE = WC_SHA384_DIGEST_SIZE,
-    HMAC_BLOCK_SIZE = WC_SHA384_BLOCK_SIZE
-#elif !defined(NO_SHA256)
-    MAX_DIGEST_SIZE = WC_SHA256_DIGEST_SIZE,
-    HMAC_BLOCK_SIZE = WC_SHA256_BLOCK_SIZE
-#elif defined(WOLFSSL_SHA224)
-    MAX_DIGEST_SIZE = WC_SHA224_DIGEST_SIZE,
-    HMAC_BLOCK_SIZE = WC_SHA224_BLOCK_SIZE
-#elif !defined(NO_SHA)
-    MAX_DIGEST_SIZE = WC_SHA_DIGEST_SIZE,
-    HMAC_BLOCK_SIZE = WC_SHA_BLOCK_SIZE,
-#elif !defined(NO_MD5)
-    MAX_DIGEST_SIZE = WC_MD5_DIGEST_SIZE,
-    HMAC_BLOCK_SIZE = WC_MD5_BLOCK_SIZE,
-#else
+#define WC_HMAC_BLOCK_SIZE WC_MAX_BLOCK_SIZE
+
+#if !defined(WOLFSSL_SHA3) && !defined(WOLFSSL_SHA512) && !defined(HAVE_BLAKE2) && \
+    !defined(WOLFSSL_SHA384) && defined(NO_SHA256) && defined(WOLFSSL_SHA224) && \
+     defined(NO_SHA) && defined(NO_MD5)
     #error "You have to have some kind of hash if you want to use HMAC."
 #endif
-};
 
 
@@ -136,12 +120,15 @@
     wc_Sha256 sha256;
 #endif
-#ifdef WOLFSSL_SHA512
 #ifdef WOLFSSL_SHA384
     wc_Sha384 sha384;
 #endif
+#ifdef WOLFSSL_SHA512
     wc_Sha512 sha512;
 #endif
 #ifdef HAVE_BLAKE2
     Blake2b blake2b;
+#endif
+#ifdef WOLFSSL_SHA3
+    wc_Sha3 sha3;
 #endif
 } Hash;
@@ -150,7 +137,7 @@
 typedef struct Hmac {
     Hash    hash;
-    word32  ipad[HMAC_BLOCK_SIZE  / sizeof(word32)];  /* same block size all*/
-    word32  opad[HMAC_BLOCK_SIZE  / sizeof(word32)];
-    word32  innerHash[MAX_DIGEST_SIZE / sizeof(word32)];
+    word32  ipad[WC_HMAC_BLOCK_SIZE  / sizeof(word32)];  /* same block size all*/
+    word32  opad[WC_HMAC_BLOCK_SIZE  / sizeof(word32)];
+    word32  innerHash[WC_MAX_DIGEST_SIZE / sizeof(word32)];
     void*   heap;                 /* heap hint */
     byte    macType;              /* md5 sha or sha256 */
@@ -160,8 +147,4 @@
     WC_ASYNC_DEV asyncDev;
     word16       keyLen;          /* hmac key length (key in ipad) */
-    #ifdef HAVE_CAVIUM
-        byte*    data;            /* buffered input data for one call */
-        word16   dataLen;
-    #endif /* HAVE_CAVIUM */
 #endif /* WOLFSSL_ASYNC_CRYPT */
 } Hmac;
@@ -179,4 +162,6 @@
 
 WOLFSSL_API int wolfSSL_GetHmacMaxSize(void);
+
+WOLFSSL_LOCAL int _InitHmac(Hmac* hmac, int type, void* heap);
 
 #ifdef HAVE_HKDF
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/idea.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/idea.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/idea.h	(revision 372)
@@ -20,4 +20,7 @@
  */
 
+/*!
+    \file wolfssl/wolfcrypt/idea.h
+*/
 
 #ifndef WOLF_CRYPT_IDEA_H
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/integer.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/integer.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/integer.h	(revision 372)
@@ -34,5 +34,7 @@
 */
 #include <wolfssl/wolfcrypt/types.h>       /* will set MP_xxBIT if not default */
-#ifdef USE_FAST_MATH
+#ifdef WOLFSSL_SP_MATH
+    #include <wolfssl/wolfcrypt/sp_int.h>
+#elif defined(USE_FAST_MATH)
     #include <wolfssl/wolfcrypt/tfm.h>
 #else
@@ -68,4 +70,9 @@
 
 /* C++ compilers don't like assigning void * to mp_digit * */
+#define  OPT_CAST(x)  (x *)
+
+#elif defined(_SH3)
+
+/* SuperH SH3 compiler doesn't like assigning voi* to mp_digit* */
 #define  OPT_CAST(x)  (x *)
 
@@ -249,12 +256,21 @@
 #define mp_tomag(mp, str)         mp_to_unsigned_bin((mp), (str))
 
-#define mp_tobinary(M, S)  mp_toradix((M), (S), 2)
-#define mp_tooctal(M, S)   mp_toradix((M), (S), 8)
-#define mp_todecimal(M, S) mp_toradix((M), (S), 10)
-#define mp_tohex(M, S)     mp_toradix((M), (S), 16)
+#define MP_RADIX_BIN  2
+#define MP_RADIX_OCT  8
+#define MP_RADIX_DEC  10
+#define MP_RADIX_HEX  16
+#define MP_RADIX_MAX  64
+
+#define mp_tobinary(M, S)  mp_toradix((M), (S), MP_RADIX_BIN)
+#define mp_tooctal(M, S)   mp_toradix((M), (S), MP_RADIX_OCT)
+#define mp_todecimal(M, S) mp_toradix((M), (S), MP_RADIX_DEC)
+#define mp_tohex(M, S)     mp_toradix((M), (S), MP_RADIX_HEX)
 
 #define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1)
 
+#if defined(HAVE_ECC) || defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) || \
+    defined(WOLFSSL_DEBUG_MATH) || defined(DEBUG_WOLFSSL)
 extern const char *mp_s_rmap;
+#endif
 
 /* 6 functions needed by Rsa */
@@ -267,4 +283,5 @@
 MP_API int  mp_to_unsigned_bin_at_pos(int x, mp_int *t, unsigned char *b);
 MP_API int  mp_to_unsigned_bin (mp_int * a, unsigned char *b);
+MP_API int  mp_to_unsigned_bin_len(mp_int * a, unsigned char *b, int c);
 MP_API int  mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y);
 /* end functions needed by Rsa */
@@ -353,13 +370,17 @@
 #endif
 
-#if defined(HAVE_ECC) || defined(WOLFSSL_KEY_GEN)
+#if defined(HAVE_ECC) || defined(WOLFSSL_KEY_GEN) || !defined(NO_RSA) || \
+    !defined(NO_DSA) || !defined(NO_DH)
     MP_API int mp_sqrmod(mp_int* a, mp_int* b, mp_int* c);
 #endif
-#if defined(HAVE_ECC) || defined(WOLFSSL_KEY_GEN)
+#if !defined(NO_DSA) || defined(HAVE_ECC)
     MP_API int mp_read_radix(mp_int* a, const char* str, int radix);
 #endif
 
+#if defined(WOLFSSL_KEY_GEN) || !defined(NO_RSA) || !defined(NO_DSA) || !defined(NO_DH)
+    MP_API int mp_prime_is_prime (mp_int * a, int t, int *result);
+    MP_API int mp_prime_is_prime_ex (mp_int * a, int t, int *result, WC_RNG*);
+#endif /* WOLFSSL_KEY_GEN NO_RSA NO_DSA NO_DH */
 #ifdef WOLFSSL_KEY_GEN
-    MP_API int mp_prime_is_prime (mp_int * a, int t, int *result);
     MP_API int mp_gcd (mp_int * a, mp_int * b, mp_int * c);
     MP_API int mp_lcm (mp_int * a, mp_int * b, mp_int * c);
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/logging.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/logging.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/logging.h	(revision 372)
@@ -20,4 +20,8 @@
  */
 
+/*!
+    \file wolfssl/wolfcrypt/logging.h
+*/
+
 
 /* submitted by eof */
@@ -34,5 +38,5 @@
 
 
-enum  CYA_Log_Levels {
+enum wc_LogLevels {
     ERROR_LOG = 0,
     INFO_LOG,
@@ -42,8 +46,58 @@
 };
 
+#ifdef WOLFSSL_FUNC_TIME
+/* WARNING: This code is only to be used for debugging performance.
+ *          The code is not thread-safe.
+ *          Do not use WOLFSSL_FUNC_TIME in production code.
+ */
+enum wc_FuncNum {
+    WC_FUNC_HELLO_REQUEST_SEND = 0,
+    WC_FUNC_HELLO_REQUEST_DO,
+    WC_FUNC_CLIENT_HELLO_SEND,
+    WC_FUNC_CLIENT_HELLO_DO,
+    WC_FUNC_SERVER_HELLO_SEND,
+    WC_FUNC_SERVER_HELLO_DO,
+    WC_FUNC_ENCRYPTED_EXTENSIONS_SEND,
+    WC_FUNC_ENCRYPTED_EXTENSIONS_DO,
+    WC_FUNC_CERTIFICATE_REQUEST_SEND,
+    WC_FUNC_CERTIFICATE_REQUEST_DO,
+    WC_FUNC_CERTIFICATE_SEND,
+    WC_FUNC_CERTIFICATE_DO,
+    WC_FUNC_CERTIFICATE_VERIFY_SEND,
+    WC_FUNC_CERTIFICATE_VERIFY_DO,
+    WC_FUNC_FINISHED_SEND,
+    WC_FUNC_FINISHED_DO,
+    WC_FUNC_KEY_UPDATE_SEND,
+    WC_FUNC_KEY_UPDATE_DO,
+    WC_FUNC_EARLY_DATA_SEND,
+    WC_FUNC_EARLY_DATA_DO,
+    WC_FUNC_NEW_SESSION_TICKET_SEND,
+    WC_FUNC_NEW_SESSION_TICKET_DO,
+    WC_FUNC_SERVER_HELLO_DONE_SEND,
+    WC_FUNC_SERVER_HELLO_DONE_DO,
+    WC_FUNC_TICKET_SEND,
+    WC_FUNC_TICKET_DO,
+    WC_FUNC_CLIENT_KEY_EXCHANGE_SEND,
+    WC_FUNC_CLIENT_KEY_EXCHANGE_DO,
+    WC_FUNC_CERTIFICATE_STATUS_SEND,
+    WC_FUNC_CERTIFICATE_STATUS_DO,
+    WC_FUNC_SERVER_KEY_EXCHANGE_SEND,
+    WC_FUNC_SERVER_KEY_EXCHANGE_DO,
+    WC_FUNC_END_OF_EARLY_DATA_SEND,
+    WC_FUNC_END_OF_EARLY_DATA_DO,
+    WC_FUNC_COUNT
+};
+#endif
+
 typedef void (*wolfSSL_Logging_cb)(const int logLevel,
                                   const char *const logMessage);
 
 WOLFSSL_API int wolfSSL_SetLoggingCb(wolfSSL_Logging_cb log_function);
+
+/* turn logging on, only if compiled in */
+WOLFSSL_API int  wolfSSL_Debugging_ON(void);
+/* turn logging off */
+WOLFSSL_API void wolfSSL_Debugging_OFF(void);
+
 
 #if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE)
@@ -56,11 +110,28 @@
     WOLFSSL_LOCAL void wc_RemoveErrorNode(int index);
     WOLFSSL_LOCAL void wc_ClearErrorNodes(void);
+    WOLFSSL_LOCAL int wc_PullErrorNode(const char **file, const char **reason,
+                            int *line);
     WOLFSSL_API   int wc_SetLoggingHeap(void* h);
+    WOLFSSL_API   int wc_ERR_remove_state(void);
     #if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM)
-        WOLFSSL_API   void wc_ERR_print_errors_fp(FILE* fp);
+        WOLFSSL_API   void wc_ERR_print_errors_fp(XFILE fp);
     #endif
-#endif /* defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE) */
+#endif /* OPENSSL_EXTRA || DEBUG_WOLFSSL_VERBOSE */
 
-#ifdef DEBUG_WOLFSSL
+#ifdef WOLFSSL_FUNC_TIME
+    /* WARNING: This code is only to be used for debugging performance.
+     *          The code is not thread-safe.
+     *          Do not use WOLFSSL_FUNC_TIME in production code.
+     */
+    WOLFSSL_API void WOLFSSL_START(int funcNum);
+    WOLFSSL_API void WOLFSSL_END(int funcNum);
+    WOLFSSL_API void WOLFSSL_TIME(int count);
+#else
+    #define WOLFSSL_START(n)
+    #define WOLFSSL_END(n)
+    #define WOLFSSL_TIME(n)
+#endif
+
+#if defined(DEBUG_WOLFSSL) && !defined(WOLFSSL_DEBUG_ERRORS_ONLY)
     #if defined(_WIN32)
         #if defined(INTIME_RTOS)
@@ -74,13 +145,13 @@
     #define WOLFSSL_LOG_CAT(a, m, b) #a " " m " "  #b
 
-    void WOLFSSL_ENTER(const char* msg);
-    void WOLFSSL_LEAVE(const char* msg, int ret);
+    WOLFSSL_API void WOLFSSL_ENTER(const char* msg);
+    WOLFSSL_API void WOLFSSL_LEAVE(const char* msg, int ret);
     #define WOLFSSL_STUB(m) \
         WOLFSSL_MSG(WOLFSSL_LOG_CAT(wolfSSL Stub, m, not implemented))
 
-    void WOLFSSL_MSG(const char* msg);
-    void WOLFSSL_BUFFER(const byte* buffer, word32 length);
+    WOLFSSL_API void WOLFSSL_MSG(const char* msg);
+    WOLFSSL_API void WOLFSSL_BUFFER(const byte* buffer, word32 length);
 
-#else /* DEBUG_WOLFSSL   */
+#else
 
     #define WOLFSSL_ENTER(m)
@@ -91,16 +162,21 @@
     #define WOLFSSL_BUFFER(b, l)
 
-#endif /* DEBUG_WOLFSSL  */
+#endif /* DEBUG_WOLFSSL && !WOLFSSL_DEBUG_ERRORS_ONLY */
 
-#if (defined(DEBUG_WOLFSSL) || defined(WOLFSSL_NGINX)) || defined(WOLFSSL_HAPROXY)
-    #if (defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE))
-    void WOLFSSL_ERROR_LINE(int err, const char* func, unsigned int line,
+#if defined(DEBUG_WOLFSSL) || defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+
+    #if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE)
+        WOLFSSL_API void WOLFSSL_ERROR_LINE(int err, const char* func, unsigned int line,
             const char* file, void* ctx);
-    #define WOLFSSL_ERROR(x) WOLFSSL_ERROR_LINE((x), __func__, __LINE__, __FILE__,NULL)
+        #define WOLFSSL_ERROR(x) \
+            WOLFSSL_ERROR_LINE((x), __func__, __LINE__, __FILE__, NULL)
     #else
-    void WOLFSSL_ERROR(int);
+        WOLFSSL_API void WOLFSSL_ERROR(int err);
     #endif
+    WOLFSSL_API void WOLFSSL_ERROR_MSG(const char* msg);
+
 #else
     #define WOLFSSL_ERROR(e)
+    #define WOLFSSL_ERROR_MSG(m)
 #endif
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/md2.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/md2.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/md2.h	(revision 372)
@@ -20,4 +20,8 @@
  */
 
+/*!
+    \file wolfssl/wolfcrypt/md2.h
+*/
+
 
 #ifndef WOLF_CRYPT_MD2_H
@@ -34,5 +38,5 @@
 /* in bytes */
 enum {
-    MD2             =  6,    /* hash type unique */
+    MD2             =  WC_HASH_TYPE_MD2,
     MD2_BLOCK_SIZE  = 16,
     MD2_DIGEST_SIZE = 16,
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/md4.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/md4.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/md4.h	(revision 372)
@@ -20,4 +20,7 @@
  */
 
+/*!
+    \file wolfssl/wolfcrypt/md4.h
+*/
 
 #ifndef WOLF_CRYPT_MD4_H
@@ -34,4 +37,5 @@
 /* in bytes */
 enum {
+    MD4             =  WC_HASH_TYPE_MD4,
     MD4_BLOCK_SIZE  = 64,
     MD4_DIGEST_SIZE = 16,
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/md5.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/md5.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/md5.h	(revision 372)
@@ -19,4 +19,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
  */
+
+/*!
+    \file wolfssl/wolfcrypt/md5.h
+*/
 
 
@@ -49,5 +53,5 @@
 /* in bytes */
 enum {
-    WC_MD5             =  0,      /* hash type unique */
+    WC_MD5             =  WC_HASH_TYPE_MD5,
     WC_MD5_BLOCK_SIZE  = 64,
     WC_MD5_DIGEST_SIZE = 16,
@@ -55,6 +59,10 @@
 };
 
+
 #ifdef WOLFSSL_MICROCHIP_PIC32MZ
     #include <wolfssl/wolfcrypt/port/pic32/pic32mz-crypt.h>
+#endif
+#ifdef STM32_HASH
+    #include <wolfssl/wolfcrypt/port/st/stm32.h>
 #endif
 #ifdef WOLFSSL_ASYNC_CRYPT
@@ -64,8 +72,13 @@
 #ifdef WOLFSSL_TI_HASH
     #include "wolfssl/wolfcrypt/port/ti/ti-hash.h"
+#elif defined(WOLFSSL_IMX6_CAAM)
+    #include "wolfssl/wolfcrypt/port/caam/wolfcaam_sha.h"
 #else
 
 /* MD5 digest */
 typedef struct wc_Md5 {
+#ifdef STM32_HASH
+    STM32_HASH_Context stmCtx;
+#else
     word32  buffLen;   /* in bytes          */
     word32  loLen;     /* length in bytes   */
@@ -81,7 +94,5 @@
     hashUpdCache cache; /* cache for updates */
 #endif
-#if defined(STM32_HASH) && defined(WOLFSSL_STM32_CUBEMX)
-    HASH_HandleTypeDef hashHandle;
-#endif
+#endif /* STM32_HASH */
 #ifdef WOLFSSL_ASYNC_CRYPT
     WC_ASYNC_DEV asyncDev;
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/memory.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/memory.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/memory.h	(revision 372)
@@ -23,4 +23,7 @@
 /* submitted by eof */
 
+/*!
+    \file wolfssl/wolfcrypt/memory.h
+*/
 
 #ifndef WOLFSSL_MEMORY_H
@@ -32,4 +35,8 @@
 #ifdef __cplusplus
     extern "C" {
+#endif
+
+#ifdef WOLFSSL_FORCE_MALLOC_FAIL_TEST
+    WOLFSSL_API void wolfSSL_SetMemFailCount(int memFailCount);
 #endif
 
@@ -75,5 +82,4 @@
                                       wolfSSL_Free_cb,
                                       wolfSSL_Realloc_cb);
-
 WOLFSSL_API int wolfSSL_GetAllocators(wolfSSL_Malloc_cb*,
                                       wolfSSL_Free_cb*,
@@ -89,16 +95,21 @@
     #endif
     #define WOLFMEM_DEF_BUCKETS  9     /* number of default memory blocks */
+    #ifndef WOLFMEM_IO_SZ
     #define WOLFMEM_IO_SZ        16992 /* 16 byte aligned */
+    #endif
     #ifndef WOLFMEM_BUCKETS
-        /* default size of chunks of memory to seperate into
-         * having session certs enabled makes a 21k SSL struct */
         #ifndef SESSION_CERTS
+            /* default size of chunks of memory to separate into */
             #define WOLFMEM_BUCKETS 64,128,256,512,1024,2432,3456,4544,16128
+        #elif defined (WOLFSSL_CERT_EXT)
+            /* certificate extensions requires 24k for the SSL struct */
+            #define WOLFMEM_BUCKETS 64,128,256,512,1024,2432,3456,4544,24576
         #else
-            #define WOLFMEM_BUCKETS 64,128,256,512,1024,2432,3456,4544,21056
+            /* increase 23k for object member of WOLFSSL_X509_NAME_ENTRY */
+            #define WOLFMEM_BUCKETS 64,128,256,512,1024,2432,3456,4544,23440
         #endif
     #endif
     #ifndef WOLFMEM_DIST
-        #define WOLFMEM_DIST    8,4,4,12,4,5,8,1,1
+        #define WOLFMEM_DIST    49,10,6,14,5,6,9,1,1
     #endif
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/misc.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/misc.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/misc.h	(revision 372)
@@ -92,4 +92,15 @@
 word32 btoi(byte b);
 
+
+WOLFSSL_LOCAL byte ctMaskGT(int a, int b);
+WOLFSSL_LOCAL byte ctMaskGTE(int a, int b);
+WOLFSSL_LOCAL byte ctMaskLT(int a, int b);
+WOLFSSL_LOCAL byte ctMaskLTE(int a, int b);
+WOLFSSL_LOCAL byte ctMaskEq(int a, int b);
+WOLFSSL_LOCAL byte ctMaskNotEq(int a, int b);
+WOLFSSL_LOCAL byte ctMaskSel(byte m, byte a, byte b);
+WOLFSSL_LOCAL int  ctMaskSelInt(byte m, int a, int b);
+WOLFSSL_LOCAL byte ctSetLTE(int a, int b);
+
 #endif /* NO_INLINE */
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/pkcs12.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/pkcs12.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/pkcs12.h	(revision 372)
@@ -40,5 +40,9 @@
 } WC_DerCertList;
 
-
+/* default values for creating PKCS12 */
+enum {
+    WC_PKCS12_ITT_DEFAULT = 2048,
+    WC_PKCS12_MAC_DEFAULT = 1,
+};
 
 WOLFSSL_API WC_PKCS12* wc_PKCS12_new(void);
@@ -48,8 +52,14 @@
         byte** pkey, word32* pkeySz, byte** cert, word32* certSz,
         WC_DerCertList** ca);
+WOLFSSL_API WC_PKCS12* wc_PKCS12_create(char* pass, word32 passSz,
+        char* name, byte* key, word32 keySz, byte* cert, word32 certSz,
+        WC_DerCertList* ca, int nidKey, int nidCert, int iter, int macIter,
+        int keyType, void* heap);
+
 
 WOLFSSL_LOCAL int wc_PKCS12_SetHeap(WC_PKCS12* pkcs12, void* heap);
 WOLFSSL_LOCAL void* wc_PKCS12_GetHeap(WC_PKCS12* pkcs12);
 
+WOLFSSL_LOCAL void wc_FreeCertList(WC_DerCertList* list, void* heap);
 
 #ifdef __cplusplus
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/pwdbased.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/pwdbased.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/pwdbased.h	(revision 372)
@@ -20,4 +20,7 @@
  */
 
+/*!
+    \file wolfssl/wolfcrypt/pwdbased.h
+*/
 
 #ifndef WOLF_CRYPT_PWDBASED_H
@@ -28,9 +31,4 @@
 #ifndef NO_PWDBASED
 
-#ifndef NO_MD5
-    #include <wolfssl/wolfcrypt/md5.h>       /* for hash type */
-#endif
-
-#include <wolfssl/wolfcrypt/sha.h>
 
 #ifdef __cplusplus
@@ -42,4 +40,8 @@
  * wolfssl/wolfcrypt/asn.h line 173 in enum Oid_Types
  */
+WOLFSSL_API int wc_PBKDF1_ex(byte* key, int keyLen, byte* iv, int ivLen,
+                      const byte* passwd, int passwdLen, 
+                      const byte* salt, int saltLen, int iterations, 
+                      int hashType, void* heap);
 WOLFSSL_API int wc_PBKDF1(byte* output, const byte* passwd, int pLen,
                       const byte* salt, int sLen, int iterations, int kLen,
@@ -61,10 +63,4 @@
 #endif
 
-/* helper functions */
-WOLFSSL_LOCAL int GetDigestSize(int typeH);
-WOLFSSL_LOCAL int GetPKCS12HashSizes(int typeH, word32* v, word32* u);
-WOLFSSL_LOCAL int DoPKCS12Hash(int typeH, byte* buffer, word32 totalLen,
-                               byte* Ai, word32 u, int iterations);
-
 
 #ifdef __cplusplus
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/rabbit.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/rabbit.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/rabbit.h	(revision 372)
@@ -19,4 +19,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
  */
+
+/*!
+    \file wolfssl/wolfcrypt/rabbit.h
+*/
 
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/random.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/random.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/random.h	(revision 372)
@@ -20,4 +20,8 @@
  */
 
+/*!
+    \file wolfssl/wolfcrypt/random.h
+*/
+
 
 
@@ -27,6 +31,12 @@
 #include <wolfssl/wolfcrypt/types.h>
 
-#ifdef HAVE_FIPS
-/* for fips @wc_fips */
+#if defined(HAVE_FIPS) && \
+    defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+    #include <wolfssl/wolfcrypt/fips.h>
+#endif /* HAVE_FIPS_VERSION >= 2 */
+
+/* included for fips @wc_fips */
+#if defined(HAVE_FIPS) && \
+        (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))
 #include <cyassl/ctaocrypt/random.h>
 #endif
@@ -58,5 +68,5 @@
 /* make sure Hash DRBG is enabled, unless WC_NO_HASHDRBG is defined
     or CUSTOM_RAND_GENERATE_BLOCK is defined*/
-#if !defined(WC_NO_HASHDRBG) || !defined(CUSTOM_RAND_GENERATE_BLOCK)
+#if !defined(WC_NO_HASHDRBG) && !defined(CUSTOM_RAND_GENERATE_BLOCK)
     #undef  HAVE_HASHDRBG
     #define HAVE_HASHDRBG
@@ -67,5 +77,7 @@
 
 
-#ifndef HAVE_FIPS /* avoid redefining structs and macros */
+/* avoid redefinition of structs */
+#if !defined(HAVE_FIPS) || \
+    (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))
 
 /* RNG supports the following sources (in order):
@@ -95,5 +107,7 @@
 #elif defined(HAVE_WNR)
      /* allow whitewood as direct RNG source using wc_GenerateSeed directly */
-#else
+#elif defined(HAVE_INTEL_RDRAND)
+    /* Intel RDRAND or RDSEED */
+#elif !defined(WC_NO_RNG)
     #error No RNG source defined!
 #endif
@@ -131,9 +145,4 @@
     typedef struct WC_RNG WC_RNG;
     #define WC_RNG_TYPE_DEFINED
-#endif
-
-#ifdef HAVE_HASHDRBG
-    /* Private DRBG state */
-    struct DRBG;
 #endif
 
@@ -153,5 +162,5 @@
 };
 
-#endif /* HAVE_FIPS */
+#endif /* NO FIPS or have FIPS v2*/
 
 /* NO_OLD_RNGNAME removes RNG struct name to prevent possible type conflicts,
@@ -172,17 +181,40 @@
 #endif /* HAVE_WNR */
 
-
+#ifndef WC_NO_RNG
 WOLFSSL_API int  wc_InitRng(WC_RNG*);
 WOLFSSL_API int  wc_InitRng_ex(WC_RNG* rng, void* heap, int devId);
+WOLFSSL_API int  wc_InitRngNonce(WC_RNG* rng, byte* nonce, word32 nonceSz);
+WOLFSSL_API int  wc_InitRngNonce_ex(WC_RNG* rng, byte* nonce, word32 nonceSz,
+                                    void* heap, int devId);
 WOLFSSL_API int  wc_RNG_GenerateBlock(WC_RNG*, byte*, word32 sz);
 WOLFSSL_API int  wc_RNG_GenerateByte(WC_RNG*, byte*);
 WOLFSSL_API int  wc_FreeRng(WC_RNG*);
+#else
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#define wc_InitRng(rng) NOT_COMPILED_IN
+#define wc_InitRng_ex(rng, h, d) NOT_COMPILED_IN
+#define wc_InitRngNonce(rng, n, s) NOT_COMPILED_IN
+#define wc_InitRngNonce_ex(rng, n, s, h, d) NOT_COMPILED_IN
+#define wc_RNG_GenerateBlock(rng, b, s) NOT_COMPILED_IN
+#define wc_RNG_GenerateByte(rng, b) NOT_COMPILED_IN
+#define wc_FreeRng(rng) (void)NOT_COMPILED_IN
+#endif
+
 
 
 #ifdef HAVE_HASHDRBG
+    WOLFSSL_LOCAL int wc_RNG_DRBG_Reseed(WC_RNG* rng, const byte* entropy,
+                                        word32 entropySz);
+    WOLFSSL_API int wc_RNG_TestSeed(const byte* seed, word32 seedSz);
     WOLFSSL_API int wc_RNG_HealthTest(int reseed,
                                         const byte* entropyA, word32 entropyASz,
                                         const byte* entropyB, word32 entropyBSz,
                                         byte* output, word32 outputSz);
+    WOLFSSL_API int wc_RNG_HealthTest_ex(int reseed,
+                                        const byte* nonce, word32 nonceSz,
+                                        const byte* entropyA, word32 entropyASz,
+                                        const byte* entropyB, word32 entropyBSz,
+                                        byte* output, word32 outputSz,
+                                        void* heap, int devId);
 #endif /* HAVE_HASHDRBG */
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/ripemd.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/ripemd.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/ripemd.h	(revision 372)
@@ -20,4 +20,7 @@
  */
 
+/*!
+    \file wolfssl/wolfcrypt/ripemd.h
+*/
 
 #ifndef WOLF_CRYPT_RIPEMD_H
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/rsa.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/rsa.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/rsa.h	(revision 372)
@@ -20,4 +20,8 @@
  */
 
+/*!
+    \file wolfssl/wolfcrypt/rsa.h
+*/
+
 
 #ifndef WOLF_CRYPT_RSA_H
@@ -27,4 +31,25 @@
 
 #ifndef NO_RSA
+
+
+/* RSA default exponent */
+#ifndef WC_RSA_EXPONENT
+    #define WC_RSA_EXPONENT 65537L
+#endif
+
+#if defined(WC_RSA_NONBLOCK)
+    /* enable support for fast math based non-blocking exptmod */
+    /* this splits the RSA function into many smaller operations */
+    #ifndef USE_FAST_MATH
+        #error RSA non-blocking mode only supported using fast math
+    #endif
+    #ifndef TFM_TIMING_RESISTANT
+      #error RSA non-blocking mode only supported with timing resistance enabled
+    #endif
+
+    /* RSA bounds check is not supported with RSA non-blocking mode */
+    #undef  NO_RSA_BOUNDS_CHECK
+    #define NO_RSA_BOUNDS_CHECK
+#endif
 
 /* allow for user to plug in own crypto */
@@ -33,5 +58,6 @@
 #else
 
-#ifdef HAVE_FIPS
+#if defined(HAVE_FIPS) && \
+	(!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))
 /* for fips @wc_fips */
 #include <cyassl/ctaocrypt/rsa.h>
@@ -42,5 +68,9 @@
     #include <wolfssl/wolfcrypt/integer.h>
     #include <wolfssl/wolfcrypt/random.h>
-#endif /* HAVE_FIPS */
+#endif /* HAVE_FIPS && HAVE_FIPS_VERION 1 */
+#if defined(HAVE_FIPS) && \
+	defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+#include <wolfssl/wolfcrypt/fips.h>
+#endif
 
 /* header file needed for OAEP padding */
@@ -55,6 +85,12 @@
 #endif
 
+enum {
+    RSA_MIN_SIZE = 512,
+    RSA_MAX_SIZE = 4096,
+};
+
 /* avoid redefinition of structs */
-#if !defined(HAVE_FIPS)
+#if !defined(HAVE_FIPS) || \
+    (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))
 
 #ifdef WOLFSSL_ASYNC_CRYPT
@@ -78,21 +114,38 @@
     RSA_BLOCK_TYPE_2 = 2,
 
-    RSA_MIN_SIZE = 512,
-    RSA_MAX_SIZE = 4096,
-
     RSA_MIN_PAD_SZ   = 11,     /* separator + 0 + pad value + 8 pads */
 
     RSA_PSS_PAD_SZ = 8,
+    RSA_PSS_SALT_MAX_SZ = 62,
 
 #ifdef OPENSSL_EXTRA
     RSA_PKCS1_PADDING_SIZE = 11,
-    RSA_PKCS1_OAEP_PADDING_SIZE = 42 /* (2 * hashlen(SHA-1)) + 2 */
+    RSA_PKCS1_OAEP_PADDING_SIZE = 42, /* (2 * hashlen(SHA-1)) + 2 */
+#endif
+#ifdef WC_RSA_PSS
+    RSA_PSS_PAD_TERM = 0xBC,
+#endif
+
+#ifdef HAVE_PKCS11
+    RSA_MAX_ID_LEN      = 32,
   #endif
 };
 
+#ifdef WC_RSA_NONBLOCK
+typedef struct RsaNb {
+    exptModNb_t exptmod; /* non-block expt_mod */
+    mp_int tmp;
+} RsaNb;
+#endif
 
 /* RSA */
 struct RsaKey {
-    mp_int n, e, d, p, q, dP, dQ, u;
+    mp_int n, e;
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
+    mp_int d, p, q;
+#if defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA) || !defined(RSA_LOW_MEM)
+    mp_int dP, dQ, u;
+#endif
+#endif
     void* heap;                               /* for user memory overrides */
     byte* data;                               /* temp buffer for async RSA */
@@ -103,4 +156,7 @@
     WC_RNG* rng;                              /* for PrivateDecrypt blinding */
 #endif
+#ifdef WOLF_CRYPTO_DEV
+    int   devId;
+#endif
 #ifdef WOLFSSL_ASYNC_CRYPT
     WC_ASYNC_DEV asyncDev;
@@ -114,5 +170,14 @@
     XSecure_Rsa xRsa;
 #endif
+#ifdef HAVE_PKCS11
+    byte id[RSA_MAX_ID_LEN];
+    int  idLen;
+#endif
+#if defined(WOLFSSL_ASYNC_CRYPT) || !defined(WOLFSSL_RSA_VERIFY_INLINE)
     byte   dataIsAlloc;
+#endif
+#ifdef WC_RSA_NONBLOCK
+    RsaNb* nb;
+#endif
 };
 
@@ -127,9 +192,14 @@
 WOLFSSL_API int  wc_InitRsaKey_ex(RsaKey* key, void* heap, int devId);
 WOLFSSL_API int  wc_FreeRsaKey(RsaKey* key);
+#ifdef HAVE_PKCS11
+WOLFSSL_API int wc_InitRsaKey_Id(RsaKey* key, unsigned char* id, int len,
+                                 void* heap, int devId);
+#endif
+WOLFSSL_API int  wc_CheckRsaKey(RsaKey* key);
 #ifdef WOLFSSL_XILINX_CRYPT
 WOLFSSL_LOCAL int wc_InitRsaHw(RsaKey* key);
 #endif /* WOLFSSL_XILINX_CRYPT */
 
-WOLFSSL_LOCAL int wc_RsaFunction(const byte* in, word32 inLen, byte* out,
+WOLFSSL_API int  wc_RsaFunction(const byte* in, word32 inLen, byte* out,
                            word32* outLen, int type, RsaKey* key, WC_RNG* rng);
 
@@ -145,4 +215,8 @@
                                 word32 outLen, enum wc_HashType hash, int mgf,
                                 RsaKey* key, WC_RNG* rng);
+WOLFSSL_API int  wc_RsaPSS_Sign_ex(const byte* in, word32 inLen, byte* out,
+                                   word32 outLen, enum wc_HashType hash,
+                                   int mgf, int saltLen, RsaKey* key,
+                                   WC_RNG* rng);
 WOLFSSL_API int  wc_RsaSSL_VerifyInline(byte* in, word32 inLen, byte** out,
                                     RsaKey* key);
@@ -152,11 +226,35 @@
                                         enum wc_HashType hash, int mgf,
                                         RsaKey* key);
+WOLFSSL_API int  wc_RsaPSS_VerifyInline_ex(byte* in, word32 inLen, byte** out,
+                                           enum wc_HashType hash, int mgf,
+                                           int saltLen, RsaKey* key);
+WOLFSSL_API int  wc_RsaPSS_Verify(byte* in, word32 inLen, byte* out,
+                                  word32 outLen, enum wc_HashType hash, int mgf,
+                                  RsaKey* key);
+WOLFSSL_API int  wc_RsaPSS_Verify_ex(byte* in, word32 inLen, byte* out,
+                                     word32 outLen, enum wc_HashType hash,
+                                     int mgf, int saltLen, RsaKey* key);
 WOLFSSL_API int  wc_RsaPSS_CheckPadding(const byte* in, word32 inLen, byte* sig,
                                         word32 sigSz,
                                         enum wc_HashType hashType);
+WOLFSSL_API int  wc_RsaPSS_CheckPadding_ex(const byte* in, word32 inLen,
+                                           byte* sig, word32 sigSz,
+                                           enum wc_HashType hashType,
+                                           int saltLen, int bits);
+WOLFSSL_API int  wc_RsaPSS_VerifyCheckInline(byte* in, word32 inLen, byte** out,
+                               const byte* digest, word32 digentLen,
+                               enum wc_HashType hash, int mgf,
+                               RsaKey* key);
+WOLFSSL_API int  wc_RsaPSS_VerifyCheck(byte* in, word32 inLen,
+                               byte* out, word32 outLen,
+                               const byte* digest, word32 digestLen,
+                               enum wc_HashType hash, int mgf,
+                               RsaKey* key);
 
 WOLFSSL_API int  wc_RsaEncryptSize(RsaKey* key);
 
-#ifndef HAVE_FIPS /* to avoid asn duplicate symbols @wc_fips */
+#if !defined(HAVE_FIPS) || \
+	(defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))
+/* to avoid asn duplicate symbols @wc_fips */
 WOLFSSL_API int  wc_RsaPrivateKeyDecode(const byte* input, word32* inOutIdx,
                                                                RsaKey*, word32);
@@ -169,5 +267,14 @@
 #endif
 
+#ifdef WC_RSA_BLINDING
 WOLFSSL_API int wc_RsaSetRNG(RsaKey* key, WC_RNG* rng);
+#endif
+#ifdef WC_RSA_NONBLOCK
+    WOLFSSL_API int wc_RsaSetNonBlock(RsaKey* key, RsaNb* nb);
+    #ifdef WC_RSA_NONBLOCK_TIME
+    WOLFSSL_API int wc_RsaSetNonBlockTime(RsaKey* key, word32 maxBlockUs,
+                                          word32 cpuMHz);
+    #endif
+#endif
 
 /*
@@ -187,4 +294,5 @@
 #define WC_RSA_OAEP_PAD    1
 #define WC_RSA_PSS_PAD     2
+#define WC_RSA_NO_PAD      3
 
 WOLFSSL_API int  wc_RsaPublicEncrypt_ex(const byte* in, word32 inLen, byte* out,
@@ -197,11 +305,32 @@
                       byte** out, RsaKey* key, int type, enum wc_HashType hash,
                       int mgf, byte* label, word32 lableSz);
+#if defined(WC_RSA_DIRECT) || defined(WC_RSA_NO_PADDING)
+WOLFSSL_API int wc_RsaDirect(byte* in, word32 inLen, byte* out, word32* outSz,
+                   RsaKey* key, int type, WC_RNG* rng);
+#endif
+
 #endif /* HAVE_FIPS*/
+
 WOLFSSL_API int  wc_RsaFlattenPublicKey(RsaKey*, byte*, word32*, byte*,
                                                                        word32*);
+WOLFSSL_API int wc_RsaExportKey(RsaKey* key,
+                                byte* e, word32* eSz,
+                                byte* n, word32* nSz,
+                                byte* d, word32* dSz,
+                                byte* p, word32* pSz,
+                                byte* q, word32* qSz);
+
+    WOLFSSL_API int wc_RsaKeyToPublicDer(RsaKey*, byte* output, word32 inLen);
 
 #ifdef WOLFSSL_KEY_GEN
-    WOLFSSL_API int wc_RsaKeyToPublicDer(RsaKey*, byte* output, word32 inLen);
     WOLFSSL_API int wc_MakeRsaKey(RsaKey* key, int size, long e, WC_RNG* rng);
+    WOLFSSL_API int wc_CheckProbablePrime_ex(const byte* p, word32 pSz,
+                                          const byte* q, word32 qSz,
+                                          const byte* e, word32 eSz,
+                                          int nlen, int* isPrime, WC_RNG* rng);
+    WOLFSSL_API int wc_CheckProbablePrime(const byte* p, word32 pSz,
+                                          const byte* q, word32 qSz,
+                                          const byte* e, word32 eSz,
+                                          int nlen, int* isPrime);
 #endif
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/settings.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/settings.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/settings.h	(revision 372)
@@ -77,4 +77,7 @@
 /* #define WOLFSSL_LSR */
 
+/* Uncomment next line if building for Freescale Classic MQX version 4.0 */
+/* #define FREESCALE_MQX_4_0 */
+
 /* Uncomment next line if building for Freescale Classic MQX/RTCS/MFS */
 /* #define FREESCALE_MQX */
@@ -86,5 +89,6 @@
 /* #define FREESCALE_KSDK_BM */
 
-/* Uncomment next line if building for Freescale KSDK FreeRTOS (old name FREESCALE_FREE_RTOS) */
+/* Uncomment next line if building for Freescale KSDK FreeRTOS, */
+/* (old name FREESCALE_FREE_RTOS) */
 /* #define FREESCALE_KSDK_FREERTOS */
 
@@ -94,4 +98,7 @@
 /* Uncomment next line if using STM32F4 */
 /* #define WOLFSSL_STM32F4 */
+
+/* Uncomment next line if using STM32FL */
+/* #define WOLFSSL_STM32FL */
 
 /* Uncomment next line if using STM32F7 */
@@ -162,4 +169,16 @@
 /* Uncomment next line if building for using XILINX */
 /* #define WOLFSSL_XILINX */
+
+/* Uncomment next line if building for Nucleus 1.2 */
+/* #define WOLFSSL_NUCLEUS_1_2 */
+
+/* Uncomment next line if building for using Apache mynewt */
+/* #define WOLFSSL_APACHE_MYNEWT */
+
+/* Uncomment next line if building for using ESP-IDF */
+/* #define WOLFSSL_ESPIDF */
+
+/* Uncomment next line if using Espressif ESP32-WROOM-32 */
+/* #define WOLFSSL_ESPWROOM32 */
 
 #include <wolfssl/wolfcrypt/visibility.h>
@@ -203,4 +222,20 @@
     #include <nx_api.h>
 #endif
+
+#if defined(WOLFSSL_ESPIDF)
+    #define FREERTOS
+    #define WOLFSSL_LWIP
+    #define NO_WRITEV
+    #define SIZEOF_LONG_LONG 8
+    #define NO_WOLFSSL_DIR
+    #define WOLFSSL_NO_CURRDIR
+
+    #define TFM_TIMING_RESISTANT
+    #define ECC_TIMING_RESISTANT
+    #define WC_RSA_BLINDING
+#if !defined(WOLFSSL_USER_SETTINGS)
+    #define HAVE_ECC
+#endif /* !WOLFSSL_USER_SETTINGS */
+#endif /* WOLFSSL_ESPIDF */
 
 #if defined(HAVE_LWIP_NATIVE) /* using LwIP native TCP socket */
@@ -210,4 +245,20 @@
     #define WOLFSSL_USER_IO
     #define NO_FILESYSTEM
+#endif
+
+#if defined(WOLFSSL_CONTIKI)
+    #include <contiki.h>
+    #define WOLFSSL_UIP
+    #define NO_WOLFSSL_MEMORY
+    #define NO_WRITEV
+    #define SINGLE_THREADED
+    #define WOLFSSL_USER_IO
+    #define NO_FILESYSTEM
+    #define CUSTOM_RAND_TYPE uint16_t
+    #define CUSTOM_RAND_GENERATE random_rand
+    static inline unsigned int LowResTimer(void)
+    {
+        return clock_seconds();
+    }
 #endif
 
@@ -241,7 +292,13 @@
 
 #ifdef WOLFSSL_MICROCHIP_PIC32MZ
+    #ifndef NO_PIC32MZ_CRYPT
     #define WOLFSSL_PIC32MZ_CRYPT
+    #endif
+    #ifndef NO_PIC32MZ_RNG
     #define WOLFSSL_PIC32MZ_RNG
+    #endif
+    #ifndef NO_PIC32MZ_HASH
     #define WOLFSSL_PIC32MZ_HASH
+#endif
 #endif
 
@@ -342,5 +399,6 @@
         #define TFM_NO_ASM
     #endif
-    #define WOLFSSL_PTHREADS
+    /* For VxWorks pthreads wrappers for mutexes uncomment the next line. */
+    /* #define WOLFSSL_PTHREADS */
     #define WOLFSSL_HAVE_MIN
     #define WOLFSSL_HAVE_MAX
@@ -441,4 +499,35 @@
     #define NO_FILESYSTEM
     #define USE_CERT_BUFFERS_2048
+#endif
+
+#ifdef WOLFSSL_CHIBIOS
+    /* ChibiOS definitions. This file is distributed with chibiOS. */
+    #include "wolfssl_chibios.h"
+#endif
+
+#ifdef WOLFSSL_PB
+    /* PB is using older 1.2 version of Nucleus */
+    #undef WOLFSSL_NUCLEUS
+    #define WOLFSSL_NUCLEUS_1_2
+#endif
+
+#ifdef WOLFSSL_NUCLEUS_1_2
+    #define NO_WRITEV
+    #define NO_WOLFSSL_DIR
+
+    #if !defined(NO_ASN_TIME) && !defined(USER_TIME)
+        #error User must define XTIME, see manual
+    #endif
+
+    #if !defined(XMALLOC_OVERRIDE) && !defined(XMALLOC_USER)
+        extern void* nucleus_malloc(unsigned long size, void* heap, int type);
+        extern void* nucleus_realloc(void* ptr, unsigned long size, void* heap,
+                                     int type);
+        extern void  nucleus_free(void* ptr, void* heap, int type);
+
+        #define XMALLOC(s, h, type)  nucleus_malloc((s), (h), (type))
+        #define XREALLOC(p, n, h, t) nucleus_realloc((p), (n), (h), (t))
+        #define XFREE(p, h, type)    nucleus_free((p), (h), (type))
+    #endif
 #endif
 
@@ -499,5 +588,5 @@
 
     /* static char* gets(char *buff); */
-    static char* fgets(char *buff, int sz, FILE *fp) {
+    static char* fgets(char *buff, int sz, XFILE fp) {
         char * p = buff;
         *p = '\0';
@@ -539,9 +628,12 @@
 
     /* FreeRTOS pvPortRealloc() only in AVR32_UC3 port */
-    #if !defined(XMALLOC_USER) && !defined(NO_WOLFSSL_MEMORY)
+    #if !defined(XMALLOC_USER) && !defined(NO_WOLFSSL_MEMORY) && \
+        !defined(WOLFSSL_STATIC_MEMORY)
         #define XMALLOC(s, h, type)  pvPortMalloc((s))
         #define XFREE(p, h, type)    vPortFree((p))
     #endif
-
+    #if defined(HAVE_ED25519) || defined(WOLFSSL_ESPIDF)
+        #define XREALLOC(p, n, h, t) wolfSSL_Realloc((p), (n))
+    #endif
     #ifndef NO_WRITEV
         #define NO_WRITEV
@@ -570,6 +662,6 @@
 
 #ifdef FREERTOS_TCP
-
-#if !defined(NO_WOLFSSL_MEMORY) && !defined(XMALLOC_USER)
+    #if !defined(NO_WOLFSSL_MEMORY) && !defined(XMALLOC_USER) && \
+        !defined(WOLFSSL_STATIC_MEMORY)
 #define XMALLOC(s, h, type)  pvPortMalloc((s))
 #define XFREE(p, h, type)    vPortFree((p))
@@ -583,5 +675,4 @@
 #define TFM_TIMING_RESISTANT
 #define NO_MAIN_DRIVER
-
 #endif
 
@@ -592,4 +683,6 @@
     #define USE_FAST_MATH
     #define TFM_TIMING_RESISTANT
+    #define ECC_TIMING_RESISTANT
+    #define WC_RSA_BLINDING
     #define NO_DEV_RANDOM
     #define NO_FILESYSTEM
@@ -599,4 +692,5 @@
     #define HAVE_ECC
     #define HAVE_ALPN
+    #define USE_WOLF_STRTOK /* use with HAVE_ALPN */
     #define HAVE_TLS_EXTENSIONS
     #define HAVE_AESGCM
@@ -702,4 +796,9 @@
 #endif
 
+#ifdef FREESCALE_MQX_4_0
+    /* use normal Freescale MQX port, but with minor changes for 4.0 */
+    #define FREESCALE_MQX
+#endif
+
 #ifdef FREESCALE_MQX
     #define FREESCALE_COMMON
@@ -718,8 +817,10 @@
     #endif
 
+    #if !defined(XMALLOC_OVERRIDE) && !defined(XMALLOC_USER)
     #define XMALLOC_OVERRIDE
     #define XMALLOC(s, h, t)    (void *)_mem_alloc_system((s))
     #define XFREE(p, h, t)      {void* xp = (p); if ((xp)) _mem_free((xp));}
     /* Note: MQX has no realloc, using fastmath above */
+#endif
 #endif
 
@@ -948,12 +1049,4 @@
                     #define HAVE_ECC384
                 #endif
-
-                /* enable features */
-                #undef  HAVE_CURVE25519
-                #define HAVE_CURVE25519
-                #undef  HAVE_ED25519
-                #define HAVE_ED25519
-                #undef  WOLFSSL_SHA512
-                #define WOLFSSL_SHA512
             #endif
         #endif
@@ -979,5 +1072,6 @@
 
 #if defined(WOLFSSL_STM32F2) || defined(WOLFSSL_STM32F4) || \
-    defined(WOLFSSL_STM32F7)
+    defined(WOLFSSL_STM32F7) || defined(WOLFSSL_STM32F1) || \
+    defined(WOLFSSL_STM32L4)
 
     #define SIZEOF_LONG_LONG 8
@@ -986,13 +1080,18 @@
     #undef  NO_RABBIT
     #define NO_RABBIT
-    #undef  NO_64BIT
-    #define NO_64BIT
     #ifndef NO_STM32_RNG
         #undef  STM32_RNG
         #define STM32_RNG
+        #ifdef WOLFSSL_STM32F427_RNG
+            #include "stm32f427xx.h"
+        #endif
     #endif
     #ifndef NO_STM32_CRYPTO
         #undef  STM32_CRYPTO
         #define STM32_CRYPTO
+
+        #ifdef WOLFSSL_STM32L4
+            #define NO_AES_192 /* hardware does not support 192-bit */
+        #endif
     #endif
     #ifndef NO_STM32_HASH
@@ -1007,8 +1106,12 @@
         #if defined(WOLFSSL_STM32F2)
             #include "stm32f2xx_hal.h"
+        #elif defined(WOLFSSL_STM32L4)
+            #include "stm32l4xx_hal.h"
         #elif defined(WOLFSSL_STM32F4)
             #include "stm32f4xx_hal.h"
         #elif defined(WOLFSSL_STM32F7)
             #include "stm32f7xx_hal.h"
+        #elif defined(WOLFSSL_STM32F1)
+            #include "stm32f1xx_hal.h"
         #endif
 
@@ -1033,9 +1136,19 @@
                 #include "stm32f4xx_hash.h"
             #endif
+        #elif defined(WOLFSSL_STM32L4)
+            #include "stm32l4xx.h"
+            #ifdef STM32_CRYPTO
+                #include "stm32l4xx_cryp.h"
+            #endif
+            #ifdef STM32_HASH
+                #include "stm32l4xx_hash.h"
+            #endif
         #elif defined(WOLFSSL_STM32F7)
             #include "stm32f7xx.h"
+        #elif defined(WOLFSSL_STM32F1)
+            #include "stm32f1xx.h"
         #endif
     #endif /* WOLFSSL_STM32_CUBEMX */
-#endif /* WOLFSSL_STM32F2 || WOLFSSL_STM32F4 || WOLFSSL_STM32F7 */
+#endif /* WOLFSSL_STM32F2 || WOLFSSL_STM32F4 || WOLFSSL_STM32L4 || WOLFSSL_STM32F7 */
 
 #ifdef MICRIUM
@@ -1074,10 +1187,4 @@
         #define CUSTOM_RAND_GENERATE Math_Rand
     #endif
-
-    #define WOLFSSL_TYPES
-    typedef CPU_INT08U byte;
-    typedef CPU_INT16U word16;
-    typedef CPU_INT32U word32;
-
     #define STRING_USER
     #define XSTRLEN(pstr) ((CPU_SIZE_T)Str_Len((CPU_CHAR *)(pstr)))
@@ -1176,4 +1283,60 @@
 #endif /*(WOLFSSL_XILINX_CRYPT)*/
 
+#if defined(WOLFSSL_APACHE_MYNEWT)
+    #include "os/os_malloc.h"
+    #if !defined(WOLFSSL_LWIP)
+        #include <mn_socket/mn_socket.h>
+    #endif
+
+    #if !defined(SIZEOF_LONG)
+        #define SIZEOF_LONG 4
+    #endif
+    #if !defined(SIZEOF_LONG_LONG)
+        #define SIZEOF_LONG_LONG 8
+    #endif
+    #if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+        #define BIG_ENDIAN_ORDER
+    #else
+        #undef  BIG_ENDIAN_ORDER
+        #define LITTLE_ENDIAN_ORDER
+    #endif
+    #define NO_WRITEV
+    #define WOLFSSL_USER_IO
+    #define SINGLE_THREADED
+    #define NO_DEV_RANDOM
+    #define NO_DH
+    #define NO_WOLFSSL_DIR
+    #define NO_ERROR_STRINGS
+    #define HAVE_ECC
+    #define NO_SESSION_CACHE
+    #define NO_ERROR_STRINGS
+    #define XMALLOC_USER
+    #define XMALLOC(sz, heap, type)     os_malloc(sz)
+    #define XREALLOC(p, sz, heap, type) os_realloc(p, sz)
+    #define XFREE(p, heap, type)        os_free(p)
+
+#endif /*(WOLFSSL_APACHE_MYNEWT)*/
+
+#ifdef WOLFSSL_IMX6
+    #ifndef SIZEOF_LONG_LONG
+        #define SIZEOF_LONG_LONG 8
+    #endif
+#endif
+
+/* if defined turn on all CAAM support */
+#ifdef WOLFSSL_IMX6_CAAM
+    #undef  WOLFSSL_IMX6_CAAM_RNG
+    #define WOLFSSL_IMX6_CAAM_RNG
+
+    #undef  WOLFSSL_IMX6_CAAM_BLOB
+    #define WOLFSSL_IMX6_CAAM_BLOB
+
+#if defined(HAVE_AESGCM) || defined(WOLFSSL_AES_XTS)
+    /* large performance gain with HAVE_AES_ECB defined */
+    #undef HAVE_AES_ECB
+    #define HAVE_AES_ECB
+#endif
+#endif
+
 #if !defined(XMALLOC_USER) && !defined(MICRIUM_MALLOC) && \
     !defined(WOLFSSL_LEANPSK) && !defined(NO_WOLFSSL_MEMORY) && \
@@ -1206,14 +1369,20 @@
 #ifdef WOLFSSL_SGX
     #ifdef _MSC_VER
-        #define WOLFCRYPT_ONLY
         #define NO_RC4
+        #ifndef HAVE_FIPS
+            #define WOLFCRYPT_ONLY
         #define NO_DES3
         #define NO_SHA
         #define NO_MD5
     #else
+        #define TFM_TIMING_RESISTANT
+            #define NO_WOLFSSL_DIR
+            #define NO_WRITEV
+            #define NO_MAIN_DRIVER
+            #define WOLFSSL_LOG_PRINTF
+            #define WOLFSSL_DH_CONST
+        #endif
+    #else
         #define HAVE_ECC
-        #define ECC_TIMING_RESISTANT
-        #define TFM_TIMING_RESISTANT
-        #define NO_FILESYSTEM
         #define NO_WRITEV
         #define NO_MAIN_DRIVER
@@ -1222,7 +1391,11 @@
         #define WOLFSSL_DH_CONST
     #endif /* _MSC_VER */
-    #ifndef NO_RSA
+    #if !defined(HAVE_FIPS) && !defined(NO_RSA)
         #define WC_RSA_BLINDING
     #endif
+
+    #define NO_FILESYSTEM
+    #define ECC_TIMING_RESISTANT
+    #define TFM_TIMING_RESISTANT
     #define SINGLE_THREADED
     #define NO_ASN_TIME /* can not use headers such as windows.h */
@@ -1284,5 +1457,5 @@
  * all curves are on by default for now */
 #ifndef ECC_USER_CURVES
-    #ifndef HAVE_ALL_CURVES
+    #if !defined(WOLFSSL_SP_MATH) && !defined(HAVE_ALL_CURVES)
         #define HAVE_ALL_CURVES
     #endif
@@ -1300,4 +1473,8 @@
         #define HAVE_ECC_VERIFY
     #endif
+    #ifndef NO_ECC_CHECK_KEY
+        #undef HAVE_ECC_CHECK_KEY
+        #define HAVE_ECC_CHECK_KEY
+    #endif
     #ifndef NO_ECC_DHE
         #undef HAVE_ECC_DHE
@@ -1359,4 +1536,21 @@
         #define AES_MAX_KEY_SIZE    256
     #endif
+
+    #ifndef NO_AES_128
+        #undef  WOLFSSL_AES_128
+        #define WOLFSSL_AES_128
+    #endif
+    #if !defined(NO_AES_192) && AES_MAX_KEY_SIZE >= 192
+        #undef  WOLFSSL_AES_192
+        #define WOLFSSL_AES_192
+    #endif
+    #if !defined(NO_AES_256) && AES_MAX_KEY_SIZE >= 256
+        #undef  WOLFSSL_AES_256
+        #define WOLFSSL_AES_256
+    #endif
+    #if !defined(WOLFSSL_AES_128) && defined(HAVE_ECC_ENCRYPT)
+        #warning HAVE_ECC_ENCRYPT uses AES 128 bit keys
+     #endif
+
     #ifndef NO_AES_DECRYPT
         #undef  HAVE_AES_DECRYPT
@@ -1366,8 +1560,4 @@
         #undef  HAVE_AES_CBC
         #define HAVE_AES_CBC
-    #else
-        #ifndef WOLFCRYPT_ONLY
-            #error "AES CBC is required for TLS and can only be disabled for WOLFCRYPT_ONLY builds"
-        #endif
     #endif
     #ifdef WOLFSSL_AES_XTS
@@ -1377,4 +1567,17 @@
         #endif
     #endif
+    #ifdef WOLFSSL_AES_CFB
+        /* AES-CFB makes calls to AES direct functions */
+        #ifndef WOLFSSL_AES_DIRECT
+        #define WOLFSSL_AES_DIRECT
+        #endif
+    #endif
+#endif
+
+#if (defined(WOLFSSL_TLS13) && defined(WOLFSSL_NO_TLS12)) || \
+    (!defined(HAVE_AES_CBC) && defined(NO_DES3) && defined(NO_RC4) && \
+     !defined(HAVE_CAMELLIA) && !defined(HAVE_IDEA) && \
+     !defined(HAVE_NULL_CIPHER) && !defined(HAVE_HC128))
+    #define WOLFSSL_AEAD_ONLY
 #endif
 
@@ -1445,7 +1648,7 @@
 
     #ifdef WOLFSSL_ASYNC_CRYPT_TEST
-        #define WC_ASYNC_DEV_SIZE 320+24
+        #define WC_ASYNC_DEV_SIZE 328+24
     #else
-        #define WC_ASYNC_DEV_SIZE 320
+        #define WC_ASYNC_DEV_SIZE 328
     #endif
 
@@ -1491,8 +1694,11 @@
 
 #ifdef HAVE_PKCS7
+    #if defined(NO_AES) && defined(NO_DES3)
+        #error PKCS7 needs either AES or 3DES enabled, please enable one
+    #endif
     #ifndef HAVE_AES_KEYWRAP
         #error PKCS7 requires AES key wrap please define HAVE_AES_KEYWRAP
     #endif
-    #ifndef HAVE_X963_KDF
+    #if defined(HAVE_ECC) && !defined(HAVE_X963_KDF)
         #error PKCS7 requires X963 KDF please define HAVE_X963_KDF
     #endif
@@ -1517,5 +1723,5 @@
 #endif /* WOLFSSL_MYSQL_COMPATIBLE */
 
-#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
     #define SSL_OP_NO_COMPRESSION    SSL_OP_NO_COMPRESSION
     #define OPENSSL_NO_ENGINE
@@ -1557,5 +1763,6 @@
     #if (defined(USE_FAST_MATH) && !defined(TFM_TIMING_RESISTANT)) || \
         (defined(HAVE_ECC) && !defined(ECC_TIMING_RESISTANT)) || \
-        (!defined(NO_RSA) && !defined(WC_RSA_BLINDING) && !defined(HAVE_FIPS))
+        (!defined(NO_RSA) && !defined(WC_RSA_BLINDING) && !defined(HAVE_FIPS) && \
+            !defined(WC_NO_RNG))
 
         #ifndef _MSC_VER
@@ -1567,4 +1774,89 @@
 #endif
 
+#if defined(NO_OLD_WC_NAMES) || defined(OPENSSL_EXTRA)
+    /* added to have compatibility with SHA256() */
+    #if !defined(NO_OLD_SHA_NAMES) && !defined(HAVE_FIPS)
+        #define NO_OLD_SHA_NAMES
+    #endif
+#endif
+
+/* switch for compatibility layer functionality. Has subparts i.e. BIO/X509
+ * When opensslextra is enabled all subparts should be turned on. */
+#ifdef OPENSSL_EXTRA
+    #undef  OPENSSL_EXTRA_X509_SMALL
+    #define OPENSSL_EXTRA_X509_SMALL
+#endif /* OPENSSL_EXTRA */
+
+/* support for converting DER to PEM */
+#if defined(WOLFSSL_KEY_GEN) || defined(WOLFSSL_CERT_GEN) || \
+        defined(OPENSSL_EXTRA)
+    #undef  WOLFSSL_DER_TO_PEM
+    #define WOLFSSL_DER_TO_PEM
+#endif
+
+/* keep backwards compatibility enabling encrypted private key */
+#ifndef WOLFSSL_ENCRYPTED_KEYS
+    #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \
+        defined(HAVE_WEBSERVER)
+        #define WOLFSSL_ENCRYPTED_KEYS
+    #endif
+#endif
+
+/* support for disabling PEM to DER */
+#if !defined(WOLFSSL_NO_PEM)
+    #undef  WOLFSSL_PEM_TO_DER
+    #define WOLFSSL_PEM_TO_DER
+#endif
+
+/* Parts of the openssl compatibility layer require peer certs */
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+    #undef  KEEP_PEER_CERT
+    #define KEEP_PEER_CERT
+#endif
+
+/* RAW hash function APIs are not implemented with ARMv8 hardware acceleration*/
+#ifdef WOLFSSL_ARMASM
+    #undef  WOLFSSL_NO_HASH_RAW
+    #define WOLFSSL_NO_HASH_RAW
+#endif
+
+#if !defined(WOLFSSL_SHA384) && !defined(WOLFSSL_SHA512) && defined(NO_AES) && \
+                                                          !defined(WOLFSSL_SHA3)
+    #undef  WOLFSSL_NO_WORD64_OPS
+    #define WOLFSSL_NO_WORD64_OPS
+#endif
+
+#if defined(NO_AES) && defined(NO_DES3) && !defined(HAVE_CAMELLIA) && \
+                                     defined(NO_PWDBASED) && !defined(HAVE_IDEA)
+    #undef  WOLFSSL_NO_XOR_OPS
+    #define WOLFSSL_NO_XOR_OPS
+#endif
+
+#if defined(NO_ASN) && defined(WOLFCRYPT_ONLY)
+    #undef  WOLFSSL_NO_INT_ENCODE
+    #define WOLFSSL_NO_INT_ENCODE
+    #undef  WOLFSSL_NO_INT_DECODE
+    #define WOLFSSL_NO_INT_DECODE
+#endif
+
+#if defined(WOLFCRYPT_ONLY) && defined(WOLFSSL_RSA_VERIFY_ONLY) && \
+    defined(WC_NO_RSA_OAEP)
+    #undef  WOLFSSL_NO_CT_OPS
+    #define WOLFSSL_NO_CT_OPS
+#endif
+
+#if defined(WOLFCRYPT_ONLY) && defined(NO_AES) && !defined(HAVE_CURVE25519) && \
+                                   defined(WC_NO_RNG) && defined(WC_NO_RSA_OAEP)
+    #undef  WOLFSSL_NO_CONST_CMP
+    #define WOLFSSL_NO_CONST_CMP
+#endif
+
+#if defined(WOLFCRYPT_ONLY) && defined(NO_AES) && !defined(WOLFSSL_SHA384) && \
+    !defined(WOLFSSL_SHA512) && defined(WC_NO_RNG) && \
+                    defined(WOLFSSL_SP_MATH) && defined(WOLFSSL_RSA_PUBLIC_ONLY)
+    #undef  WOLFSSL_NO_FORCE_ZERO
+    #define WOLFSSL_NO_FORCE_ZERO
+#endif
+
 #ifdef __cplusplus
     }   /* extern "C" */
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/sha.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/sha.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/sha.h	(revision 372)
@@ -20,4 +20,8 @@
  */
 
+/*!
+    \file wolfssl/wolfcrypt/sha.h
+*/
+
 
 #ifndef WOLF_CRYPT_SHA_H
@@ -28,5 +32,11 @@
 #ifndef NO_SHA
 
-#ifdef HAVE_FIPS
+#if defined(HAVE_FIPS) && \
+    defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+    #include <wolfssl/wolfcrypt/fips.h>
+#endif /* HAVE_FIPS_VERSION >= 2 */
+
+#if defined(HAVE_FIPS) && \
+	(!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))
 #define wc_Sha             Sha
 #define WC_SHA             SHA
@@ -47,8 +57,13 @@
 #endif
 
-#ifndef HAVE_FIPS /* avoid redefining structs */
+/* avoid redefinition of structs */
+#if !defined(HAVE_FIPS) || \
+    (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))
 
 #ifdef WOLFSSL_MICROCHIP_PIC32MZ
     #include <wolfssl/wolfcrypt/port/pic32/pic32mz-crypt.h>
+#endif
+#ifdef STM32_HASH
+    #include <wolfssl/wolfcrypt/port/st/stm32.h>
 #endif
 #ifdef WOLFSSL_ASYNC_CRYPT
@@ -56,7 +71,10 @@
 #endif
 
+#if !defined(NO_OLD_SHA_NAMES)
+    #define SHA             WC_SHA
+#endif
+
 #ifndef NO_OLD_WC_NAMES
     #define Sha             wc_Sha
-    #define SHA             WC_SHA
     #define SHA_BLOCK_SIZE  WC_SHA_BLOCK_SIZE
     #define SHA_DIGEST_SIZE WC_SHA_DIGEST_SIZE
@@ -66,5 +84,5 @@
 /* in bytes */
 enum {
-    WC_SHA              =  1,    /* hash type unique */
+    WC_SHA              =  WC_HASH_TYPE_SHA,
     WC_SHA_BLOCK_SIZE   = 64,
     WC_SHA_DIGEST_SIZE  = 20,
@@ -73,9 +91,17 @@
 
 
-#ifndef WOLFSSL_TI_HASH
+#if defined(WOLFSSL_TI_HASH)
+    #include "wolfssl/wolfcrypt/port/ti/ti-hash.h"
+
+#elif defined(WOLFSSL_IMX6_CAAM)
+    #include "wolfssl/wolfcrypt/port/caam/wolfcaam_sha.h"
+
+#else
 /* Sha digest */
 typedef struct wc_Sha {
     #ifdef FREESCALE_LTC_SHA
         ltc_hash_ctx_t ctx;
+#elif defined(STM32_HASH)
+        STM32_HASH_Context stmCtx;
     #else
         word32  buffLen;   /* in bytes          */
@@ -95,9 +121,7 @@
         WC_ASYNC_DEV asyncDev;
     #endif /* WOLFSSL_ASYNC_CRYPT */
-#endif /* FREESCALE_LTC_SHA */
+#endif
 } wc_Sha;
 
-#else
-    #include "wolfssl/wolfcrypt/port/ti/ti-hash.h"
 #endif /* WOLFSSL_TI_HASH */
 
@@ -108,4 +132,5 @@
 WOLFSSL_API int wc_InitSha_ex(wc_Sha* sha, void* heap, int devId);
 WOLFSSL_API int wc_ShaUpdate(wc_Sha*, const byte*, word32);
+WOLFSSL_API int wc_ShaFinalRaw(wc_Sha*, byte*);
 WOLFSSL_API int wc_ShaFinal(wc_Sha*, byte*);
 WOLFSSL_API void wc_ShaFree(wc_Sha*);
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/sha256.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/sha256.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/sha256.h	(revision 372)
@@ -20,4 +20,8 @@
  */
 
+/*!
+    \file wolfssl/wolfcrypt/sha256.h
+*/
+
 
 /* code submitted by raphael.huck@efixo.com */
@@ -30,5 +34,11 @@
 #ifndef NO_SHA256
 
-#ifdef HAVE_FIPS
+#if defined(HAVE_FIPS) && \
+    defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+    #include <wolfssl/wolfcrypt/fips.h>
+#endif /* HAVE_FIPS_VERSION >= 2 */
+
+#if defined(HAVE_FIPS) && \
+	(!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))
     #define wc_Sha256             Sha256
     #define WC_SHA256             SHA256
@@ -58,16 +68,35 @@
 #endif
 
-#ifndef HAVE_FIPS /* avoid redefinition of structs */
+/* avoid redefinition of structs */
+#if !defined(HAVE_FIPS) || \
+    (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))
 
 #ifdef WOLFSSL_MICROCHIP_PIC32MZ
     #include <wolfssl/wolfcrypt/port/pic32/pic32mz-crypt.h>
 #endif
+#ifdef STM32_HASH
+    #include <wolfssl/wolfcrypt/port/st/stm32.h>
+#endif
 #ifdef WOLFSSL_ASYNC_CRYPT
     #include <wolfssl/wolfcrypt/async.h>
 #endif
+#if defined(WOLFSSL_DEVCRYPTO) && defined(WOLFSSL_DEVCRYPTO_HASH)
+    #include <wolfssl/wolfcrypt/port/devcrypto/wc_devcrypto.h>
+#endif
+
+#if defined(_MSC_VER)
+    #define SHA256_NOINLINE __declspec(noinline)
+#elif defined(__GNUC__)
+    #define SHA256_NOINLINE __attribute__((noinline))
+#else
+    #define SHA256_NOINLINE
+#endif
+
+#if !defined(NO_OLD_SHA_NAMES)
+    #define SHA256             WC_SHA256
+#endif
 
 #ifndef NO_OLD_WC_NAMES
     #define Sha256             wc_Sha256
-    #define SHA256             WC_SHA256
     #define SHA256_BLOCK_SIZE  WC_SHA256_BLOCK_SIZE
     #define SHA256_DIGEST_SIZE WC_SHA256_DIGEST_SIZE
@@ -77,5 +106,5 @@
 /* in bytes */
 enum {
-    WC_SHA256              =  2,   /* hash type unique */
+    WC_SHA256              =  WC_HASH_TYPE_SHA256,
     WC_SHA256_BLOCK_SIZE   = 64,
     WC_SHA256_DIGEST_SIZE  = 32,
@@ -83,10 +112,18 @@
 };
 
-#ifndef WOLFSSL_TI_HASH
-
+
+#ifdef WOLFSSL_TI_HASH
+    #include "wolfssl/wolfcrypt/port/ti/ti-hash.h"
+#elif defined(WOLFSSL_IMX6_CAAM)
+    #include "wolfssl/wolfcrypt/port/caam/wolfcaam_sha.h"
+#elif defined(WOLFSSL_AFALG_HASH)
+    #include "wolfssl/wolfcrypt/port/af_alg/afalg_hash.h"
+#else
 /* wc_Sha256 digest */
 typedef struct wc_Sha256 {
 #ifdef FREESCALE_LTC_SHA
     ltc_hash_ctx_t ctx;
+#elif defined(STM32_HASH)
+    STM32_HASH_Context stmCtx;
 #else
     /* alignment on digest and buffer speeds up ARMv8 crypto operations */
@@ -97,18 +134,25 @@
     word32  hiLen;     /* length in bytes   */
     void*   heap;
+#ifdef USE_INTEL_SPEEDUP
+    const byte* data;
+#endif
 #ifdef WOLFSSL_PIC32MZ_HASH
     hashUpdCache cache; /* cache for updates */
-#endif
-#if defined(STM32_HASH) && defined(WOLFSSL_STM32_CUBEMX)
-    HASH_HandleTypeDef hashHandle;
 #endif
 #ifdef WOLFSSL_ASYNC_CRYPT
     WC_ASYNC_DEV asyncDev;
 #endif /* WOLFSSL_ASYNC_CRYPT */
-#endif /* FREESCALE_LTC_SHA */
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+    word32* W;
+#endif
+#ifdef WOLFSSL_DEVCRYPTO_HASH
+    WC_CRYPTODEV ctx;
+    byte*  msg;
+    word32 used;
+    word32 len;
+#endif
+#endif
 } wc_Sha256;
 
-#else
-    #include "wolfssl/wolfcrypt/port/ti/ti-hash.h"
 #endif
 
@@ -118,4 +162,5 @@
 WOLFSSL_API int wc_InitSha256_ex(wc_Sha256*, void*, int);
 WOLFSSL_API int wc_Sha256Update(wc_Sha256*, const byte*, word32);
+WOLFSSL_API int wc_Sha256FinalRaw(wc_Sha256*, byte*);
 WOLFSSL_API int wc_Sha256Final(wc_Sha256*, byte*);
 WOLFSSL_API void wc_Sha256Free(wc_Sha256*);
@@ -129,5 +174,7 @@
 
 #ifdef WOLFSSL_SHA224
-#ifndef HAVE_FIPS /* avoid redefinition of structs */
+/* avoid redefinition of structs */
+#if !defined(HAVE_FIPS) || \
+    (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))
 
 #ifndef NO_OLD_WC_NAMES
@@ -141,9 +188,10 @@
 /* in bytes */
 enum {
-    WC_SHA224              =   8,   /* hash type unique */
+    WC_SHA224              =   WC_HASH_TYPE_SHA224,
     WC_SHA224_BLOCK_SIZE   =   WC_SHA256_BLOCK_SIZE,
     WC_SHA224_DIGEST_SIZE  =   28,
     WC_SHA224_PAD_SIZE     =   WC_SHA256_PAD_SIZE
 };
+
 
 typedef wc_Sha256 wc_Sha224;
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/sha512.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/sha512.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/sha512.h	(revision 372)
@@ -1,5 +1,5 @@
 /* sha512.h
  *
- * Copyright (C) 2006-2017 wolfSSL Inc.
+ * Copyright (C) 2006-2018 wolfSSL Inc.
  *
  * This file is part of wolfSSL.
@@ -20,4 +20,8 @@
  */
 
+/*!
+    \file wolfssl/wolfcrypt/sha512.h
+*/
+
 
 #ifndef WOLF_CRYPT_SHA512_H
@@ -26,8 +30,14 @@
 #include <wolfssl/wolfcrypt/types.h>
 
-#ifdef WOLFSSL_SHA512
+#if defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384)
 
-/* for fips @wc_fips */
-#ifdef HAVE_FIPS
+#if defined(HAVE_FIPS) && \
+    defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+    #include <wolfssl/wolfcrypt/fips.h>
+#endif /* HAVE_FIPS_VERSION >= 2 */
+
+#if defined(HAVE_FIPS) && \
+	(!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))
+    #ifdef WOLFSSL_SHA512
     #define wc_Sha512             Sha512
     #define WC_SHA512             SHA512
@@ -35,4 +45,5 @@
     #define WC_SHA512_DIGEST_SIZE SHA512_DIGEST_SIZE
     #define WC_SHA512_PAD_SIZE    SHA512_PAD_SIZE
+    #endif /* WOLFSSL_SHA512 */
     #ifdef WOLFSSL_SHA384
         #define wc_Sha384             Sha384
@@ -47,4 +58,5 @@
         #define CYASSL_SHA384
     #endif
+	/* for fips @wc_fips */
     #include <cyassl/ctaocrypt/sha512.h>
 #endif
@@ -54,5 +66,7 @@
 #endif
 
-#ifndef HAVE_FIPS /* avoid redefinition of structs */
+/* avoid redefinition of structs */
+#if !defined(HAVE_FIPS) || \
+    (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))
 
 #ifdef WOLFSSL_ASYNC_CRYPT
@@ -60,7 +74,20 @@
 #endif
 
-#ifndef NO_OLD_WC_NAMES
+#if defined(_MSC_VER)
+    #define SHA512_NOINLINE __declspec(noinline)
+#elif defined(__GNUC__)
+    #define SHA512_NOINLINE __attribute__((noinline))
+#else
+    #define SHA512_NOINLINE
+#endif
+
+#ifdef WOLFSSL_SHA512
+
+#if !defined(NO_OLD_SHA_NAMES)
+    #define SHA512             WC_SHA512
+#endif
+
+#if !defined(NO_OLD_WC_NAMES)
     #define Sha512             wc_Sha512
-    #define SHA512             WC_SHA512
     #define SHA512_BLOCK_SIZE  WC_SHA512_BLOCK_SIZE
     #define SHA512_DIGEST_SIZE WC_SHA512_DIGEST_SIZE
@@ -68,7 +95,11 @@
 #endif
 
+#endif /* WOLFSSL_SHA512 */
+
 /* in bytes */
 enum {
-    WC_SHA512              =   4,   /* hash type unique */
+#ifdef WOLFSSL_SHA512
+    WC_SHA512              =   WC_HASH_TYPE_SHA512,
+#endif
     WC_SHA512_BLOCK_SIZE   = 128,
     WC_SHA512_DIGEST_SIZE  =  64,
@@ -77,22 +108,35 @@
 
 
+#ifdef WOLFSSL_IMX6_CAAM
+    #include "wolfssl/wolfcrypt/port/caam/wolfcaam_sha.h"
+#else
 /* wc_Sha512 digest */
 typedef struct wc_Sha512 {
+    word64  digest[WC_SHA512_DIGEST_SIZE / sizeof(word64)];
+    word64  buffer[WC_SHA512_BLOCK_SIZE  / sizeof(word64)];
     word32  buffLen;   /* in bytes          */
     word64  loLen;     /* length in bytes   */
     word64  hiLen;     /* length in bytes   */
-    word64  digest[WC_SHA512_DIGEST_SIZE / sizeof(word64)];
-    word64  buffer[WC_SHA512_BLOCK_SIZE  / sizeof(word64)];
     void*   heap;
+#ifdef USE_INTEL_SPEEDUP
+    const byte* data;
+#endif
 #ifdef WOLFSSL_ASYNC_CRYPT
     WC_ASYNC_DEV asyncDev;
 #endif /* WOLFSSL_ASYNC_CRYPT */
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+    word64* W;
+#endif
 } wc_Sha512;
+#endif
 
 #endif /* HAVE_FIPS */
+
+#ifdef WOLFSSL_SHA512
 
 WOLFSSL_API int wc_InitSha512(wc_Sha512*);
 WOLFSSL_API int wc_InitSha512_ex(wc_Sha512*, void*, int);
 WOLFSSL_API int wc_Sha512Update(wc_Sha512*, const byte*, word32);
+WOLFSSL_API int wc_Sha512FinalRaw(wc_Sha512*, byte*);
 WOLFSSL_API int wc_Sha512Final(wc_Sha512*, byte*);
 WOLFSSL_API void wc_Sha512Free(wc_Sha512*);
@@ -101,11 +145,18 @@
 WOLFSSL_API int wc_Sha512Copy(wc_Sha512* src, wc_Sha512* dst);
 
+#endif /* WOLFSSL_SHA512 */
+
 #if defined(WOLFSSL_SHA384)
 
-#ifndef HAVE_FIPS /* avoid redefinition of structs */
+/* avoid redefinition of structs */
+#if !defined(HAVE_FIPS) || \
+    (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))
 
-#ifndef NO_OLD_WC_NAMES
+#if !defined(NO_OLD_SHA_NAMES)
+    #define SHA384             WC_SHA384
+#endif
+
+#if !defined(NO_OLD_WC_NAMES)
     #define Sha384             wc_Sha384
-    #define SHA384             WC_SHA384
     #define SHA384_BLOCK_SIZE  WC_SHA384_BLOCK_SIZE
     #define SHA384_DIGEST_SIZE WC_SHA384_DIGEST_SIZE
@@ -115,9 +166,10 @@
 /* in bytes */
 enum {
-    WC_SHA384              =   5,   /* hash type unique */
+    WC_SHA384              =   WC_HASH_TYPE_SHA384,
     WC_SHA384_BLOCK_SIZE   =   WC_SHA512_BLOCK_SIZE,
     WC_SHA384_DIGEST_SIZE  =   48,
     WC_SHA384_PAD_SIZE     =   WC_SHA512_PAD_SIZE
 };
+
 
 typedef wc_Sha512 wc_Sha384;
@@ -127,4 +179,5 @@
 WOLFSSL_API int wc_InitSha384_ex(wc_Sha384*, void*, int);
 WOLFSSL_API int wc_Sha384Update(wc_Sha384*, const byte*, word32);
+WOLFSSL_API int wc_Sha384FinalRaw(wc_Sha384*, byte*);
 WOLFSSL_API int wc_Sha384Final(wc_Sha384*, byte*);
 WOLFSSL_API void wc_Sha384Free(wc_Sha384*);
@@ -139,5 +192,5 @@
 #endif
 
-#endif /* WOLFSSL_SHA512 */
+#endif /* WOLFSSL_SHA512 || WOLFSSL_SHA384 */
 #endif /* WOLF_CRYPT_SHA512_H */
 
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/types.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/types.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/types.h	(revision 372)
@@ -20,5 +20,7 @@
  */
 
-
+/*!
+    \file wolfssl/wolfcrypt/types.h
+*/
 
 #ifndef WOLF_CRYPT_TYPES_H
@@ -52,8 +54,9 @@
 
 	/* try to set SIZEOF_LONG or LONG_LONG if user didn't */
-	#if !defined(_MSC_VER) && !defined(__BCPLUSPLUS__)
+    #if !defined(_MSC_VER) && !defined(__BCPLUSPLUS__) && !defined(__EMSCRIPTEN__)
 	    #if !defined(SIZEOF_LONG_LONG) && !defined(SIZEOF_LONG)
-	        #if (defined(__alpha__) || defined(__ia64__) || defined(_ARCH_PPC64) \
-	                || defined(__mips64)  || defined(__x86_64__) || \
+            #if (defined(__alpha__) || defined(__ia64__) || \
+                defined(_ARCH_PPC64) || defined(__mips64) || \
+                defined(__x86_64__) || \
                     ((defined(sun) || defined(__sun)) && \
                      (defined(LP64) || defined(_LP64))))
@@ -67,9 +70,12 @@
 	#endif
 
-
 	#if defined(_MSC_VER) || defined(__BCPLUSPLUS__)
 	    #define WORD64_AVAILABLE
 	    #define W64LIT(x) x##ui64
 	    typedef unsigned __int64 word64;
+    #elif defined(__EMSCRIPTEN__)
+        #define WORD64_AVAILABLE
+        #define W64LIT(x) x##ull
+        typedef unsigned long long word64;
 	#elif defined(SIZEOF_LONG) && SIZEOF_LONG == 8
 	    #define WORD64_AVAILABLE
@@ -84,10 +90,7 @@
 	    #define W64LIT(x) x##LL
 	    typedef unsigned long long word64;
-	#else
-	    #define MP_16BIT  /* for mp_int, mp_word needs to be twice as big as
-	                         mp_digit, no 64 bit type so make mp_digit 16 bit */
-	#endif
-
-
+	#endif
+
+#if !defined(NO_64BIT) && defined(WORD64_AVAILABLE)
 	/* These platforms have 64-bit CPU registers.  */
 	#if (defined(__alpha__) || defined(__ia64__) || defined(_ARCH_PPC64) || \
@@ -100,5 +103,5 @@
         /* LP64 with GNU GCC compiler is reserved for when long int is 64 bits
          * and int uses 32 bits. When using Solaris Studio sparc and __sparc are
-         * avialable for 32 bit detection but __sparc64__ could be missed. This
+         * available for 32 bit detection but __sparc64__ could be missed. This
          * uses LP64 for checking 64 bit CPU arch. */
 	    typedef word64 wolfssl_word;
@@ -110,5 +113,10 @@
 	    #endif
 	#endif
-
+#else
+        #undef WORD64_AVAILABLE
+        typedef word32 wolfssl_word;
+        #define MP_16BIT  /* for mp_int, mp_word needs to be twice as big as
+                             mp_digit, no 64 bit type so make mp_digit 16 bit */
+#endif
 
 	enum {
@@ -121,24 +129,28 @@
 
 	/* use inlining if compiler allows */
-	#ifndef INLINE
+    #ifndef WC_INLINE
 	#ifndef NO_INLINE
 	    #ifdef _MSC_VER
-	        #define INLINE __inline
+            #define WC_INLINE __inline
 	    #elif defined(__GNUC__)
                #ifdef WOLFSSL_VXWORKS
-                   #define INLINE __inline__
+                   #define WC_INLINE __inline__
                #else
-                   #define INLINE inline
+                   #define WC_INLINE inline
                #endif
 	    #elif defined(__IAR_SYSTEMS_ICC__)
-	        #define INLINE inline
+            #define WC_INLINE inline
 	    #elif defined(THREADX)
-	        #define INLINE _Inline
+            #define WC_INLINE _Inline
 	    #else
-	        #define INLINE
+            #define WC_INLINE
 	    #endif
 	#else
-	    #define INLINE
-	#endif
+        #define WC_INLINE
+    #endif
+	#endif
+
+    #if defined(HAVE_FIPS) || defined(HAVE_SELFTEST)
+        #define INLINE WC_INLINE
 	#endif
 
@@ -164,5 +176,5 @@
 	        #define THREAD_LS_T __declspec(thread)
 	    /* Thread local storage only in FreeRTOS v8.2.1 and higher */
-	    #elif defined(FREERTOS)
+        #elif defined(FREERTOS) || defined(FREERTOS_TCP)
 	        #define THREAD_LS_T
 	    #else
@@ -176,5 +188,5 @@
     #if defined(__GNUC__)
         #if ((__GNUC__ > 7) || ((__GNUC__ == 7) && (__GNUC_MINOR__ >= 1)))
-            #define FALL_THROUGH __attribute__ ((fallthrough));
+            #define FALL_THROUGH __attribute__ ((fallthrough))
         #endif
     #endif
@@ -194,5 +206,5 @@
 	/* default to libc stuff */
 	/* XREALLOC is used once in normal math lib, not in fast math lib */
-	/* XFREE on some embeded systems doesn't like free(0) so test  */
+    /* XFREE on some embedded systems doesn't like free(0) so test  */
 	#if defined(HAVE_IO_POOL)
 		WOLFSSL_API void* XMALLOC(size_t n, void* heap, int type);
@@ -217,4 +229,18 @@
 	    extern void *XREALLOC(void *p, size_t n, void* heap, int type);
 	    extern void XFREE(void *p, void* heap, int type);
+    #elif defined(WOLFSSL_MEMORY_LOG)
+        #define XMALLOC(n, h, t)        xmalloc(n, h, t, __func__, __FILE__, __LINE__)
+        #define XREALLOC(p, n, h, t)    xrealloc(p, n, h, t, __func__,  __FILE__, __LINE__)
+        #define XFREE(p, h, t)          xfree(p, h, t, __func__, __FILE__, __LINE__)
+
+        /* prototypes for user heap override functions */
+        #include <stddef.h>  /* for size_t */
+        #include <stdlib.h>
+        extern void *xmalloc(size_t n, void* heap, int type, const char* func,
+              const char* file, unsigned int line);
+        extern void *xrealloc(void *p, size_t n, void* heap, int type,
+              const char* func, const char* file, unsigned int line);
+        extern void xfree(void *p, void* heap, int type, const char* func,
+              const char* file, unsigned int line);
     #elif defined(XMALLOC_OVERRIDE)
         /* override the XMALLOC, XFREE and XREALLOC macros */
@@ -228,6 +254,5 @@
 	        && !defined(WOLFSSL_SAFERTOS) && !defined(FREESCALE_MQX) \
 	        && !defined(FREESCALE_KSDK_MQX) && !defined(FREESCALE_FREE_RTOS) \
-            && !defined(WOLFSSL_LEANPSK) && !defined(FREERTOS) && !defined(FREERTOS_TCP)\
-            && !defined(WOLFSSL_uITRON4)
+            && !defined(WOLFSSL_LEANPSK) && !defined(WOLFSSL_uITRON4)
 	    /* default C runtime, can install different routines at runtime via cbs */
 	    #include <wolfssl/wolfcrypt/memory.h>
@@ -242,5 +267,5 @@
 				#define XREALLOC(p, n, h, t) wolfSSL_Realloc((p), (n), (h), (t))
             #endif /* WOLFSSL_DEBUG_MEMORY */
-        #else
+        #elif !defined(FREERTOS) && !defined(FREERTOS_TCP)
             #ifdef WOLFSSL_DEBUG_MEMORY
 				#define XMALLOC(s, h, t)     ((void)h, (void)t, wolfSSL_Malloc((s), __func__, __LINE__))
@@ -258,8 +283,8 @@
     #ifdef WOLFSSL_ASYNC_CRYPT
         #define DECLARE_VAR(VAR_NAME, VAR_TYPE, VAR_SIZE, HEAP) \
-            VAR_TYPE* VAR_NAME = (VAR_TYPE*)XMALLOC(sizeof(VAR_TYPE) * VAR_SIZE, HEAP, DYNAMIC_TYPE_WOLF_BIGINT);
+            VAR_TYPE* VAR_NAME = (VAR_TYPE*)XMALLOC(sizeof(VAR_TYPE) * VAR_SIZE, (HEAP), DYNAMIC_TYPE_WOLF_BIGINT);
         #define DECLARE_VAR_INIT(VAR_NAME, VAR_TYPE, VAR_SIZE, INIT_VALUE, HEAP) \
             VAR_TYPE* VAR_NAME = ({ \
-                VAR_TYPE* ptr = (VAR_TYPE*)XMALLOC(sizeof(VAR_TYPE) * VAR_SIZE, HEAP, DYNAMIC_TYPE_WOLF_BIGINT); \
+                VAR_TYPE* ptr = (VAR_TYPE*)XMALLOC(sizeof(VAR_TYPE) * VAR_SIZE, (HEAP), DYNAMIC_TYPE_WOLF_BIGINT); \
                 if (ptr && INIT_VALUE) { \
                     XMEMCPY(ptr, INIT_VALUE, sizeof(VAR_TYPE) * VAR_SIZE); \
@@ -271,11 +296,11 @@
             int idx##VAR_NAME; \
             for (idx##VAR_NAME=0; idx##VAR_NAME<VAR_ITEMS; idx##VAR_NAME++) { \
-                VAR_NAME[idx##VAR_NAME] = (VAR_TYPE*)XMALLOC(VAR_SIZE, HEAP, DYNAMIC_TYPE_WOLF_BIGINT); \
+                VAR_NAME[idx##VAR_NAME] = (VAR_TYPE*)XMALLOC(VAR_SIZE, (HEAP), DYNAMIC_TYPE_WOLF_BIGINT); \
             }
         #define FREE_VAR(VAR_NAME, HEAP) \
-            XFREE(VAR_NAME, HEAP, DYNAMIC_TYPE_WOLF_BIGINT);
+            XFREE(VAR_NAME, (HEAP), DYNAMIC_TYPE_WOLF_BIGINT);
         #define FREE_ARRAY(VAR_NAME, VAR_ITEMS, HEAP) \
             for (idx##VAR_NAME=0; idx##VAR_NAME<VAR_ITEMS; idx##VAR_NAME++) { \
-                XFREE(VAR_NAME[idx##VAR_NAME], HEAP, DYNAMIC_TYPE_WOLF_BIGINT); \
+                XFREE(VAR_NAME[idx##VAR_NAME], (HEAP), DYNAMIC_TYPE_WOLF_BIGINT); \
             }
     #else
@@ -290,6 +315,11 @@
     #endif
 
-    #ifndef WOLFSSL_LEANPSK
-	    char* mystrnstr(const char* s1, const char* s2, unsigned int n);
+    #if !defined(USE_WOLF_STRTOK) && \
+            ((defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)) || \
+             defined(WOLFSSL_TIRTOS) || defined(WOLF_C99))
+        #define USE_WOLF_STRTOK
+    #endif
+    #if !defined(USE_WOLF_STRSEP) && (defined(WOLF_C99))
+        #define USE_WOLF_STRSEP
     #endif
 
@@ -310,15 +340,32 @@
 	    #define XSTRNCAT(s1,s2,n) strncat((s1),(s2),(n))
 
-        #ifdef MICROCHIP_PIC32
+        #ifdef USE_WOLF_STRSEP
+            #define XSTRSEP(s1,d) wc_strsep((s1),(d))
+        #else
+            #define XSTRSEP(s1,d) strsep((s1),(d))
+        #endif
+
+        #if defined(MICROCHIP_PIC32) || defined(WOLFSSL_TIRTOS)
             /* XC32 does not support strncasecmp, so use case sensitive one */
             #define XSTRNCASECMP(s1,s2,n) strncmp((s1),(s2),(n))
-        #elif defined(USE_WINDOWS_API)
+        #elif defined(USE_WINDOWS_API) || defined(FREERTOS_TCP_WINSIM)
 	        #define XSTRNCASECMP(s1,s2,n) _strnicmp((s1),(s2),(n))
         #else
+            #if defined(HAVE_STRINGS_H) && defined(WOLF_C99) && \
+                !defined(WOLFSSL_SGX)
+                #include <strings.h>
+            #endif
 	        #define XSTRNCASECMP(s1,s2,n) strncasecmp((s1),(s2),(n))
 	    #endif
 
-        /* snprintf is used in asn.c for GetTimeString and PKCS7 test */
+        /* snprintf is used in asn.c for GetTimeString, PKCS7 test, and when
+           debugging is turned on */
         #ifndef USE_WINDOWS_API
+            #if defined(NO_FILESYSTEM) && (defined(OPENSSL_EXTRA) || \
+                   defined(HAVE_PKCS7)) && !defined(NO_STDIO_FILESYSTEM)
+                /* case where stdio is not included else where but is needed for
+                 * snprintf */
+                #include <stdio.h>
+            #endif
             #define XSNPRINTF snprintf
         #else
@@ -328,21 +375,33 @@
         #if defined(WOLFSSL_CERT_EXT) || defined(HAVE_ALPN)
             /* use only Thread Safe version of strtok */
-            #if !defined(USE_WINDOWS_API) && !defined(INTIME_RTOS)
-                #define XSTRTOK strtok_r
-            #elif defined(__MINGW32__) || defined(WOLFSSL_TIRTOS) || \
-                    defined(USE_WOLF_STRTOK)
-                #ifndef USE_WOLF_STRTOK
-                    #define USE_WOLF_STRTOK
-                #endif
-                #define XSTRTOK wc_strtok
+            #if defined(USE_WOLF_STRTOK)
+                #define XSTRTOK(s1,d,ptr) wc_strtok((s1),(d),(ptr))
+            #elif defined(USE_WINDOWS_API) || defined(INTIME_RTOS)
+                #define XSTRTOK(s1,d,ptr) strtok_s((s1),(d),(ptr))
             #else
-                #define XSTRTOK strtok_s
+                #define XSTRTOK(s1,d,ptr) strtok_r((s1),(d),(ptr))
             #endif
         #endif
-	#endif
+    #endif
+
+    #ifdef USE_WOLF_STRTOK
+        WOLFSSL_API char* wc_strtok(char *str, const char *delim, char **nextp);
+            #endif
+    #ifdef USE_WOLF_STRSEP
+        WOLFSSL_API char* wc_strsep(char **stringp, const char *delim);
+        #endif
+
+    #if !defined(NO_FILESYSTEM) && defined(OPENSSL_EXTRA) && \
+        !defined(NO_STDIO_FILESYSTEM)
+        #ifndef XGETENV
+            #include <stdlib.h>
+            #define XGETENV getenv
+	#endif
+    #endif /* OPENSSL_EXTRA */
 
 	#ifndef CTYPE_USER
 	    #include <ctype.h>
-	    #if defined(HAVE_ECC) || defined(HAVE_OCSP) || defined(WOLFSSL_KEY_GEN)
+        #if defined(HAVE_ECC) || defined(HAVE_OCSP) || \
+            defined(WOLFSSL_KEY_GEN) || !defined(NO_DSA)
 	        #define XTOUPPER(c)     toupper((c))
 	        #define XISALPHA(c)     isalpha((c))
@@ -438,15 +497,17 @@
         DYNAMIC_TYPE_HASHCTX      = 82,
         DYNAMIC_TYPE_SEED         = 83,
-        DYNAMIC_TYPE_SYMETRIC_KEY = 84,
+        DYNAMIC_TYPE_SYMMETRIC_KEY= 84,
         DYNAMIC_TYPE_ECC_BUFFER   = 85,
         DYNAMIC_TYPE_QSH          = 86,
         DYNAMIC_TYPE_SALT         = 87,
         DYNAMIC_TYPE_HASH_TMP     = 88,
+        DYNAMIC_TYPE_BLOB         = 89,
+        DYNAMIC_TYPE_NAME_ENTRY   = 90,
 	};
 
 	/* max error buffer string size */
-	enum {
-	    WOLFSSL_MAX_ERROR_SZ = 80
-	};
+    #ifndef WOLFSSL_MAX_ERROR_SZ
+        #define WOLFSSL_MAX_ERROR_SZ 80
+    #endif
 
 	/* stack protection */
@@ -455,4 +516,91 @@
 	};
 
+
+    /* Algorithm Types */
+    enum wc_AlgoType {
+        WC_ALGO_TYPE_NONE = 0,
+        WC_ALGO_TYPE_HASH = 1,
+        WC_ALGO_TYPE_CIPHER = 2,
+        WC_ALGO_TYPE_PK = 3,
+
+        WC_ALGO_TYPE_MAX = WC_ALGO_TYPE_PK
+    };
+
+    /* hash types */
+    enum wc_HashType {
+    #if defined(HAVE_SELFTEST) || defined(HAVE_FIPS)
+        /* In selftest build, WC_* types are not mapped to WC_HASH_TYPE types.
+         * Values here are based on old selftest hmac.h enum, with additions */
+        WC_HASH_TYPE_NONE = 15,
+        WC_HASH_TYPE_MD2 = 16,
+        WC_HASH_TYPE_MD4 = 17,
+        WC_HASH_TYPE_MD5 = 0,
+        WC_HASH_TYPE_SHA = 1, /* SHA-1 (not old SHA-0) */
+        WC_HASH_TYPE_SHA224 = 8,
+        WC_HASH_TYPE_SHA256 = 2,
+        WC_HASH_TYPE_SHA384 = 5,
+        WC_HASH_TYPE_SHA512 = 4,
+        WC_HASH_TYPE_MD5_SHA = 18,
+        WC_HASH_TYPE_SHA3_224 = 10,
+        WC_HASH_TYPE_SHA3_256 = 11,
+        WC_HASH_TYPE_SHA3_384 = 12,
+        WC_HASH_TYPE_SHA3_512 = 13,
+        WC_HASH_TYPE_BLAKE2B = 14,
+
+        WC_HASH_TYPE_MAX = WC_HASH_TYPE_MD5_SHA
+    #else
+        WC_HASH_TYPE_NONE = 0,
+        WC_HASH_TYPE_MD2 = 1,
+        WC_HASH_TYPE_MD4 = 2,
+        WC_HASH_TYPE_MD5 = 3,
+        WC_HASH_TYPE_SHA = 4, /* SHA-1 (not old SHA-0) */
+        WC_HASH_TYPE_SHA224 = 5,
+        WC_HASH_TYPE_SHA256 = 6,
+        WC_HASH_TYPE_SHA384 = 7,
+        WC_HASH_TYPE_SHA512 = 8,
+        WC_HASH_TYPE_MD5_SHA = 9,
+        WC_HASH_TYPE_SHA3_224 = 10,
+        WC_HASH_TYPE_SHA3_256 = 11,
+        WC_HASH_TYPE_SHA3_384 = 12,
+        WC_HASH_TYPE_SHA3_512 = 13,
+        WC_HASH_TYPE_BLAKE2B = 14,
+
+        WC_HASH_TYPE_MAX = WC_HASH_TYPE_BLAKE2B
+    #endif /* HAVE_SELFTEST */
+    };
+
+    /* cipher types */
+    enum wc_CipherType {
+        WC_CIPHER_NONE = 0,
+        WC_CIPHER_AES = 1,
+        WC_CIPHER_AES_CBC = 2,
+        WC_CIPHER_AES_GCM = 3,
+        WC_CIPHER_AES_CTR = 4,
+        WC_CIPHER_AES_XTS = 5,
+        WC_CIPHER_AES_CFB = 6,
+        WC_CIPHER_DES3 = 7,
+        WC_CIPHER_DES = 8,
+        WC_CIPHER_CHACHA = 9,
+        WC_CIPHER_HC128 = 10,
+        WC_CIPHER_IDEA = 11,
+
+        WC_CIPHER_MAX = WC_CIPHER_HC128
+    };
+
+    /* PK=public key (asymmetric) based algorithms */
+    enum wc_PkType {
+        WC_PK_TYPE_NONE = 0,
+        WC_PK_TYPE_RSA = 1,
+        WC_PK_TYPE_DH = 2,
+        WC_PK_TYPE_ECDH = 3,
+        WC_PK_TYPE_ECDSA_SIGN = 4,
+        WC_PK_TYPE_ECDSA_VERIFY = 5,
+        WC_PK_TYPE_ED25519 = 6,
+        WC_PK_TYPE_CURVE25519 = 7,
+        WC_PK_TYPE_RSA_KEYGEN = 8,
+        WC_PK_TYPE_EC_KEYGEN = 9,
+
+        WC_PK_TYPE_MAX = WC_PK_TYPE_EC_KEYGEN
+    };
 
 
@@ -582,4 +730,34 @@
     #endif
 
+
+    #if defined(__GNUC__)
+        #define WOLFSSL_PACK __attribute__ ((packed))
+    #else
+        #define WOLFSSL_PACK
+    #endif
+
+    #ifndef __GNUC_PREREQ
+        #if defined(__GNUC__) && defined(__GNUC_MINOR__)
+            #define __GNUC_PREREQ(maj, min) \
+                ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+        #else
+            #define __GNUC_PREREQ(maj, min) (0) /* not GNUC */
+        #endif
+    #endif
+
+    #if defined(__GNUC__)
+        #define WC_NORETURN __attribute__((noreturn))
+    #else
+        #define WC_NORETURN
+    #endif
+
+    #if defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) || \
+        defined(WOLFSSL_DEBUG_MATH) || defined(DEBUG_WOLFSSL) || \
+        defined(WOLFSSL_PUBLIC_MP) || defined(OPENSSL_EXTRA) || \
+            (defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT))
+        #undef  WC_MP_TO_RADIX
+        #define WC_MP_TO_RADIX
+    #endif
+
 	#ifdef __cplusplus
 	    }   /* extern "C" */
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/visibility.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/visibility.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/visibility.h	(revision 372)
@@ -28,5 +28,8 @@
 
 /* for compatibility and so that fips is using same name of macro @wc_fips */
-#ifdef HAVE_FIPS
+/* The following visibility wrappers are for old FIPS. New FIPS should use
+ * the same as a non-FIPS build. */
+#if defined(HAVE_FIPS) && \
+    (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))
     #include <cyassl/ctaocrypt/visibility.h>
     #define WOLFSSL_API   CYASSL_API
@@ -41,11 +44,5 @@
 
 #if defined(BUILDING_WOLFSSL)
-    #if defined(HAVE_VISIBILITY) && HAVE_VISIBILITY
-        #define WOLFSSL_API   __attribute__ ((visibility("default")))
-        #define WOLFSSL_LOCAL __attribute__ ((visibility("hidden")))
-    #elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
-        #define WOLFSSL_API   __global
-        #define WOLFSSL_LOCAL __hidden
-    #elif defined(_MSC_VER) || defined(__MINGW32__)
+    #if defined(_MSC_VER) || defined(__MINGW32__)
         #if defined(WOLFSSL_DLL)
             #define WOLFSSL_API __declspec(dllexport)
@@ -54,4 +51,10 @@
         #endif
         #define WOLFSSL_LOCAL
+    #elif defined(HAVE_VISIBILITY) && HAVE_VISIBILITY
+        #define WOLFSSL_API   __attribute__ ((visibility("default")))
+        #define WOLFSSL_LOCAL __attribute__ ((visibility("hidden")))
+    #elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+        #define WOLFSSL_API   __global
+        #define WOLFSSL_LOCAL __hidden
     #else
         #define WOLFSSL_API
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/wc_encrypt.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/wc_encrypt.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/wc_encrypt.h	(revision 372)
@@ -20,4 +20,7 @@
  */
 
+/*!
+    \file wolfssl/wolfcrypt/wc_encrypt.h
+*/
 
 
@@ -26,4 +29,8 @@
 
 #include <wolfssl/wolfcrypt/types.h>
+#include <wolfssl/wolfcrypt/aes.h>
+#include <wolfssl/wolfcrypt/chacha.h>
+#include <wolfssl/wolfcrypt/des3.h>
+#include <wolfssl/wolfcrypt/arc4.h>
 
 #ifdef __cplusplus
@@ -31,5 +38,19 @@
 #endif
 
+/* determine max cipher key size */
 #ifndef NO_AES
+    #define WC_MAX_SYM_KEY_SIZE     (AES_MAX_KEY_SIZE/8)
+#elif defined(HAVE_CHACHA)
+    #define WC_MAX_SYM_KEY_SIZE     CHACHA_MAX_KEY_SZ
+#elif !defined(NO_DES3)
+    #define WC_MAX_SYM_KEY_SIZE     DES3_KEY_SIZE
+#elif !defined(NO_RC4)
+    #define WC_MAX_SYM_KEY_SIZE     RC4_KEY_SIZE
+#else
+    #define WC_MAX_SYM_KEY_SIZE     32
+#endif
+
+
+#if !defined(NO_AES) && defined(HAVE_AES_CBC)
 WOLFSSL_API int  wc_AesCbcEncryptWithKey(byte* out, const byte* in, word32 inSz,
                                          const byte* key, word32 keySz,
@@ -56,4 +77,21 @@
 #endif /* !NO_DES3 */
 
+
+
+
+#ifdef WOLFSSL_ENCRYPTED_KEYS
+    struct EncryptedInfo;
+    WOLFSSL_API int wc_BufferKeyDecrypt(struct EncryptedInfo* info, byte* der, word32 derSz,
+        const byte* password, int passwordSz, int hashType);
+    WOLFSSL_API int wc_BufferKeyEncrypt(struct EncryptedInfo* info, byte* der, word32 derSz,
+        const byte* password, int passwordSz, int hashType);
+#endif /* WOLFSSL_ENCRYPTED_KEYS */
+
+#ifndef NO_PWDBASED
+    WOLFSSL_LOCAL int wc_CryptKey(const char* password, int passwordSz, 
+        byte* salt, int saltSz, int iterations, int id, byte* input, int length,
+        int version, byte* cbcIv, int enc);
+#endif
+
 #ifdef __cplusplus
     }  /* extern "C" */
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/wc_port.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/wc_port.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/wc_port.h	(revision 372)
@@ -20,5 +20,7 @@
  */
 
-
+/*!
+    \file wolfssl/wolfcrypt/wc_port.h
+*/
 
 #ifndef WOLF_CRYPT_PORT_H
@@ -32,4 +34,12 @@
 #endif
 
+/* Detect if compiler supports C99. "NO_WOLF_C99" can be defined in
+ * user_settings.h to disable checking for C99 support. */
+#if !defined(WOLF_C99) && defined(__STDC_VERSION__) && \
+    !defined(WOLFSSL_ARDUINO) && !defined(NO_WOLF_C99)
+    #if __STDC_VERSION__ >= 199901L
+        #define WOLF_C99
+    #endif
+#endif
 
 #ifdef USE_WINDOWS_API
@@ -65,4 +75,6 @@
 #elif defined(FREESCALE_FREE_RTOS)
     #include "fsl_os_abstraction.h"
+#elif defined(WOLFSSL_VXWORKS)
+    #include <semLib.h>
 #elif defined(WOLFSSL_uITRON4)
     #include "stddef.h"
@@ -70,4 +82,6 @@
 #elif  defined(WOLFSSL_uTKERNEL2)
     #include "tk/tkernel.h"
+#elif defined(WOLFSSL_CMSIS_RTOS)
+    #include "cmsis_os.h"
 #elif defined(WOLFSSL_MDK_ARM)
     #if defined(WOLFSSL_MDK5)
@@ -86,4 +100,11 @@
     #include <rt.h>
     #include <io.h>
+#elif defined(WOLFSSL_NUCLEUS_1_2)
+    /* NU_DEBUG needed struct access in nucleus_realloc */
+    #define NU_DEBUG
+    #include "plus/nucleus.h"
+    #include "nucleus.h"
+#elif defined(WOLFSSL_APACHE_MYNEWT)
+    /* do nothing */
 #else
     #ifndef SINGLE_THREADED
@@ -133,4 +154,6 @@
     #elif defined(FREESCALE_FREE_RTOS)
         typedef mutex_t wolfSSL_Mutex;
+    #elif defined(WOLFSSL_VXWORKS)
+        typedef SEM_ID wolfSSL_Mutex;
     #elif defined(WOLFSSL_uITRON4)
         typedef struct wolfSSL_Mutex {
@@ -157,4 +180,6 @@
     #elif defined(INTIME_RTOS)
         typedef RTHANDLE wolfSSL_Mutex;
+    #elif defined(WOLFSSL_NUCLEUS_1_2)
+        typedef NU_SEMAPHORE wolfSSL_Mutex;
     #else
         #error Need a mutex type in multithreaded mode
@@ -185,5 +210,5 @@
     #define wolfSSL_CryptHwMutexInit()      0 /* Success */
     #define wolfSSL_CryptHwMutexLock()      0 /* Success */
-    #define wolfSSL_CryptHwMutexUnLock()    0 /* Success */
+    #define wolfSSL_CryptHwMutexUnLock()    (void)0 /* Success */
 #endif /* WOLFSSL_CRYPT_HW_MUTEX */
 
@@ -194,4 +219,11 @@
 WOLFSSL_API int wc_LockMutex(wolfSSL_Mutex*);
 WOLFSSL_API int wc_UnLockMutex(wolfSSL_Mutex*);
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+/* dynamiclly set which mutex to use. unlock / lock is controlled by flag */
+typedef void (mutex_cb)(int flag, int type, const char* file, int line);
+
+WOLFSSL_API int wc_LockMutex_ex(int flag, int type, const char* file, int line);
+WOLFSSL_API int wc_SetMutexCb(mutex_cb* cb);
+#endif
 
 /* main crypto initialization function */
@@ -255,4 +287,32 @@
     #define XBADFILE   NULL
     #define XFGETS(b,s,f) -2 /* Not ported yet */
+#elif defined(WOLFSSL_NUCLEUS_1_2)
+    #include "fal/inc/fal.h"
+    #define XFILE      FILE*
+    #define XFOPEN     fopen
+    #define XFSEEK     fseek
+    #define XFTELL     ftell
+    #define XREWIND    rewind
+    #define XFREAD     fread
+    #define XFWRITE    fwrite
+    #define XFCLOSE    fclose
+    #define XSEEK_END  PSEEK_END
+    #define XBADFILE   NULL
+#elif defined(WOLFSSL_APACHE_MYNEWT)
+    #include <fs/fs.h>
+    #define XFILE  struct fs_file*
+
+    #define XFOPEN     mynewt_fopen
+    #define XFSEEK     mynewt_fseek
+    #define XFTELL     mynewt_ftell
+    #define XREWIND    mynewt_rewind
+    #define XFREAD     mynewt_fread
+    #define XFWRITE    mynewt_fwrite
+    #define XFCLOSE    mynewt_fclose
+    #define XSEEK_END  2
+    #define XBADFILE   NULL
+    #define XFGETS(b,s,f) -2 /* Not ported yet */
+#elif defined(WOLFSSL_USER_FILESYSTEM)
+    /* To be defined in user_settings.h */
 #else
     /* stdio, default case */
@@ -275,5 +335,6 @@
     #define XFGETS     fgets
 
-    #if !defined(USE_WINDOWS_API) && !defined(NO_WOLFSSL_DIR)
+    #if !defined(USE_WINDOWS_API) && !defined(NO_WOLFSSL_DIR)\
+        && !defined(WOLFSSL_NUCLEUS) && !defined(WOLFSSL_NUCLEUS_1_2)
         #include <dirent.h>
         #include <unistd.h>
@@ -289,5 +350,6 @@
     #endif
 
-#if !defined(NO_WOLFSSL_DIR)
+#if !defined(NO_WOLFSSL_DIR) && !defined(WOLFSSL_NUCLEUS) && \
+    !defined(WOLFSSL_NUCLEUS_1_2)
     typedef struct ReadDirCtx {
     #ifdef USE_WINDOWS_API
@@ -302,4 +364,6 @@
     } ReadDirCtx;
 
+    #define WC_READDIR_NOFILE -1
+
     WOLFSSL_API int wc_ReadDirFirst(ReadDirCtx* ctx, const char* path, char** name);
     WOLFSSL_API int wc_ReadDirNext(ReadDirCtx* ctx, const char* path, char** name);
@@ -308,8 +372,4 @@
 
 #endif /* !NO_FILESYSTEM */
-
-#ifdef USE_WOLF_STRTOK
-    WOLFSSL_LOCAL char* wc_strtok(char *str, const char *delim, char **nextp);
-#endif
 
 /* Windows API defines its own min() macro. */
@@ -323,4 +383,193 @@
 #endif /* USE_WINDOWS_API */
 
+/* Time functions */
+#ifndef NO_ASN_TIME
+#if defined(USER_TIME)
+    /* Use our gmtime and time_t/struct tm types.
+       Only needs seconds since EPOCH using XTIME function.
+       time_t XTIME(time_t * timer) {}
+    */
+    #define WOLFSSL_GMTIME
+    #define USE_WOLF_TM
+    #define USE_WOLF_TIME_T
+
+#elif defined(TIME_OVERRIDES)
+    /* Override XTIME() and XGMTIME() functionality.
+       Requires user to provide these functions:
+        time_t XTIME(time_t * timer) {}
+        struct tm* XGMTIME(const time_t* timer, struct tm* tmp) {}
+    */
+    #ifndef HAVE_TIME_T_TYPE
+        #define USE_WOLF_TIME_T
+    #endif
+    #ifndef HAVE_TM_TYPE
+        #define USE_WOLF_TM
+    #endif
+    #define NEED_TMP_TIME
+
+#elif defined(HAVE_RTP_SYS)
+    #include "os.h"           /* dc_rtc_api needs    */
+    #include "dc_rtc_api.h"   /* to get current time */
+
+    /* uses parital <time.h> structures */
+    #define XTIME(tl)       (0)
+    #define XGMTIME(c, t)   rtpsys_gmtime((c))
+
+#elif defined(MICRIUM)
+    #include <clk.h>
+    #include <time.h>
+    #define XTIME(t1)       micrium_time((t1))
+    #define WOLFSSL_GMTIME
+
+#elif defined(MICROCHIP_TCPIP_V5) || defined(MICROCHIP_TCPIP)
+    #include <time.h>
+    #define XTIME(t1)       pic32_time((t1))
+    #define XGMTIME(c, t)   gmtime((c))
+
+#elif defined(FREESCALE_MQX) || defined(FREESCALE_KSDK_MQX)
+    #ifdef FREESCALE_MQX_4_0
+        #include <time.h>
+        extern time_t mqx_time(time_t* timer);
+    #else
+        #define HAVE_GMTIME_R
+    #endif
+    #define XTIME(t1)       mqx_time((t1))
+
+#elif defined(FREESCALE_KSDK_BM) || defined(FREESCALE_FREE_RTOS) || defined(FREESCALE_KSDK_FREERTOS)
+    #include <time.h>
+    #ifndef XTIME
+        /*extern time_t ksdk_time(time_t* timer);*/
+        #define XTIME(t1)   ksdk_time((t1))
+    #endif
+    #define XGMTIME(c, t)   gmtime((c))
+
+#elif defined(WOLFSSL_ATMEL) && defined(WOLFSSL_ATMEL_TIME)
+    #define XTIME(t1)       atmel_get_curr_time_and_date((t1))
+    #define WOLFSSL_GMTIME
+    #define USE_WOLF_TM
+    #define USE_WOLF_TIME_T
+
+#elif defined(IDIRECT_DEV_TIME)
+    /*Gets the timestamp from cloak software owned by VT iDirect
+    in place of time() from <time.h> */
+    #include <time.h>
+    #define XTIME(t1)       idirect_time((t1))
+    #define XGMTIME(c, t)   gmtime((c))
+
+#elif defined(_WIN32_WCE)
+    #include <windows.h>
+    #define XTIME(t1)       windows_time((t1))
+    #define WOLFSSL_GMTIME
+
+#elif defined(WOLFSSL_APACHE_MYNEWT)
+    #include "os/os_time.h"
+    #define XTIME(t1)       mynewt_time((t1))
+    #define WOLFSSL_GMTIME
+    #define USE_WOLF_TM
+    #define USE_WOLF_TIME_T
+#else
+    /* default */
+    /* uses complete <time.h> facility */
+    #include <time.h>
+    #if defined(HAVE_SYS_TIME_H)
+        #include <sys/time.h>
+    #endif
+
+    /* PowerPC time_t is int */
+    #ifdef __PPC__
+        #define TIME_T_NOT_64BIT
+    #endif
+#endif
+
+#ifdef SIZEOF_TIME_T
+    /* check if size of time_t from autoconf is less than 8 bytes (64bits) */
+    #if SIZEOF_TIME_T < 8
+        #undef  TIME_T_NOT_64BIT
+        #define TIME_T_NOT_64BIT
+    #endif
+#endif
+#ifdef TIME_T_NOT_LONG
+    /* one old reference to TIME_T_NOT_LONG in GCC-ARM example README
+     * this keeps support for the old macro name */
+    #undef TIME_T_NOT_64BIT
+    #define TIME_T_NOT_64BIT
+#endif
+
+/* Map default time functions */
+#if !defined(XTIME) && !defined(TIME_OVERRIDES) && !defined(USER_TIME)
+    #define XTIME(tl)       time((tl))
+#endif
+#if !defined(XGMTIME) && !defined(TIME_OVERRIDES)
+    #if defined(WOLFSSL_GMTIME) || !defined(HAVE_GMTIME_R) || defined(WOLF_C99)
+        #define XGMTIME(c, t)   gmtime((c))
+    #else
+        #define XGMTIME(c, t)   gmtime_r((c), (t))
+        #define NEED_TMP_TIME
+    #endif
+#endif
+#if !defined(XVALIDATE_DATE) && !defined(HAVE_VALIDATE_DATE)
+    #define USE_WOLF_VALIDDATE
+    #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t))
+#endif
+
+/* wolf struct tm and time_t */
+#if defined(USE_WOLF_TM)
+    struct tm {
+        int  tm_sec;     /* seconds after the minute [0-60] */
+        int  tm_min;     /* minutes after the hour [0-59] */
+        int  tm_hour;    /* hours since midnight [0-23] */
+        int  tm_mday;    /* day of the month [1-31] */
+        int  tm_mon;     /* months since January [0-11] */
+        int  tm_year;    /* years since 1900 */
+        int  tm_wday;    /* days since Sunday [0-6] */
+        int  tm_yday;    /* days since January 1 [0-365] */
+        int  tm_isdst;   /* Daylight Savings Time flag */
+        long tm_gmtoff;  /* offset from CUT in seconds */
+        char *tm_zone;   /* timezone abbreviation */
+    };
+#endif /* USE_WOLF_TM */
+#if defined(USE_WOLF_TIME_T)
+    typedef long time_t;
+#endif
+#if defined(USE_WOLF_SUSECONDS_T)
+    typedef long suseconds_t;
+#endif
+#if defined(USE_WOLF_TIMEVAL_T)
+    struct timeval
+    {
+        time_t tv_sec;
+        suseconds_t tv_usec;
+    };
+#endif
+
+    /* forward declarations */
+#if defined(USER_TIME)
+    struct tm* gmtime(const time_t* timer);
+    extern time_t XTIME(time_t * timer);
+
+    #ifdef STACK_TRAP
+        /* for stack trap tracking, don't call os gmtime on OS X/linux,
+           uses a lot of stack spce */
+        extern time_t time(time_t * timer);
+        #define XTIME(tl)  time((tl))
+    #endif /* STACK_TRAP */
+
+#elif defined(TIME_OVERRIDES)
+    extern time_t XTIME(time_t * timer);
+    extern struct tm* XGMTIME(const time_t* timer, struct tm* tmp);
+#elif defined(WOLFSSL_GMTIME)
+    struct tm* gmtime(const time_t* timer);
+#endif
+#endif /* NO_ASN_TIME */
+
+#ifndef WOLFSSL_LEANPSK
+    char* mystrnstr(const char* s1, const char* s2, unsigned int n);
+#endif
+
+#ifndef FILE_BUFFER_SIZE
+    #define FILE_BUFFER_SIZE 1024     /* default static file buffer size for input,
+                                    will use dynamic buffer if not big enough */
+#endif
+
 
 #ifdef __cplusplus
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/wolfmath.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/wolfmath.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfcrypt/wolfmath.h	(revision 372)
@@ -52,4 +52,12 @@
     int mp_rand(mp_int* a, int digits, WC_RNG* rng);
 
+    enum {
+        /* format type */
+        WC_TYPE_HEX_STR = 1,
+        WC_TYPE_UNSIGNED_BIN = 2,
+    };
+
+    WOLFSSL_API int wc_export_int(mp_int* mp, byte* buf, word32* len, 
+        word32 keySz, int encType);
 
     #ifdef HAVE_WOLF_BIGINT
@@ -62,4 +70,5 @@
 
         int wc_mp_to_bigint(mp_int* src, WC_BIGINT* dst);
+        int wc_mp_to_bigint_sz(mp_int* src, WC_BIGINT* dst, word32 sz);
         int wc_bigint_to_mp(WC_BIGINT* src, mp_int* dst);
     #endif /* HAVE_WOLF_BIGINT */
Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfio.h
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfio.h	(revision 371)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfssl/wolfio.h	(revision 372)
@@ -20,4 +20,7 @@
  */
 
+/*!
+    \file wolfssl/wolfio.h   
+*/
 
 #ifndef WOLFSSL_IO_H
@@ -28,4 +31,6 @@
 #endif
 
+/* Micrium uses NetSock I/O callbacks in wolfio.c */
+#if !defined(WOLFSSL_USER_IO)
 /* OCSP and CRL_IO require HTTP client */
 #if defined(HAVE_OCSP) || defined(HAVE_CRL_IO)
@@ -34,8 +39,9 @@
     #endif
 #endif
+#endif
 
 #if !defined(WOLFSSL_USER_IO)
     /* Micrium uses NetSock I/O callbacks in wolfio.c */
-    #if !defined(USE_WOLFSSL_IO) && !defined(MICRIUM)
+    #if !defined(USE_WOLFSSL_IO) && !defined(MICRIUM) && !defined(WOLFSSL_CONTIKI)
         #define USE_WOLFSSL_IO
     #endif
@@ -50,10 +56,10 @@
 
 #ifndef USE_WINDOWS_API
-    #ifdef WOLFSSL_LWIP
+    #if defined(WOLFSSL_LWIP) && !defined(WOLFSSL_APACHE_MYNEWT)
         /* lwIP needs to be configured to use sockets API in this mode */
         /* LWIP_SOCKET 1 in lwip/opt.h or in build */
         #include "lwip/sockets.h"
-        #include <errno.h>
         #ifndef LWIP_PROVIDE_ERRNO
+            #include <errno.h>
             #define LWIP_PROVIDE_ERRNO 1
         #endif
@@ -63,13 +69,10 @@
     #elif defined(FREESCALE_KSDK_MQX)
         #include <rtcs.h>
-    #elif defined(WOLFSSL_MDK_ARM) || defined(WOLFSSL_KEIL_TCP_NET)
-        #if !defined(WOLFSSL_MDK_ARM)
+    #elif (defined(WOLFSSL_MDK_ARM) || defined(WOLFSSL_KEIL_TCP_NET))
             #include "cmsis_os.h"
             #include "rl_net.h"
-        #else
-            #include <rtl.h>
-        #endif
         #include "errno.h"
-        #define SOCKET_T int
+    #elif defined(WOLFSSL_CMSIS_RTOS)
+        #include "cmsis_os.h"
     #elif defined(WOLFSSL_TIRTOS)
         #include <sys/socket.h>
@@ -80,4 +83,7 @@
     #elif defined(WOLFSSL_VXWORKS)
         #include <sockLib.h>
+        #include <errno.h>
+    #elif defined(WOLFSSL_NUCLEUS_1_2)
+        #include <externs.h>
         #include <errno.h>
     #elif defined(WOLFSSL_ATMEL)
@@ -105,4 +111,6 @@
     #elif defined(WOLFSSL_SGX)
         #include <errno.h>
+    #elif defined(WOLFSSL_APACHE_MYNEWT) && !defined(WOLFSSL_LWIP)
+        #include <mn_socket/mn_socket.h>
     #elif !defined(WOLFSSL_NO_SOCK)
         #include <sys/types.h>
@@ -118,5 +126,5 @@
             #include "rtipapi.h"  /* errno */
             #include "socket.h"
-        #elif !defined(DEVKITPRO) && !defined(WOLFSSL_PICOTCP)
+        #elif !defined(DEVKITPRO) && !defined(WOLFSSL_PICOTCP) && !defined(WOLFSSL_CONTIKI)
             #include <sys/socket.h>
             #include <arpa/inet.h>
@@ -148,5 +156,4 @@
     #define SOCKET_ECONNREFUSED WSAENOTCONN
     #define SOCKET_ECONNABORTED WSAECONNABORTED
-    #define close(s) closesocket(s)
 #elif defined(__PPU)
     #define SOCKET_EWOULDBLOCK SYS_NET_EWOULDBLOCK
@@ -177,5 +184,4 @@
     #endif
 #elif defined(WOLFSSL_MDK_ARM)|| defined(WOLFSSL_KEIL_TCP_NET)
-    #if !defined(WOLFSSL_MDK_ARM)
         #define SOCKET_EWOULDBLOCK BSD_ERROR_WOULDBLOCK
         #define SOCKET_EAGAIN      BSD_ERROR_LOCKED
@@ -185,13 +191,4 @@
         #define SOCKET_ECONNREFUSED BSD_ERROR
         #define SOCKET_ECONNABORTED BSD_ERROR
-    #else
-        #define SOCKET_EWOULDBLOCK SCK_EWOULDBLOCK
-        #define SOCKET_EAGAIN      SCK_ELOCKED
-        #define SOCKET_ECONNRESET  SCK_ECLOSED
-        #define SOCKET_EINTR       SCK_ERROR
-        #define SOCKET_EPIPE       SCK_ERROR
-        #define SOCKET_ECONNREFUSED SCK_ERROR
-        #define SOCKET_ECONNABORTED SCK_ERROR
-    #endif
 #elif defined(WOLFSSL_PICOTCP)
     #define SOCKET_EWOULDBLOCK  PICO_ERR_EAGAIN
@@ -210,4 +207,12 @@
     #define SOCKET_ECONNREFUSED FREERTOS_SOCKET_ERROR
     #define SOCKET_ECONNABORTED FREERTOS_SOCKET_ERROR
+#elif defined(WOLFSSL_NUCLEUS_1_2)
+    #define SOCKET_EWOULDBLOCK  NU_WOULD_BLOCK
+    #define SOCKET_EAGAIN       NU_WOULD_BLOCK
+    #define SOCKET_ECONNRESET   NU_NOT_CONNECTED
+    #define SOCKET_EINTR        NU_NOT_CONNECTED
+    #define SOCKET_EPIPE        NU_NOT_CONNECTED
+    #define SOCKET_ECONNREFUSED NU_CONNECTION_REFUSED
+    #define SOCKET_ECONNABORTED NU_NOT_CONNECTED
 #else
     #define SOCKET_EWOULDBLOCK EWOULDBLOCK
@@ -221,4 +226,6 @@
 
 
+
+
 #ifdef DEVKITPRO
     /* from network.h */
@@ -227,5 +234,5 @@
     #define SEND_FUNCTION net_send
     #define RECV_FUNCTION net_recv
-#elif defined(WOLFSSL_LWIP)
+#elif defined(WOLFSSL_LWIP) && !defined(WOLFSSL_APACHE_MYNEWT)
     #define SEND_FUNCTION lwip_send
     #define RECV_FUNCTION lwip_recv
@@ -239,4 +246,7 @@
     #define SEND_FUNCTION send
     #define RECV_FUNCTION recv
+#elif defined(WOLFSSL_NUCLEUS_1_2)
+    #define SEND_FUNCTION NU_Send
+    #define RECV_FUNCTION NU_Recv
 #else
     #define SEND_FUNCTION send
@@ -273,4 +283,9 @@
     #endif /* HAVE_SOCKADDR */
 
+    /* use gethostbyname for c99 */
+    #ifdef WOLF_C99
+        #undef HAVE_GETADDRINFO
+    #endif
+
     #ifdef HAVE_GETADDRINFO
         typedef struct addrinfo         ADDRINFO;
@@ -282,5 +297,5 @@
 #ifdef HAVE_IO_TIMEOUT
     WOLFSSL_API  int wolfIO_SetBlockingMode(SOCKET_T sockfd, int non_blocking);
-    WOLFSSL_API void wolfIO_SetTimeout(int to_sec);;
+    WOLFSSL_API void wolfIO_SetTimeout(int to_sec);
     WOLFSSL_API  int wolfIO_Select(SOCKET_T sockfd, int to_sec);
 #endif
@@ -293,4 +308,28 @@
 
 
+#ifdef USE_WINDOWS_API
+    #ifndef CloseSocket
+        #define CloseSocket(s) closesocket(s)
+    #endif
+    #define StartTCP() { WSADATA wsd; WSAStartup(0x0002, &wsd); }
+#elif defined(WOLFSSL_MDK_ARM) || defined(WOLFSSL_KEIL_TCP_NET)
+    #ifndef CloseSocket
+        extern int closesocket(int);
+        #define CloseSocket(s) closesocket(s)
+    #endif
+    #define StartTCP()
+#else
+    #ifndef CloseSocket
+        #define CloseSocket(s) close(s)
+    #endif
+    #define StartTCP()
+    #ifdef FREERTOS_TCP_WINSIM
+        extern int close(int);
+    #endif
+#endif
+
+
+WOLFSSL_API int BioSend(WOLFSSL* ssl, char *buf, int sz, void *ctx);
+WOLFSSL_API int BioReceive(WOLFSSL* ssl, char* buf, int sz, void* ctx);
 #if defined(USE_WOLFSSL_IO)
     /* default IO callbacks */
@@ -346,5 +385,5 @@
         const char* domainName, const char* path, int pathLen, int reqSz,
         const char* contentType, unsigned char* buf, int bufSize);
-    WOLFSSL_API  int wolfIO_HttpProcessResponse(int sfd, const char* appStr,
+    WOLFSSL_API  int wolfIO_HttpProcessResponse(int sfd, const char** appStrList,
         unsigned char** respBuf, unsigned char* httpBuf, int httpBufSz,
         int dynType, void* heap);
@@ -355,6 +394,9 @@
 typedef int (*CallbackIORecv)(WOLFSSL *ssl, char *buf, int sz, void *ctx);
 typedef int (*CallbackIOSend)(WOLFSSL *ssl, char *buf, int sz, void *ctx);
-WOLFSSL_API void wolfSSL_SetIORecv(WOLFSSL_CTX*, CallbackIORecv);
-WOLFSSL_API void wolfSSL_SetIOSend(WOLFSSL_CTX*, CallbackIOSend);
+WOLFSSL_API void wolfSSL_CTX_SetIORecv(WOLFSSL_CTX*, CallbackIORecv);
+WOLFSSL_API void wolfSSL_CTX_SetIOSend(WOLFSSL_CTX*, CallbackIOSend);
+/* deprecated old name */
+#define wolfSSL_SetIORecv wolfSSL_CTX_SetIORecv
+#define wolfSSL_SetIOSend wolfSSL_CTX_SetIOSend
 
 WOLFSSL_API void wolfSSL_SetIOReadCtx( WOLFSSL* ssl, void *ctx);
@@ -385,4 +427,44 @@
 #endif /* MICRIUM */
 
+#if defined(WOLFSSL_APACHE_MYNEWT) && !defined(WOLFSSL_LWIP)
+    WOLFSSL_LOCAL int Mynewt_Receive(WOLFSSL *ssl, char *buf, int sz, void *ctx);
+    WOLFSSL_LOCAL int Mynewt_Send(WOLFSSL* ssl, char *buf, int sz, void *ctx);
+    WOLFSSL_API void wolfSSL_SetIO_Mynewt(WOLFSSL* ssl, struct mn_socket* mnSocket,
+                                          struct mn_sockaddr_in* mnSockAddrIn);
+#endif /* defined(WOLFSSL_APACHE_MYNEWT) && !defined(WOLFSSL_LWIP) */
+
+#ifdef WOLFSSL_UIP
+
+    struct uip_wolfssl_ctx {
+        union socket_connector {
+            struct tcp_socket tcp;
+            struct udp_socket udp;
+        } conn;
+        WOLFSSL_CTX *ctx;
+        WOLFSSL *ssl;
+        uint8_t *input_databuf;
+        uint8_t *output_databuf;
+        uint8_t *ssl_rx_databuf;
+        int ssl_rb_len;
+        int ssl_rb_off;
+        struct process *process;
+        tcp_socket_data_callback_t input_callback;
+        tcp_socket_event_callback_t event_callback;
+        int closing;
+        uip_ipaddr_t peer_addr;
+        uint16_t peer_port;
+    };
+
+    typedef struct uip_wolfssl_ctx uip_wolfssl_ctx;
+
+    WOLFSSL_LOCAL int uIPSend(WOLFSSL* ssl, char* buf, int sz, void* ctx);
+    WOLFSSL_LOCAL int uIPReceive(WOLFSSL* ssl, char* buf, int sz,
+                                     void* ctx);
+    WOLFSSL_LOCAL int uIPReceiveFrom(WOLFSSL* ssl, char* buf, int sz,
+                                         void* ctx);
+    WOLFSSL_LOCAL int uIPSendTo(WOLFSSL* ssl, char* buf, int sz, void* ctx);
+
+#endif
+
 #ifdef WOLFSSL_DTLS
     typedef int (*CallbackGenCookie)(WOLFSSL* ssl, unsigned char* buf, int sz,
@@ -407,7 +489,15 @@
 #ifndef XINET_NTOP
     #define XINET_NTOP(a,b,c,d) inet_ntop((a),(b),(c),(d))
+    #ifdef USE_WINDOWS_API /* Windows-friendly definition */
+        #undef  XINET_NTOP
+        #define XINET_NTOP(a,b,c,d) InetNtop((a),(b),(c),(d))
+    #endif
 #endif
 #ifndef XINET_PTON
     #define XINET_PTON(a,b,c)   inet_pton((a),(b),(c))
+    #ifdef USE_WINDOWS_API /* Windows-friendly definition */
+        #undef  XINET_PTON
+        #define XINET_PTON(a,b,c)   InetPton((a),(b),(c))
+    #endif
 #endif
 #ifndef XHTONS
